summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2016-01-31 15:25:07 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2016-01-31 15:25:07 +0100
commit12f9fcebaa41ebf5fdc0e95e1471b3113a61a022 (patch)
tree039c9af17a4a51b9e06c4c8a6d690aa43875d506 /3rdparty
parent68e9c4fea3081379bc1f5ade9c60e731960074e0 (diff)
added libuv library (nw)
Diffstat (limited to '3rdparty')
-rw-r--r--3rdparty/libuv/.gitignore75
-rw-r--r--3rdparty/libuv/.mailmap39
-rw-r--r--3rdparty/libuv/AUTHORS242
-rw-r--r--3rdparty/libuv/CONTRIBUTING.md166
-rw-r--r--3rdparty/libuv/ChangeLog2372
-rw-r--r--3rdparty/libuv/LICENSE46
-rw-r--r--3rdparty/libuv/MAINTAINERS.md36
-rw-r--r--3rdparty/libuv/Makefile.am344
-rw-r--r--3rdparty/libuv/Makefile.mingw84
-rw-r--r--3rdparty/libuv/README.md245
-rw-r--r--3rdparty/libuv/android-configure20
-rw-r--r--3rdparty/libuv/appveyor.yml36
-rw-r--r--3rdparty/libuv/autogen.sh46
-rw-r--r--3rdparty/libuv/checksparse.sh234
-rw-r--r--3rdparty/libuv/common.gypi210
-rw-r--r--3rdparty/libuv/configure.ac68
-rw-r--r--3rdparty/libuv/docs/Makefile178
-rw-r--r--3rdparty/libuv/docs/make.bat243
-rw-r--r--3rdparty/libuv/docs/src/async.rst57
-rw-r--r--3rdparty/libuv/docs/src/check.rst46
-rw-r--r--3rdparty/libuv/docs/src/conf.py348
-rw-r--r--3rdparty/libuv/docs/src/design.rst137
-rw-r--r--3rdparty/libuv/docs/src/dll.rst44
-rw-r--r--3rdparty/libuv/docs/src/dns.rst108
-rw-r--r--3rdparty/libuv/docs/src/errors.rst331
-rw-r--r--3rdparty/libuv/docs/src/fs.rst300
-rw-r--r--3rdparty/libuv/docs/src/fs_event.rst108
-rw-r--r--3rdparty/libuv/docs/src/fs_poll.rst72
-rw-r--r--3rdparty/libuv/docs/src/handle.rst181
-rw-r--r--3rdparty/libuv/docs/src/idle.rst54
-rw-r--r--3rdparty/libuv/docs/src/index.rst95
-rw-r--r--3rdparty/libuv/docs/src/loop.rst166
-rw-r--r--3rdparty/libuv/docs/src/migration_010_100.rst244
-rw-r--r--3rdparty/libuv/docs/src/misc.rst328
-rw-r--r--3rdparty/libuv/docs/src/pipe.rst104
-rw-r--r--3rdparty/libuv/docs/src/poll.rst103
-rw-r--r--3rdparty/libuv/docs/src/prepare.rst46
-rw-r--r--3rdparty/libuv/docs/src/process.rst225
-rw-r--r--3rdparty/libuv/docs/src/request.rst82
-rw-r--r--3rdparty/libuv/docs/src/signal.rst77
-rw-r--r--3rdparty/libuv/docs/src/sphinx-plugins/manpage.py46
-rw-r--r--3rdparty/libuv/docs/src/static/architecture.pngbin0 -> 206767 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpgbin0 -> 19328 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpgbin0 -> 12655 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Index.zipbin0 -> 71160 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist8
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier1
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plistbin0 -> 340 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpgbin0 -> 1425 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpgbin0 -> 8106 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview.jpgbin0 -> 107456 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/favicon.icobin0 -> 15086 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/logo.pngbin0 -> 33545 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/loop_iteration.pngbin0 -> 80528 bytes
-rw-r--r--3rdparty/libuv/docs/src/stream.rst219
-rw-r--r--3rdparty/libuv/docs/src/tcp.rst108
-rw-r--r--3rdparty/libuv/docs/src/threading.rst160
-rw-r--r--3rdparty/libuv/docs/src/threadpool.rst67
-rw-r--r--3rdparty/libuv/docs/src/timer.rst76
-rw-r--r--3rdparty/libuv/docs/src/tty.rst93
-rw-r--r--3rdparty/libuv/docs/src/udp.rst295
-rw-r--r--3rdparty/libuv/docs/src/version.rst60
-rw-r--r--3rdparty/libuv/gyp_uv.py93
-rw-r--r--3rdparty/libuv/img/banner.pngbin0 -> 44102 bytes
-rw-r--r--3rdparty/libuv/img/logos.svg152
-rw-r--r--3rdparty/libuv/include/android-ifaddrs.h54
-rw-r--r--3rdparty/libuv/include/pthread-fixes.h72
-rw-r--r--3rdparty/libuv/include/stdint-msvc2008.h247
-rw-r--r--3rdparty/libuv/include/tree.h768
-rw-r--r--3rdparty/libuv/include/uv-aix.h32
-rw-r--r--3rdparty/libuv/include/uv-bsd.h34
-rw-r--r--3rdparty/libuv/include/uv-darwin.h61
-rw-r--r--3rdparty/libuv/include/uv-errno.h418
-rw-r--r--3rdparty/libuv/include/uv-linux.h34
-rw-r--r--3rdparty/libuv/include/uv-sunos.h44
-rw-r--r--3rdparty/libuv/include/uv-threadpool.h37
-rw-r--r--3rdparty/libuv/include/uv-unix.h383
-rw-r--r--3rdparty/libuv/include/uv-version.h43
-rw-r--r--3rdparty/libuv/include/uv-win.h653
-rw-r--r--3rdparty/libuv/include/uv.h1482
-rw-r--r--3rdparty/libuv/libuv.nsi86
-rw-r--r--3rdparty/libuv/libuv.pc.in11
-rw-r--r--3rdparty/libuv/m4/.gitignore4
-rw-r--r--3rdparty/libuv/m4/as_case.m421
-rw-r--r--3rdparty/libuv/m4/libuv-check-flags.m4319
-rw-r--r--3rdparty/libuv/samples/.gitignore22
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/.gitignore21
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/LICENSE53
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/Makefile46
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/build.gyp46
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/client.c737
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/defs.h139
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/getopt.c131
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/main.c99
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/s5.c271
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/s5.h94
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/server.c241
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/util.c72
-rw-r--r--3rdparty/libuv/src/fs-poll.c255
-rw-r--r--3rdparty/libuv/src/heap-inl.h245
-rw-r--r--3rdparty/libuv/src/inet.c309
-rw-r--r--3rdparty/libuv/src/queue.h108
-rw-r--r--3rdparty/libuv/src/threadpool.c303
-rw-r--r--3rdparty/libuv/src/unix/aix.c1158
-rw-r--r--3rdparty/libuv/src/unix/android-ifaddrs.c703
-rw-r--r--3rdparty/libuv/src/unix/async.c290
-rw-r--r--3rdparty/libuv/src/unix/atomic-ops.h77
-rw-r--r--3rdparty/libuv/src/unix/core.c1104
-rw-r--r--3rdparty/libuv/src/unix/darwin-proctitle.c206
-rw-r--r--3rdparty/libuv/src/unix/darwin.c335
-rw-r--r--3rdparty/libuv/src/unix/dl.c80
-rw-r--r--3rdparty/libuv/src/unix/freebsd.c450
-rw-r--r--3rdparty/libuv/src/unix/fs.c1310
-rw-r--r--3rdparty/libuv/src/unix/fsevents.c904
-rw-r--r--3rdparty/libuv/src/unix/getaddrinfo.c202
-rw-r--r--3rdparty/libuv/src/unix/getnameinfo.c120
-rw-r--r--3rdparty/libuv/src/unix/internal.h316
-rw-r--r--3rdparty/libuv/src/unix/kqueue.c426
-rw-r--r--3rdparty/libuv/src/unix/linux-core.c899
-rw-r--r--3rdparty/libuv/src/unix/linux-inotify.c285
-rw-r--r--3rdparty/libuv/src/unix/linux-syscalls.c471
-rw-r--r--3rdparty/libuv/src/unix/linux-syscalls.h158
-rw-r--r--3rdparty/libuv/src/unix/loop-watcher.c68
-rw-r--r--3rdparty/libuv/src/unix/loop.c155
-rw-r--r--3rdparty/libuv/src/unix/netbsd.c370
-rw-r--r--3rdparty/libuv/src/unix/openbsd.c386
-rw-r--r--3rdparty/libuv/src/unix/pipe.c288
-rw-r--r--3rdparty/libuv/src/unix/poll.c113
-rw-r--r--3rdparty/libuv/src/unix/process.c563
-rw-r--r--3rdparty/libuv/src/unix/proctitle.c102
-rw-r--r--3rdparty/libuv/src/unix/pthread-fixes.c104
-rw-r--r--3rdparty/libuv/src/unix/signal.c467
-rw-r--r--3rdparty/libuv/src/unix/spinlock.h53
-rw-r--r--3rdparty/libuv/src/unix/stream.c1615
-rw-r--r--3rdparty/libuv/src/unix/sunos.c765
-rw-r--r--3rdparty/libuv/src/unix/tcp.c362
-rw-r--r--3rdparty/libuv/src/unix/thread.c525
-rw-r--r--3rdparty/libuv/src/unix/timer.c172
-rw-r--r--3rdparty/libuv/src/unix/tty.c279
-rw-r--r--3rdparty/libuv/src/unix/udp.c873
-rw-r--r--3rdparty/libuv/src/uv-common.c627
-rw-r--r--3rdparty/libuv/src/uv-common.h227
-rw-r--r--3rdparty/libuv/src/version.c45
-rw-r--r--3rdparty/libuv/src/win/async.c99
-rw-r--r--3rdparty/libuv/src/win/atomicops-inl.h56
-rw-r--r--3rdparty/libuv/src/win/core.c457
-rw-r--r--3rdparty/libuv/src/win/dl.c113
-rw-r--r--3rdparty/libuv/src/win/error.c170
-rw-r--r--3rdparty/libuv/src/win/fs-event.c552
-rw-r--r--3rdparty/libuv/src/win/fs.c2468
-rw-r--r--3rdparty/libuv/src/win/getaddrinfo.c358
-rw-r--r--3rdparty/libuv/src/win/getnameinfo.c150
-rw-r--r--3rdparty/libuv/src/win/handle-inl.h179
-rw-r--r--3rdparty/libuv/src/win/handle.c154
-rw-r--r--3rdparty/libuv/src/win/internal.h382
-rw-r--r--3rdparty/libuv/src/win/loop-watcher.c122
-rw-r--r--3rdparty/libuv/src/win/pipe.c2118
-rw-r--r--3rdparty/libuv/src/win/poll.c635
-rw-r--r--3rdparty/libuv/src/win/process-stdio.c510
-rw-r--r--3rdparty/libuv/src/win/process.c1247
-rw-r--r--3rdparty/libuv/src/win/req-inl.h224
-rw-r--r--3rdparty/libuv/src/win/req.c25
-rw-r--r--3rdparty/libuv/src/win/signal.c356
-rw-r--r--3rdparty/libuv/src/win/snprintf.c42
-rw-r--r--3rdparty/libuv/src/win/stream-inl.h56
-rw-r--r--3rdparty/libuv/src/win/stream.c249
-rw-r--r--3rdparty/libuv/src/win/tcp.c1507
-rw-r--r--3rdparty/libuv/src/win/thread.c697
-rw-r--r--3rdparty/libuv/src/win/timer.c200
-rw-r--r--3rdparty/libuv/src/win/tty.c2084
-rw-r--r--3rdparty/libuv/src/win/udp.c926
-rw-r--r--3rdparty/libuv/src/win/util.c1232
-rw-r--r--3rdparty/libuv/src/win/winapi.c146
-rw-r--r--3rdparty/libuv/src/win/winapi.h4710
-rw-r--r--3rdparty/libuv/src/win/winsock.c561
-rw-r--r--3rdparty/libuv/src/win/winsock.h190
-rw-r--r--3rdparty/libuv/test/benchmark-async-pummel.c119
-rw-r--r--3rdparty/libuv/test/benchmark-async.c141
-rw-r--r--3rdparty/libuv/test/benchmark-fs-stat.c136
-rw-r--r--3rdparty/libuv/test/benchmark-getaddrinfo.c92
-rw-r--r--3rdparty/libuv/test/benchmark-list.h163
-rw-r--r--3rdparty/libuv/test/benchmark-loop-count.c92
-rw-r--r--3rdparty/libuv/test/benchmark-million-async.c112
-rw-r--r--3rdparty/libuv/test/benchmark-million-timers.c86
-rw-r--r--3rdparty/libuv/test/benchmark-multi-accept.c447
-rw-r--r--3rdparty/libuv/test/benchmark-ping-pongs.c221
-rw-r--r--3rdparty/libuv/test/benchmark-pound.c351
-rw-r--r--3rdparty/libuv/test/benchmark-pump.c476
-rw-r--r--3rdparty/libuv/test/benchmark-sizes.c46
-rw-r--r--3rdparty/libuv/test/benchmark-spawn.c164
-rw-r--r--3rdparty/libuv/test/benchmark-tcp-write-batch.c144
-rw-r--r--3rdparty/libuv/test/benchmark-thread.c64
-rw-r--r--3rdparty/libuv/test/benchmark-udp-pummel.c243
-rw-r--r--3rdparty/libuv/test/blackhole-server.c121
-rw-r--r--3rdparty/libuv/test/dns-server.c340
-rw-r--r--3rdparty/libuv/test/echo-server.c378
-rw-r--r--3rdparty/libuv/test/fixtures/empty_file0
-rw-r--r--3rdparty/libuv/test/fixtures/load_error.node1
-rw-r--r--3rdparty/libuv/test/run-benchmarks.c65
-rw-r--r--3rdparty/libuv/test/run-tests.c181
-rw-r--r--3rdparty/libuv/test/runner-unix.c400
-rw-r--r--3rdparty/libuv/test/runner-unix.h36
-rw-r--r--3rdparty/libuv/test/runner-win.c371
-rw-r--r--3rdparty/libuv/test/runner-win.h39
-rw-r--r--3rdparty/libuv/test/runner.c466
-rw-r--r--3rdparty/libuv/test/runner.h178
-rw-r--r--3rdparty/libuv/test/task.h220
-rw-r--r--3rdparty/libuv/test/test-active.c84
-rw-r--r--3rdparty/libuv/test/test-async-null-cb.c55
-rw-r--r--3rdparty/libuv/test/test-async.c134
-rw-r--r--3rdparty/libuv/test/test-barrier.c106
-rw-r--r--3rdparty/libuv/test/test-callback-order.c77
-rw-r--r--3rdparty/libuv/test/test-callback-stack.c205
-rw-r--r--3rdparty/libuv/test/test-close-fd.c76
-rw-r--r--3rdparty/libuv/test/test-close-order.c80
-rw-r--r--3rdparty/libuv/test/test-condvar.c173
-rw-r--r--3rdparty/libuv/test/test-connection-fail.c151
-rw-r--r--3rdparty/libuv/test/test-cwd-and-chdir.c51
-rw-r--r--3rdparty/libuv/test/test-default-loop-close.c59
-rw-r--r--3rdparty/libuv/test/test-delayed-accept.c189
-rw-r--r--3rdparty/libuv/test/test-dlerror.c55
-rw-r--r--3rdparty/libuv/test/test-embed.c138
-rw-r--r--3rdparty/libuv/test/test-emfile.c110
-rw-r--r--3rdparty/libuv/test/test-error.c50
-rw-r--r--3rdparty/libuv/test/test-fail-always.c29
-rw-r--r--3rdparty/libuv/test/test-fs-event.c907
-rw-r--r--3rdparty/libuv/test/test-fs-poll.c186
-rw-r--r--3rdparty/libuv/test/test-fs.c2664
-rw-r--r--3rdparty/libuv/test/test-get-currentexe.c86
-rw-r--r--3rdparty/libuv/test/test-get-loadavg.c35
-rw-r--r--3rdparty/libuv/test/test-get-memory.c38
-rw-r--r--3rdparty/libuv/test/test-getaddrinfo.c184
-rw-r--r--3rdparty/libuv/test/test-getnameinfo.c101
-rw-r--r--3rdparty/libuv/test/test-getsockname.c361
-rw-r--r--3rdparty/libuv/test/test-handle-fileno.c121
-rw-r--r--3rdparty/libuv/test/test-homedir.c49
-rw-r--r--3rdparty/libuv/test/test-hrtime.c54
-rw-r--r--3rdparty/libuv/test/test-idle.c99
-rw-r--r--3rdparty/libuv/test/test-ip4-addr.c46
-rw-r--r--3rdparty/libuv/test/test-ip6-addr.c141
-rw-r--r--3rdparty/libuv/test/test-ipc-send-recv.c411
-rw-r--r--3rdparty/libuv/test/test-ipc.c779
-rw-r--r--3rdparty/libuv/test/test-list.h732
-rw-r--r--3rdparty/libuv/test/test-loop-alive.c67
-rw-r--r--3rdparty/libuv/test/test-loop-close.c53
-rw-r--r--3rdparty/libuv/test/test-loop-configure.c38
-rw-r--r--3rdparty/libuv/test/test-loop-handles.c337
-rw-r--r--3rdparty/libuv/test/test-loop-stop.c71
-rw-r--r--3rdparty/libuv/test/test-loop-time.c63
-rw-r--r--3rdparty/libuv/test/test-multiple-listen.c109
-rw-r--r--3rdparty/libuv/test/test-mutexes.c162
-rw-r--r--3rdparty/libuv/test/test-osx-select.c140
-rw-r--r--3rdparty/libuv/test/test-pass-always.c28
-rw-r--r--3rdparty/libuv/test/test-ping-pong.c270
-rw-r--r--3rdparty/libuv/test/test-pipe-bind-error.c136
-rw-r--r--3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c104
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-error.c95
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-multiple.c104
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-prepare.c83
-rw-r--r--3rdparty/libuv/test/test-pipe-getsockname.c263
-rw-r--r--3rdparty/libuv/test/test-pipe-pending-instances.c59
-rw-r--r--3rdparty/libuv/test/test-pipe-sendmsg.c169
-rw-r--r--3rdparty/libuv/test/test-pipe-server-close.c91
-rw-r--r--3rdparty/libuv/test/test-pipe-set-non-blocking.c99
-rw-r--r--3rdparty/libuv/test/test-platform-output.c126
-rw-r--r--3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c114
-rw-r--r--3rdparty/libuv/test/test-poll-close.c73
-rw-r--r--3rdparty/libuv/test/test-poll-closesocket.c89
-rw-r--r--3rdparty/libuv/test/test-poll.c560
-rw-r--r--3rdparty/libuv/test/test-process-title.c53
-rw-r--r--3rdparty/libuv/test/test-queue-foreach-delete.c200
-rw-r--r--3rdparty/libuv/test/test-ref.c442
-rw-r--r--3rdparty/libuv/test/test-run-nowait.c45
-rw-r--r--3rdparty/libuv/test/test-run-once.c48
-rw-r--r--3rdparty/libuv/test/test-semaphore.c111
-rw-r--r--3rdparty/libuv/test/test-shutdown-close.c108
-rw-r--r--3rdparty/libuv/test/test-shutdown-eof.c182
-rw-r--r--3rdparty/libuv/test/test-shutdown-twice.c84
-rw-r--r--3rdparty/libuv/test/test-signal-multiple-loops.c290
-rw-r--r--3rdparty/libuv/test/test-signal.c152
-rw-r--r--3rdparty/libuv/test/test-socket-buffer-size.c77
-rw-r--r--3rdparty/libuv/test/test-spawn.c1706
-rw-r--r--3rdparty/libuv/test/test-stdio-over-pipes.c255
-rw-r--r--3rdparty/libuv/test/test-tcp-bind-error.c216
-rw-r--r--3rdparty/libuv/test/test-tcp-bind6-error.c176
-rw-r--r--3rdparty/libuv/test/test-tcp-close-accept.c188
-rw-r--r--3rdparty/libuv/test/test-tcp-close-while-connecting.c86
-rw-r--r--3rdparty/libuv/test/test-tcp-close.c136
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-error-after-write.c98
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-error.c73
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-timeout.c91
-rw-r--r--3rdparty/libuv/test/test-tcp-connect6-error.c71
-rw-r--r--3rdparty/libuv/test/test-tcp-create-socket-early.c206
-rw-r--r--3rdparty/libuv/test/test-tcp-flags.c52
-rw-r--r--3rdparty/libuv/test/test-tcp-oob.c128
-rw-r--r--3rdparty/libuv/test/test-tcp-open.c220
-rw-r--r--3rdparty/libuv/test/test-tcp-read-stop.c76
-rw-r--r--3rdparty/libuv/test/test-tcp-shutdown-after-write.c138
-rw-r--r--3rdparty/libuv/test/test-tcp-try-write.c135
-rw-r--r--3rdparty/libuv/test/test-tcp-unexpected-read.c117
-rw-r--r--3rdparty/libuv/test/test-tcp-write-after-connect.c68
-rw-r--r--3rdparty/libuv/test/test-tcp-write-fail.c115
-rw-r--r--3rdparty/libuv/test/test-tcp-write-queue-order.c137
-rw-r--r--3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c141
-rw-r--r--3rdparty/libuv/test/test-tcp-writealot.c176
-rw-r--r--3rdparty/libuv/test/test-thread-equal.c45
-rw-r--r--3rdparty/libuv/test/test-thread.c211
-rw-r--r--3rdparty/libuv/test/test-threadpool-cancel.c362
-rw-r--r--3rdparty/libuv/test/test-threadpool.c76
-rw-r--r--3rdparty/libuv/test/test-timer-again.c141
-rw-r--r--3rdparty/libuv/test/test-timer-from-check.c80
-rw-r--r--3rdparty/libuv/test/test-timer.c303
-rw-r--r--3rdparty/libuv/test/test-tty.c184
-rw-r--r--3rdparty/libuv/test/test-udp-bind.c93
-rw-r--r--3rdparty/libuv/test/test-udp-create-socket-early.c132
-rw-r--r--3rdparty/libuv/test/test-udp-dgram-too-big.c91
-rw-r--r--3rdparty/libuv/test/test-udp-ipv6.c193
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-interface.c99
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-interface6.c103
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-join.c150
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-join6.c161
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-ttl.c94
-rw-r--r--3rdparty/libuv/test/test-udp-open.c204
-rw-r--r--3rdparty/libuv/test/test-udp-options.c126
-rw-r--r--3rdparty/libuv/test/test-udp-send-and-recv.c214
-rw-r--r--3rdparty/libuv/test/test-udp-send-immediate.c148
-rw-r--r--3rdparty/libuv/test/test-udp-send-unreachable.c150
-rw-r--r--3rdparty/libuv/test/test-udp-try-send.c133
-rw-r--r--3rdparty/libuv/test/test-walk-handles.c77
-rw-r--r--3rdparty/libuv/test/test-watcher-cross-stop.c103
-rw-r--r--3rdparty/libuv/uv.gyp508
-rw-r--r--3rdparty/libuv/vcbuild.bat153
332 files changed, 87084 insertions, 0 deletions
diff --git a/3rdparty/libuv/.gitignore b/3rdparty/libuv/.gitignore
new file mode 100644
index 00000000000..86a8a5b7b85
--- /dev/null
+++ b/3rdparty/libuv/.gitignore
@@ -0,0 +1,75 @@
+*.swp
+*.[oa]
+*.l[oa]
+*.opensdf
+*.orig
+*.pyc
+*.sdf
+*.suo
+core
+vgcore.*
+.buildstamp
+.dirstamp
+.deps/
+/.libs/
+/aclocal.m4
+/ar-lib
+/autom4te.cache/
+/compile
+/config.guess
+/config.log
+/config.status
+/config.sub
+/configure
+/depcomp
+/install-sh
+/libtool
+/libuv.a
+/libuv.dylib
+/libuv.pc
+/libuv.so
+/ltmain.sh
+/missing
+/test-driver
+Makefile
+Makefile.in
+
+# Generated by gyp for android
+*.target.mk
+
+/out/
+/build/gyp
+
+/test/.libs/
+/test/run-tests
+/test/run-tests.exe
+/test/run-tests.dSYM
+/test/run-benchmarks
+/test/run-benchmarks.exe
+/test/run-benchmarks.dSYM
+
+*.sln
+*.sln.cache
+*.ncb
+*.vcproj
+*.vcproj*.user
+*.vcxproj
+*.vcxproj.filters
+*.vcxproj.user
+_UpgradeReport_Files/
+UpgradeLog*.XML
+Debug
+Release
+ipch
+
+# sphinx generated files
+/docs/build/
+
+# Clion / IntelliJ project files
+/.idea/
+
+*.xcodeproj
+*.xcworkspace
+
+# make dist output
+libuv-*.tar.*
diff --git a/3rdparty/libuv/.mailmap b/3rdparty/libuv/.mailmap
new file mode 100644
index 00000000000..7a51588c0b7
--- /dev/null
+++ b/3rdparty/libuv/.mailmap
@@ -0,0 +1,39 @@
+Aaron Bieber <qbit@deftly.net> <deftly@gmail.com>
+Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com>
+Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com>
+Bert Belder <bertbelder@gmail.com> <info@2bs.nl>
+Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)>
+Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org>
+Brian White <mscdex@mscdex.net>
+Brian White <mscdex@mscdex.net> <mscdex@gmail.com>
+Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr>
+Christoph Iserlohn <christoph.iserlohn@innoq.com>
+Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
+Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com>
+Frank Denis <github@pureftpd.org>
+Isaac Z. Schlueter <i@izs.me>
+Jason Williams <necmon@yahoo.com>
+Justin Venus <justin.venus@gmail.com> <justin.venus@orbitz.com>
+Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu>
+Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu>
+Leith Bade <leith@leithalweapon.geek.nz> <leith@mapbox.com>
+Leonard Hecker <leonard.hecker91@gmail.com> <leonard@hecker.io>
+Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
+Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
+Michael <michael_dawson@ca.ibm.com>
+Michael Neumann <mneumann@think.localnet> <mneumann@ntecs.de>
+Nicholas Vavilov <vvnicholas@gmail.com>
+Rasmus Christian Pedersen <zerhacken@yahoo.com>
+Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
+Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
+Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
+Ryan Emery <seebees@gmail.com>
+Sam Roberts <vieuxtech@gmail.com> <sam@strongloop.com>
+San-Tai Hsu <vanilla@fatpipi.com>
+Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
+Saúl Ibarra Corretgé <saghul@gmail.com>
+Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
+Timothy J. Fontaine <tjfontaine@gmail.com>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Yazhong Liu <yorkiefixer@gmail.com>
+Yuki Okumura <mjt@cltn.org>
diff --git a/3rdparty/libuv/AUTHORS b/3rdparty/libuv/AUTHORS
new file mode 100644
index 00000000000..8dc3955cad5
--- /dev/null
+++ b/3rdparty/libuv/AUTHORS
@@ -0,0 +1,242 @@
+# Authors ordered by first contribution.
+Ryan Dahl <ryan@joyent.com>
+Bert Belder <bertbelder@gmail.com>
+Josh Roesslein <jroesslein@gmail.com>
+Alan Gutierrez <alan@prettyrobots.com>
+Joshua Peek <josh@joshpeek.com>
+Igor Zinkovsky <igorzi@microsoft.com>
+San-Tai Hsu <vanilla@fatpipi.com>
+Ben Noordhuis <info@bnoordhuis.nl>
+Henry Rawas <henryr@schakra.com>
+Robert Mustacchi <rm@joyent.com>
+Matt Stevens <matt@alloysoft.com>
+Paul Querna <pquerna@apache.org>
+Shigeki Ohtsu <ohtsu@iij.ad.jp>
+Tom Hughes <tom.hughes@palm.com>
+Peter Bright <drpizza@quiscalusmexicanus.org>
+Jeroen Janssen <jeroen.janssen@gmail.com>
+Andrea Lattuada <ndr.lattuada@gmail.com>
+Augusto Henrique Hentz <ahhentz@gmail.com>
+Clifford Heath <clifford.heath@gmail.com>
+Jorge Chamorro Bieling <jorge@jorgechamorro.com>
+Luis Lavena <luislavena@gmail.com>
+Matthew Sporleder <msporleder@gmail.com>
+Erick Tryzelaar <erick.tryzelaar@gmail.com>
+Isaac Z. Schlueter <i@izs.me>
+Pieter Noordhuis <pcnoordhuis@gmail.com>
+Marek Jelen <marek@jelen.biz>
+Fedor Indutny <fedor.indutny@gmail.com>
+Saúl Ibarra Corretgé <saghul@gmail.com>
+Felix Geisendörfer <felix@debuggable.com>
+Yuki Okumura <mjt@cltn.org>
+Roman Shtylman <shtylman@gmail.com>
+Frank Denis <github@pureftpd.org>
+Carter Allen <CarterA@opt-6.com>
+Tj Holowaychuk <tj@vision-media.ca>
+Shimon Doodkin <helpmepro1@gmail.com>
+Ryan Emery <seebees@gmail.com>
+Bruce Mitchener <bruce.mitchener@gmail.com>
+Maciej Małecki <maciej.malecki@notimplemented.org>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Daisuke Murase <typester@cpan.org>
+Paddy Byers <paddy.byers@gmail.com>
+Dan VerWeire <dverweire@gmail.com>
+Brandon Benvie <brandon@bbenvie.com>
+Brandon Philips <brandon.philips@rackspace.com>
+Nathan Rajlich <nathan@tootallnate.net>
+Charlie McConnell <charlie@charlieistheman.com>
+Vladimir Dronnikov <dronnikov@gmail.com>
+Aaron Bieber <qbit@deftly.net>
+Bulat Shakirzyanov <mallluhuct@gmail.com>
+Brian White <mscdex@mscdex.net>
+Erik Dubbelboer <erik@dubbelboer.com>
+Keno Fischer <kenof@stanford.edu>
+Ira Cooper <Ira.Cooper@mathworks.com>
+Andrius Bentkus <andrius.bentkus@gmail.com>
+Iñaki Baz Castillo <ibc@aliax.net>
+Mark Cavage <mark.cavage@joyent.com>
+George Yohng <georgegh@oss3d.com>
+Xidorn Quan <quanxunzhen@gmail.com>
+Roman Neuhauser <rneuhauser@suse.cz>
+Shuhei Tanuma <shuhei.tanuma@gmail.com>
+Bryan Cantrill <bcantrill@acm.org>
+Trond Norbye <trond.norbye@gmail.com>
+Tim Holy <holy@wustl.edu>
+Prancesco Pertugio <meh@schizofreni.co>
+Leonard Hecker <leonard.hecker91@gmail.com>
+Andrew Paprocki <andrew@ishiboo.com>
+Luigi Grilli <luigi.grilli@gmail.com>
+Shannen Saez <shannenlaptop@gmail.com>
+Artur Adib <arturadib@gmail.com>
+Hiroaki Nakamura <hnakamur@gmail.com>
+Ting-Yu Lin <ph.minamo@cytisan.com>
+Stephen Gallagher <sgallagh@redhat.com>
+Shane Holloway <shane.holloway@ieee.org>
+Andrew Shaffer <darawk@gmail.com>
+Vlad Tudose <vlad.tudose@intel.com>
+Ben Leslie <benno@benno.id.au>
+Tim Bradshaw <tfb@cley.com>
+Timothy J. Fontaine <tjfontaine@gmail.com>
+Marc Schlaich <marc.schlaich@googlemail.com>
+Brian Mazza <louseman@gmail.com>
+Elliot Saba <staticfloat@gmail.com>
+Ben Kelly <ben@wanderview.com>
+Nils Maier <maierman@web.de>
+Nicholas Vavilov <vvnicholas@gmail.com>
+Miroslav Bajtoš <miro.bajtos@gmail.com>
+Sean Silva <chisophugis@gmail.com>
+Wynn Wilkes <wynnw@movenetworks.com>
+Andrei Sedoi <bsnote@gmail.com>
+Alex Crichton <alex@alexcrichton.com>
+Brent Cook <brent@boundary.com>
+Brian Kaisner <bkize1@gmail.com>
+Luca Bruno <lucab@debian.org>
+Reini Urban <rurban@cpanel.net>
+Maks Naumov <maksqwe1@ukr.net>
+Sean Farrell <sean.farrell@rioki.org>
+Chris Bank <cbank@adobe.com>
+Geert Jansen <geertj@gmail.com>
+Christoph Iserlohn <christoph.iserlohn@innoq.com>
+Steven Kabbes <stevenkabbes@gmail.com>
+Alex Gaynor <alex.gaynor@gmail.com>
+huxingyi <huxingyi@msn.com>
+Tenor Biel <tenorbiel@gmail.com>
+Andrej Manduch <AManduch@gmail.com>
+Joshua Neuheisel <joshua@neuheisel.us>
+Alexis Campailla <alexis@janeasystems.com>
+Yazhong Liu <yorkiefixer@gmail.com>
+Sam Roberts <vieuxtech@gmail.com>
+River Tarnell <river@loreley.flyingparchment.org.uk>
+Nathan Sweet <nathanjsweet@gmail.com>
+Trevor Norris <trev.norris@gmail.com>
+Oguz Bastemur <obastemur@gmail.com>
+Dylan Cali <calid1984@gmail.com>
+Austin Foxley <austinf@cetoncorp.com>
+Benjamin Saunders <ben.e.saunders@gmail.com>
+Geoffry Song <goffrie@gmail.com>
+Rasmus Christian Pedersen <ruysch@outlook.com>
+William Light <wrl@illest.net>
+Oleg Efimov <o.efimov@corp.badoo.com>
+Lars Gierth <larsg@systemli.org>
+Rasmus Christian Pedersen <zerhacken@yahoo.com>
+Justin Venus <justin.venus@gmail.com>
+Kristian Evensen <kristian.evensen@gmail.com>
+Linus Mårtensson <linus.martensson@sonymobile.com>
+Navaneeth Kedaram Nambiathan <navaneethkn@gmail.com>
+Yorkie <yorkiefixer@gmail.com>
+StarWing <weasley.wx@gmail.com>
+thierry-FreeBSD <thierry@FreeBSD.org>
+Isaiah Norton <isaiah.norton@gmail.com>
+Raul Martins <raulms.martins@gmail.com>
+David Capello <davidcapello@gmail.com>
+Paul Tan <pyokagan@gmail.com>
+Javier Hernández <jhernandez@emergya.com>
+Tonis Tiigi <tonistiigi@gmail.com>
+Norio Kobota <nori.0428@gmail.com>
+李港平 <chopdown@gmail.com>
+Chernyshev Viacheslav <astellar@ro.ru>
+Stephen von Takach <steve@advancedcontrol.com.au>
+JD Ballard <jd@pixelandline.com>
+Luka Perkov <luka.perkov@sartura.hr>
+Ryan Cole <ryan@rycole.com>
+HungMingWu <u9089000@gmail.com>
+Jay Satiro <raysatiro@yahoo.com>
+Leith Bade <leith@leithalweapon.geek.nz>
+Peter Atashian <retep998@gmail.com>
+Tim Cooper <tim.cooper@layeh.com>
+Caleb James DeLisle <cjd@hyperboria.ca>
+Jameson Nash <vtjnash@gmail.com>
+Graham Lee <ghmlee@ghmlee.com>
+Andrew Low <Andrew_Low@ca.ibm.com>
+Pavel Platto <hinidu@gmail.com>
+Tony Kelman <tony@kelman.net>
+John Firebaugh <john.firebaugh@gmail.com>
+lilohuang <lilohuang@hotmail.com>
+Paul Goldsmith <paul.goldsmith@aplink.net>
+Julien Gilli <julien.gilli@joyent.com>
+Michael Hudson-Doyle <michael.hudson@linaro.org>
+Recep ASLANTAS <m@recp.me>
+Rob Adams <readams@readams.net>
+Zachary Newman <znewman01@gmail.com>
+Robin Hahling <robin.hahling@gw-computing.net>
+Jeff Widman <jeff@jeffwidman.com>
+cjihrig <cjihrig@gmail.com>
+Tomasz Kołodziejski <tkolodziejski@mozilla.com>
+Unknown W. Brackets <checkins@unknownbrackets.org>
+Emmanuel Odeke <odeke@ualberta.ca>
+Mikhail Mukovnikov <yndi@me.com>
+Thorsten Lorenz <thlorenz@gmx.de>
+Yuri D'Elia <yuri.delia@eurac.edu>
+Manos Nikolaidis <manos@shadowrobot.com>
+Elijah Andrews <elijah@busbud.com>
+Michael Ira Krufky <m.krufky@samsung.com>
+Helge Deller <deller@gmx.de>
+Joey Geralnik <jgeralnik@gmail.com>
+Tim Caswell <tim@creationix.com>
+Logan Rosen <loganrosen@gmail.com>
+Kenneth Perry <thothonegan@gmail.com>
+John Marino <marino@FreeBSD.org>
+Alexey Melnichuk <mimir@newmail.ru>
+Johan Bergström <bugs@bergstroem.nu>
+Alex Mo <almosnow@gmail.com>
+Luis Martinez de Bartolome <lasote@gmail.com>
+Michael Penick <michael.penick@datastax.com>
+Michael <michael_dawson@ca.ibm.com>
+Massimiliano Torromeo <massimiliano.torromeo@gmail.com>
+TomCrypto <thomas.beneteau@yahoo.fr>
+Brett Vickers <brett@beevik.com>
+Ole André Vadla Ravnås <oleavr@gmail.com>
+Kazuho Oku <kazuhooku@gmail.com>
+Ryan Phillips <ryan.phillips@rackspace.com>
+Brian Green <briangreenery@gmail.com>
+Devchandra Meetei Leishangthem <dlmeetei@gmail.com>
+Corey Farrell <git@cfware.com>
+Per Nilsson <pni@qlik.com>
+Alan Rogers <alanjrogers@me.com>
+Daryl Haresign <github@daryl.haresign.com>
+Rui Abreu Ferreira <raf-ep@gmx.com>
+João Reis <reis@janeasystems.com>
+farblue68 <farblue68@gmail.com>
+Jason Williams <necmon@yahoo.com>
+Igor Soarez <igorsoarez@gmail.com>
+Miodrag Milanovic <mmicko@gmail.com>
+Cheng Zhao <zcbenz@gmail.com>
+Michael Neumann <mneumann@think.localnet>
+Stefano Cristiano <stefanocristiano82@gmail.com>
+heshamsafi <hesham.safi.eldeen@gmail.com>
+A. Hauptmann <andreashauptmann@t-online.de>
+John McNamee <jpm@microwiz.com>
+Yosuke Furukawa <yosuke.furukawa@gmail.com>
+Santiago Gimeno <santiago.gimeno@quantion.es>
+guworks <ground.up.works@gmail.com>
+RossBencina <rossb@audiomulch.com>
+Roger A. Light <roger@atchoo.org>
+chenttuuvv <chenttuuvv@yahoo.com>
+Richard Lau <riclau@uk.ibm.com>
+ronkorving <rkorving@wizcorp.jp>
+Corbin Simpson <MostAwesomeDude@gmail.com>
+Zachary Hamm <zsh@imipolexg.org>
+Karl Skomski <karl@skomski.com>
+Jeremy Whitlock <jwhitlock@apache.org>
+Willem Thiart <himself@willemthiart.com>
+Ben Trask <bentrask@comcast.net>
+Jianghua Yang <jianghua.yjh@alibaba-inc.com>
+Colin Snover <github.com@zetafleet.com>
+Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
+Eli Skeggs <skeggse@gmail.com>
+nmushell <nmushell@bloomberg.net>
+Gireesh Punathil <gpunathi@in.ibm.com>
+Ryan Johnston <ryan@mediapixel.co.nz>
+Adam Stylinski <stylinae@mail.uc.edu>
+Nathan Corvino <nathan@corvino.com>
+Wink Saville <wink@saville.com>
+Angel Leon <gubatron@gmail.com>
+Louis DeJardin <lodejard@microsoft.com>
+Imran Iqbal <imrani@ca.ibm.com>
+Petka Antonov <petka_antonov@hotmail.com>
+Ian Kronquist <iankronquist@teleport.com>
+kkdaemon <kkdaemon@gmail.com>
+Yuval Brik <yuval@brik.org.il>
+Joran Dirk Greef <joran@ronomon.com>
+Andrey Mazo <andrey.mazo@fidelissecurity.com>
+sztomi <hello.sztomi@gmail.com>
diff --git a/3rdparty/libuv/CONTRIBUTING.md b/3rdparty/libuv/CONTRIBUTING.md
new file mode 100644
index 00000000000..b46edd492aa
--- /dev/null
+++ b/3rdparty/libuv/CONTRIBUTING.md
@@ -0,0 +1,166 @@
+# CONTRIBUTING
+
+The libuv project welcomes new contributors. This document will guide you
+through the process.
+
+
+### FORK
+
+Fork the project [on GitHub](https://github.com/libuv/libuv) and check out
+your copy.
+
+```
+$ git clone https://github.com/username/libuv.git
+$ cd libuv
+$ git remote add upstream https://github.com/libuv/libuv.git
+```
+
+Now decide if you want your feature or bug fix to go into the master branch
+or the stable branch. As a rule of thumb, bug fixes go into the stable branch
+while new features go into the master branch.
+
+The stable branch is effectively frozen; patches that change the libuv
+API/ABI or affect the run-time behavior of applications get rejected.
+
+In case of doubt, open an issue in the [issue tracker][], post your question
+to the [libuv mailing list], or contact one of project maintainers
+(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][].
+
+Especially do so if you plan to work on something big. Nothing is more
+frustrating than seeing your hard work go to waste because your vision
+does not align with that of a project maintainers.
+
+
+### BRANCH
+
+Okay, so you have decided on the proper branch. Create a feature branch
+and start hacking:
+
+```
+$ git checkout -b my-feature-branch -t origin/v1.x
+```
+
+(Where v1.x is the latest stable branch as of this writing.)
+
+### CODE
+
+Please adhere to libuv's code style. In general it follows the conventions from
+the [Google C/C++ style guide]. Some of the key points, as well as some
+additional guidelines, are enumerated below.
+
+* Code that is specific to unix-y platforms should be placed in `src/unix`, and
+ declarations go into `include/uv-unix.h`.
+
+* Source code that is Windows-specific goes into `src/win`, and related
+ publicly exported types, functions and macro declarations should generally
+ be declared in `include/uv-win.h`.
+
+* Names should be descriptive and concise.
+
+* All the symbols and types that libuv makes available publicly should be
+ prefixed with `uv_` (or `UV_` in case of macros).
+
+* Internal, non-static functions should be prefixed with `uv__`.
+
+* Use two spaces and no tabs.
+
+* Lines should be wrapped at 80 characters.
+
+* Ensure that lines have no trailing whitespace, and use unix-style (LF) line
+ endings.
+
+* Use C89-compliant syntax. In other words, variables can only be declared at
+ the top of a scope (function, if/for/while-block).
+
+* When writing comments, use properly constructed sentences, including
+ punctuation.
+
+* When documenting APIs and/or source code, don't make assumptions or make
+ implications about race, gender, religion, political orientation or anything
+ else that isn't relevant to the project.
+
+* Remember that source code usually gets written once and read often: ensure
+ the reader doesn't have to make guesses. Make sure that the purpose and inner
+ logic are either obvious to a reasonably skilled professional, or add a
+ comment that explains it.
+
+
+### COMMIT
+
+Make sure git knows your name and email address:
+
+```
+$ git config --global user.name "J. Random User"
+$ git config --global user.email "j.random.user@example.com"
+```
+
+Writing good commit logs is important. A commit log should describe what
+changed and why. Follow these guidelines when writing one:
+
+1. The first line should be 50 characters or less and contain a short
+ description of the change prefixed with the name of the changed
+ subsystem (e.g. "net: add localAddress and localPort to Socket").
+2. Keep the second line blank.
+3. Wrap all other lines at 72 columns.
+
+A good commit log looks like this:
+
+```
+subsystem: explaining the commit in one line
+
+Body of commit message is a few lines of text, explaining things
+in more detail, possibly giving some background about the issue
+being fixed, etc etc.
+
+The body of the commit message can be several paragraphs, and
+please do proper word-wrap and keep columns shorter than about
+72 characters or so. That way `git log` will show things
+nicely even when it is indented.
+```
+
+The header line should be meaningful; it is what other people see when they
+run `git shortlog` or `git log --oneline`.
+
+Check the output of `git log --oneline files_that_you_changed` to find out
+what subsystem (or subsystems) your changes touch.
+
+
+### REBASE
+
+Use `git rebase` (not `git merge`) to sync your work from time to time.
+
+```
+$ git fetch upstream
+$ git rebase upstream/v1.x # or upstream/master
+```
+
+
+### TEST
+
+Bug fixes and features should come with tests. Add your tests in the
+`test/` directory. Tests also need to be registered in `test/test-list.h`.
+Look at other tests to see how they should be structured (license boilerplate,
+the way entry points are declared, etc.).
+
+Check README.md file to find out how to run the test suite and make sure that
+there are no test regressions.
+
+### PUSH
+
+```
+$ git push origin my-feature-branch
+```
+
+Go to https://github.com/username/libuv and select your feature branch. Click
+the 'Pull Request' button and fill out the form.
+
+Pull requests are usually reviewed within a few days. If there are comments
+to address, apply your changes in a separate commit and push that to your
+feature branch. Post a comment in the pull request afterwards; GitHub does
+not send out notifications when you add commits.
+
+
+[issue tracker]: https://github.com/libuv/libuv/issues
+[libuv mailing list]: http://groups.google.com/group/libuv
+[IRC]: http://webchat.freelibuv.net/?channels=libuv
+[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
diff --git a/3rdparty/libuv/ChangeLog b/3rdparty/libuv/ChangeLog
new file mode 100644
index 00000000000..d5f95404a56
--- /dev/null
+++ b/3rdparty/libuv/ChangeLog
@@ -0,0 +1,2372 @@
+2015.12.15, Version 1.8.0 (Stable)
+
+Changes since version 1.7.5:
+
+* unix: fix memory leak in uv_interface_addresses (Jianghua Yang)
+
+* unix: make uv_guess_handle work properly for AIX (Gireesh Punathil)
+
+* fs: undo uv__req_init when uv__malloc failed (Jianghua Yang)
+
+* build: remove unused 'component' GYP option (Saúl Ibarra Corretgé)
+
+* include: remove duplicate extern declaration (Jianghua Yang)
+
+* win: use the MSVC provided snprintf where possible (Jason Williams)
+
+* win, test: fix compilation warning (Saúl Ibarra Corretgé)
+
+* win: fix compilation with VS < 2012 (Ryan Johnston)
+
+* stream: support empty uv_try_write on unix (Fedor Indutny)
+
+* unix: fix request handle leak in uv__udp_send (Jianghua Yang)
+
+* src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis)
+
+* unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis)
+
+* unix: squelch harmless valgrind warning (Ben Noordhuis)
+
+* test: don't abort on setrlimit() failure (Ben Noordhuis)
+
+* unix: only undo fs req registration in async mode (Ben Noordhuis)
+
+* unix: fix uv__getiovmax return value (HungMingWu)
+
+* unix: make work with Solaris Studio. (Adam Stylinski)
+
+* test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno)
+
+* unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino)
+
+* test: use FQDN in getaddrinfo_fail test (Wink Saville)
+
+* docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus)
+
+* win: fix comment (Miodrag Milanovic)
+
+* doc: fix typo in README (Angel Leon)
+
+* darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis)
+
+* pipe: enable inprocess uv_write2 on Windows (Louis DeJardin)
+
+* win: properly return UV_EBADF when _close() fails (Nicholas Vavilov)
+
+* test: skip process_title for AIX (Imran Iqbal)
+
+* misc: expose handle print APIs (Petka Antonov)
+
+* include: add stdio.h to uv.h (Saúl Ibarra Corretgé)
+
+* misc: remove unnecessary null pointer checks (Ian Kronquist)
+
+* test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno)
+
+* linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis)
+
+* unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis)
+
+* test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé)
+
+* win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman)
+
+* test: fix test/test-tty.c for AIX (Imran Iqbal)
+
+* android: support api level less than 21 (kkdaemon)
+
+* fsevents: fix race on simultaneous init+close (Fedor Indutny)
+
+* linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé)
+
+* fs: add uv_fs_realpath() (Yuval Brik)
+
+* win: fix path for removed and renamed fs events (Joran Dirk Greef)
+
+* win: do not read more from stream than available (Jeremy Whitlock)
+
+* test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo)
+
+* unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo)
+
+* test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis)
+
+* src: remove non ascii character (sztomi)
+
+* test: fix test udp_multicast_join6 for AIX (Imran Iqbal)
+
+
+2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8
+
+Changes since version 1.7.4:
+
+* unix: Support atomic compare & swap xlC on AIX (nmushell)
+
+* unix: Fix including uv-aix.h on AIX (nmushell)
+
+* unix: consolidate rwlock tryrdlock trywrlock errors (Saúl Ibarra Corretgé)
+
+* unix, win: consolidate mutex trylock errors (Saúl Ibarra Corretgé)
+
+* darwin: fix memory leak in uv_cpu_info (Jianghua Yang)
+
+* test: add tests for the uv_rwlock implementation (Bert Belder)
+
+* win: redo/fix the uv_rwlock APIs (Bert Belder)
+
+* win: don't fetch function pointers to SRWLock APIs (Bert Belder)
+
+
+2015.09.12, Version 1.7.4 (Stable), a7ad4f52189d89cfcba35f78bfc5ff3b1f4105c4
+
+Changes since version 1.7.3:
+
+* doc: uv_read_start and uv_read_cb clarifications (Ben Trask)
+
+* freebsd: obtain true uptime through clock_gettime() (Jianghua Yang)
+
+* win, tty: do not convert \r to \r\n (Colin Snover)
+
+* build,gyp: add DragonFly to the list of OSes (Michael Neumann)
+
+* fs: fix bug in sendfile for DragonFly (Michael Neumann)
+
+* doc: add uv_dlsym() return type (Brian White)
+
+* tests: fix fs tests run w/o full getdents support (Jeremy Whitlock)
+
+* doc: fix typo (Devchandra Meetei Leishangthem)
+
+* doc: fix uv-unix.h location (Sakthipriyan Vairamani)
+
+* unix: fix error check when closing process pipe fd (Ben Noordhuis)
+
+* test,freebsd: fix ipc_listen_xx_write tests (Santiago Gimeno)
+
+* win: fix unsavory rwlock fallback implementation (Bert Belder)
+
+* doc: clarify repeat timer behavior (Eli Skeggs)
+
+
+2015.08.28, Version 1.7.3 (Stable), 93877b11c8b86e0a6befcda83a54555c1e36e4f0
+
+Changes since version 1.7.2:
+
+* threadpool: fix thread starvation bug (Ben Noordhuis)
+
+
+2015.08.25, Version 1.7.2 (Stable), 4d13a013fcfa72311f0102751fdc7951873f466c
+
+Changes since version 1.7.1:
+
+* unix, win: make uv_loop_init return on error (Willem Thiart)
+
+* win: reset pipe handle for pipe servers (Saúl Ibarra Corretgé)
+
+* win: fix replacing pipe handle for pipe servers (Saúl Ibarra Corretgé)
+
+* win: fix setting pipe pending instances after bind (Saúl Ibarra Corretgé)
+
+
+2015.08.20, Version 1.7.1 (Stable), 44f4b6bd82d8ae4583ccc4768a83af778ef69f85
+
+Changes since version 1.7.0:
+
+* doc: document the procedure for verifying releases (Saúl Ibarra Corretgé)
+
+* doc: add note about Windows binaries to the README (Saúl Ibarra Corretgé)
+
+* doc: use long GPG IDs in MAINTAINERS.md (Saúl Ibarra Corretgé)
+
+* Revert "stream: squelch ECONNRESET error if already closed" (Saúl Ibarra
+ Corretgé)
+
+* doc: clarify uv_read_stop() is idempotent (Corbin Simpson)
+
+* unix: OpenBSD's setsockopt needs an unsigned char for multicast (Zachary
+ Hamm)
+
+* test: Fix two memory leaks (Karl Skomski)
+
+* unix,win: return EINVAL on nullptr args in uv_fs_{read,write} (Karl Skomski)
+
+* win: set accepted TCP sockets as non-inheritable (Saúl Ibarra Corretgé)
+
+* unix: remove superfluous parentheses in fs macros (Ben Noordhuis)
+
+* unix: don't copy arguments for sync fs requests (Ben Noordhuis)
+
+* test: plug small memory leak in unix test runner (Ben Noordhuis)
+
+* unix,windows: allow NULL loop for sync fs requests (Ben Noordhuis)
+
+* unix,windows: don't assert on unknown error code (Ben Noordhuis)
+
+* stream: retry write on EPROTOTYPE on OSX (Brian White)
+
+* common: fix use of snprintf on Windows (Saúl Ibarra Corretgé)
+
+* tests: refactored fs watch_dir tests for stability (Jeremy Whitlock)
+
+
+2015.08.06, Version 1.7.0 (Stable), 415a865d6365ba58d02b92b89d46ba5d7744ec8b
+
+Changes since version 1.6.1:
+
+* win,stream: add slot to remember CRT fd (Bert Belder)
+
+* win,pipe: properly close when created from CRT fd (Bert Belder)
+
+* win,pipe: don't close fd 0-2 (Bert Belder)
+
+* win,tty: convert fd -> handle safely (Bert Belder)
+
+* win,tty: properly close when created from CRT fd (Bert Belder)
+
+* win,tty: don't close fd 0-2 (Bert Belder)
+
+* win,fs: don't close fd 0-2 (Bert Belder)
+
+* win: include "malloc.h" (Cheng Zhao)
+
+* windows: MSVC 2015 has C99 inline (Jason Williams)
+
+* dragonflybsd: fixes for nonblocking and cloexec (Michael Neumann)
+
+* dragonflybsd: use sendfile(2) for uv_fs_sendfile (Michael Neumann)
+
+* dragonflybsd: fix uv_exepath (Michael Neumann)
+
+* win,fs: Fixes align(8) directive on mingw (Stefano Cristiano)
+
+* unix, win: prevent replacing fd in uv_{udp,tcp,pipe}_t (Saúl Ibarra Corretgé)
+
+* win: move logic to set socket non-inheritable to uv_tcp_set_socket (Saúl
+ Ibarra Corretgé)
+
+* unix, win: add ability to create tcp/udp sockets early (Saúl Ibarra Corretgé)
+
+* test: retry select() on EINTR, honor milliseconds (Ben Noordhuis)
+
+* unix: consolidate tcp and udp bind error (Saúl Ibarra Corretgé)
+
+* test: conditionally skip udp_ipv6_multicast_join6 (heshamsafi)
+
+* core: add UV_VERSION_HEX macro (Saúl Ibarra Corretgé)
+
+* doc: add section with version-checking macros and functions (Saúl Ibarra
+ Corretgé)
+
+* tty: cleanup handle if uv_tty_init fails (Saúl Ibarra Corretgé)
+
+* darwin: save a fd when FSEvents is used (Saúl Ibarra Corretgé)
+
+* win: fix returning thread id in uv_thread_self (Saúl Ibarra Corretgé)
+
+* common: use offsetof for QUEUE_DATA (Saúl Ibarra Corretgé)
+
+* win: remove UV_HANDLE_CONNECTED (A. Hauptmann)
+
+* docs: add Windows specific note for uv_fs_open (Saúl Ibarra Corretgé)
+
+* doc: add note about uv_fs_scandir (Saúl Ibarra Corretgé)
+
+* test,unix: reduce stack size of watchdog threads (Ben Noordhuis)
+
+* win: add support for recursive file watching (Saúl Ibarra Corretgé)
+
+* win,tty: support consoles with non-default colors (John McNamee)
+
+* doc: add missing variable name (Yosuke Furukawa)
+
+* stream: squelch ECONNRESET error if already closed (Santiago Gimeno)
+
+* build: remove ancient condition from common.gypi (Saúl Ibarra Corretgé)
+
+* tests: skip some tests when network is unreachable (Luca Bruno)
+
+* build: proper support for android cross compilation (guworks)
+
+* android: add missing include to pthread-fixes.c (RossBencina)
+
+* test: fix compilation warning (Saúl Ibarra Corretgé)
+
+* doc: add a note about uv_dirent_t.type (Saúl Ibarra Corretgé)
+
+* win,test: fix shared library build (Saúl Ibarra Corretgé)
+
+* test: fix compilation warning (Santiago Gimeno)
+
+* build: add experimental Windows installer (Roger A. Light)
+
+* threadpool: send signal only when queue is empty (chenttuuvv)
+
+* aix: fix uv_exepath with relative paths (Richard Lau)
+
+* build: fix version syntax in AppVeyor file (Saúl Ibarra Corretgé)
+
+* unix: allow nbufs > IOV_MAX in uv_fs_{read,write} (ronkorving)
+
+
+2015.06.06, Version 1.6.1 (Stable), 30c8be07bb78a66fdee5141626bf53a49a17094a
+
+Changes since version 1.6.0:
+
+* unix: handle invalid _SC_GETPW_R_SIZE_MAX values (cjihrig)
+
+
+2015.06.04, Version 1.6.0 (Stable), adfccad76456061dfcf79b8df8e7dbfee51791d7
+
+Changes since version 1.5.0:
+
+* aix: fix setsockopt for multicast options (Michael)
+
+* unix: don't block for io if any io handle is primed (Saúl Ibarra Corretgé)
+
+* windows: MSVC 2015 has snprintf() (Rui Abreu Ferreira)
+
+* windows: Add VS2015 support to vcbuild.bat (Jason Williams)
+
+* doc: fix typo in tcp.rst (Igor Soarez)
+
+* linux: work around epoll bug in kernels < 2.6.37 (Ben Noordhuis)
+
+* unix,win: add uv_os_homedir() (cjihrig)
+
+* stream: fix `select()` race condition (Fedor Indutny)
+
+* unix: prevent infinite loop in uv__run_pending (Saúl Ibarra Corretgé)
+
+* unix: make sure UDP send callbacks are asynchronous (Saúl Ibarra Corretgé)
+
+* test: fix `platform_output` netmask printing. (Andrew Paprocki)
+
+* aix: add ahafs autoconf detection and README notes (Andrew Paprocki)
+
+* core: add ability to customize memory allocator (Saúl Ibarra Corretgé)
+
+
+2015.05.07, Version 1.5.0 (Stable), 4e77f74c7b95b639b3397095db1bc5bcc016c203
+
+Changes since version 1.4.2:
+
+* doc: clarify that the thread pool primites are not thread safe (Andrius
+ Bentkus)
+
+* aix: always deregister closing fds from epoll (Michael)
+
+* unix: fix glibc-2.20+ macro incompatibility (Massimiliano Torromeo)
+
+* doc: add Sphinx plugin for generating links to man pages (Saúl Ibarra
+ Corretgé)
+
+* doc: link system and library calls to man pages (Saúl Ibarra Corretgé)
+
+* doc: document uv_getnameinfo_t.{host|service} (Saúl Ibarra Corretgé)
+
+* build: update the location of gyp (Stephen von Takach)
+
+* win: name all anonymous structs and unions (TomCrypto)
+
+* linux: work around epoll bug in kernels 3.10-3.19 (Ben Noordhuis)
+
+* darwin: fix size calculation in select() fallback (Ole André Vadla Ravnås)
+
+* solaris: fix setsockopt for multicast options (Julien Gilli)
+
+* test: fix race condition in multithreaded test (Ben Noordhuis)
+
+* doc: fix long lines in tty.rst (Ben Noordhuis)
+
+* test: use UV_TTY_MODE_* values in tty test (Ben Noordhuis)
+
+* unix: don't clobber errno in uv_tty_reset_mode() (Ben Noordhuis)
+
+* unix: reject non-tty fds in uv_tty_init() (Ben Noordhuis)
+
+* win: fix pipe blocking writes (Alexis Campailla)
+
+* build: fix cross-compiling for iOS (Steven Kabbes)
+
+* win: remove unnecessary malloc.h
+
+* include: use `extern "c++"` for defining C++ code (Kazuho Oku)
+
+* unix: reap child on execvp() failure (Ryan Phillips)
+
+* windows: fix handle leak on EMFILE (Brian Green)
+
+* test: fix tty_file, close handle if initialized (Saúl Ibarra Corretgé)
+
+* doc: clarify what uv_*_open accepts (Saúl Ibarra Corretgé)
+
+* doc: clarify that we don't maintain external doc resources (Saúl Ibarra
+ Corretgé)
+
+* build: add documentation for ninja support (Devchandra Meetei Leishangthem)
+
+* doc: document uv_buf_t members (Corey Farrell)
+
+* linux: fix epoll_pwait() fallback on arm64 (Ben Noordhuis)
+
+* android: fix compilation warning (Saúl Ibarra Corretgé)
+
+* unix: don't close the fds we just setup (Sam Roberts)
+
+* test: spawn child replacing std{out,err} to stderr (Saúl Ibarra Corretgé)
+
+* unix: fix swapping fds order in uv_spawn (Saúl Ibarra Corretgé)
+
+* unix: fix potential bug if dup2 fails in uv_spawn (Saúl Ibarra Corretgé)
+
+* test: remove LOG and LOGF variadic macros (Saúl Ibarra Corretgé)
+
+* win: fix uv_fs_access on directories (Saúl Ibarra Corretgé)
+
+* win: fix of double free in uv_uptime (Per Nilsson)
+
+* unix: open "/dev/null" instead of "/" for emfile_fd (Alan Rogers)
+
+* docs: add some missing words (Daryl Haresign)
+
+* unix: clean up uv_fs_open() O_CLOEXEC logic (Ben Noordhuis)
+
+* build: set SONAME for shared library in uv.gyp (Rui Abreu Ferreira)
+
+* windows: define snprintf replacement as inline instead of static (Rui Abreu
+ Ferreira)
+
+* win: fix unlink of readonly files (João Reis)
+
+* doc: fix uv_run(UV_RUN_DEFAULT) description (Ben Noordhuis)
+
+* linux: intercept syscall when running under memory sanitizer (Keno Fischer)
+
+* aix: fix uv_interface_addresses return value (farblue68)
+
+* windows: defer reporting TCP write failure until next tick (Saúl Ibarra
+ Corretgé)
+
+* test: add test for deferred TCP write failure (Saúl Ibarra Corretgé)
+
+
+2015.02.27, Version 1.4.2 (Stable), 1a7391348a11d5450c0f69c828d5302e2cb842eb
+
+Changes since version 1.4.1:
+
+* stream: ignore EINVAL for SO_OOBINLINE on OS X (Fedor Indutny)
+
+
+2015.02.25, Version 1.4.1 (Stable), e8e3fc5789cc0f02937879d141cca0411274093c
+
+Changes since version 1.4.0:
+
+* win: don't use inline keyword in thread.c (Ben Noordhuis)
+
+* windows: fix setting dirent types on uv_fs_scandir_next (Saúl Ibarra
+ Corretgé)
+
+* unix,windows: make uv_thread_create() return errno (Ben Noordhuis)
+
+* tty: fix build for SmartOS (Julien Gilli)
+
+* unix: fix for uv_async data race (Michael Penick)
+
+* unix, windows: map EHOSTDOWN errno (Ben Noordhuis)
+
+* stream: use SO_OOBINLINE on OS X (Fedor Indutny)
+
+
+2015.02.10, Version 1.4.0 (Stable), 19fb8a90648f3763240db004b77ab984264409be
+
+Changes since version 1.3.0:
+
+* unix: check Android support for pthread_cond_timedwait_monotonic_np (Leith
+ Bade)
+
+* test: use modified path in test (cjihrig)
+
+* unix: implement uv_stream_set_blocking() (Ben Noordhuis)
+
+
+2015.01.29, Version 1.3.0 (Stable), 165685b2a9a42cf96501d79cd6d48a18aaa16e3b
+
+Changes since version 1.2.1:
+
+* unix, windows: set non-block mode in uv_poll_init (Saúl Ibarra Corretgé)
+
+* doc: clarify which flags are supported in uv_fs_event_start (Saúl Ibarra
+ Corretgé)
+
+* win,unix: move loop functions which have identical implementations (Andrius
+ Bentkus)
+
+* doc: explain how the threadpool is allocated (Alex Mo)
+
+* doc: clarify uv_default_loop (Saúl Ibarra Corretgé)
+
+* unix: fix implicit declaration compiler warning (Ben Noordhuis)
+
+* unix: fix long line introduced in commit 94e628fa (Ben Noordhuis)
+
+* unix, win: add synchronous uv_get{addr,name}info (Saúl Ibarra Corretgé)
+
+* linux: fix epoll_pwait() regression with < 2.6.19 (Ben Noordhuis)
+
+* build: compile -D_GNU_SOURCE on linux (Ben Noordhuis)
+
+* build: use -fvisibility=hidden in autotools build (Ben Noordhuis)
+
+* fs, pipe: no trailing terminator in exact sized buffers (Andrius Bentkus)
+
+* style: rename buf to buffer and len to size for consistency (Andrius Bentkus)
+
+* test: fix test-spawn on MinGW32 (Luis Martinez de Bartolome)
+
+* win, pipe: fix assertion when destroying timer (Andrius Bentkus)
+
+* win, unix: add pipe_peername implementation (Andrius Bentkus)
+
+
+2015.01.29, Version 0.10.33 (Stable), 7a2253d33ad8215a26c1b34f1952aee7242dd687
+
+Changes since version 0.10.32:
+
+* linux: fix epoll_pwait() regression with < 2.6.19 (Ben Noordhuis)
+
+* test: back-port uv_loop_configure() test (Ben Noordhuis)
+
+
+2015.01.15, Version 1.2.1 (Stable), 4ca78e989062a1099dc4b9ad182a98e8374134b1
+
+Changes since version 1.2.0:
+
+* unix: remove unused dtrace file (Saúl Ibarra Corretgé)
+
+* test: skip TTY select test if /dev/tty can't be opened (Saúl Ibarra Corretgé)
+
+* doc: clarify the behavior of uv_tty_init (Saúl Ibarra Corretgé)
+
+* doc: clarify how uv_async_send behaves (Saúl Ibarra Corretgé)
+
+* build: make dist now generates a full tarball (Johan Bergström)
+
+* freebsd: make uv_exepath more resilient (Saúl Ibarra Corretgé)
+
+* unix: make setting the tty mode to the same value a no-op (Saúl Ibarra
+ Corretgé)
+
+* win,tcp: support uv_try_write (Bert Belder)
+
+* test: enable test-tcp-try-write on windows (Bert Belder)
+
+* win,tty: support uv_try_write (Bert Belder)
+
+* unix: set non-block mode in uv_{pipe,tcp,udp}_open (Ben Noordhuis)
+
+
+2015.01.06, Version 1.2.0 (Stable), 09f25b13cd149c7981108fc1a75611daf1277f83
+
+Changes since version 1.1.0:
+
+* linux: fix epoll_pwait() sigmask size calculation (Ben Noordhuis)
+
+* tty: implement binary I/O terminal mode (Yuri D'Elia)
+
+* test: fix spawn test with autotools build (Ben Noordhuis)
+
+* test: skip ipv6 tests when ipv6 is not supported (Ben Noordhuis)
+
+* common: move STATIC_ASSERT to uv-common.h (Alexey Melnichuk)
+
+* win/thread: store thread handle in a TLS slot (Alexey Melnichuk)
+
+* unix: fix ttl, multicast ttl and loop options on IPv6 (Saúl Ibarra Corretgé)
+
+* linux: fix support for preadv/pwritev-less kernels (Ben Noordhuis)
+
+* unix: make uv_exepath(size=0) return UV_EINVAL (Ben Noordhuis)
+
+* darwin: fix uv_exepath(smallbuf) UV_EPERM error (Ben Noordhuis)
+
+* openbsd: fix uv_exepath(smallbuf) UV_EINVAL error (Ben Noordhuis)
+
+* linux: fix uv_exepath(size=1) UV_EINVAL error (Ben Noordhuis)
+
+* sunos: preemptively fix uv_exepath(size=1) (Ben Noordhuis)
+
+* win: fix and clarify comments in winapi.h (Bert Belder)
+
+* win: make available NtQueryDirectoryFile (Bert Belder)
+
+* win: add definitions for directory information types (Bert Belder)
+
+* win: use NtQueryDirectoryFile to implement uv_fs_scandir (Bert Belder)
+
+* unix: don't unlink unix socket on bind error (Ben Noordhuis)
+
+* build: fix bad comment in autogen.sh (Ben Noordhuis)
+
+* build: add AC_PROG_LIBTOOL to configure.ac (Ben Noordhuis)
+
+* test: skip udp_options6 if there no IPv6 support (Saúl Ibarra Corretgé)
+
+* win: add definitions for MUI errors mingw lacks (Bert Belder)
+
+* build: enable warnings in autotools build (Ben Noordhuis)
+
+* build: remove -Wno-dollar-in-identifier-extension (Ben Noordhuis)
+
+* build: move flags from Makefile.am to configure.ac (Ben Noordhuis)
+
+
+2015.01.06, Version 0.10.32 (Stable), 378de30c59aef5fdb6d130fa5cfcb0a68fce571c
+
+Changes since version 0.10.31:
+
+* linux: fix epoll_pwait() sigmask size calculation (Ben Noordhuis)
+
+
+2014.12.25, Version 1.1.0 (Stable), 9572f3e74a167f59a8017e57ca3ebe91ffd88e18
+
+Changes since version 1.0.2:
+
+* test: test that closing a poll handle doesn't corrupt the stack (Bert Belder)
+
+* win: fix compilation of tests (Marc Schlaich)
+
+* Revert "win: keep a reference to AFD_POLL_INFO in cancel poll" (Bert Belder)
+
+* win: avoid stack corruption when closing a poll handle (Bert Belder)
+
+* test: fix test-fs-file-loop on Windows (Bert Belder)
+
+* test: fix test-cwd-and-chdir (Bert Belder)
+
+* doc: indicate what version uv_loop_configure was added on (Saúl Ibarra
+ Corretgé)
+
+* doc: fix sphinx warning (Saúl Ibarra Corretgé)
+
+* test: skip spawn_setuid_setgid if we get EACCES (Saúl Ibarra Corretgé)
+
+* test: silence some Clang warnings (Saúl Ibarra Corretgé)
+
+* test: relax osx_select_many_fds (Saúl Ibarra Corretgé)
+
+* test: fix compilation warnings when building with Clang (Saúl Ibarra
+ Corretgé)
+
+* win: fix autotools build of tests (Luis Lavena)
+
+* gitignore: ignore Visual Studio files (Marc Schlaich)
+
+* win: set fallback message if FormatMessage fails (Marc Schlaich)
+
+* win: fall back to default language in uv_dlerror (Marc Schlaich)
+
+* test: improve compatibility for dlerror test (Marc Schlaich)
+
+* test: check dlerror is "no error" in no error case (Marc Schlaich)
+
+* unix: change uv_cwd not to return a trailing slash (Saúl Ibarra Corretgé)
+
+* test: fix cwd_and_chdir test on Unix (Saúl Ibarra Corretgé)
+
+* test: add uv_cwd output to platform_output test (Saúl Ibarra Corretgé)
+
+* build: fix dragonflybsd autotools build (John Marino)
+
+* win: scandir use 'ls' for formatting long strings (Kenneth Perry)
+
+* build: remove clang and gcc_version gyp defines (Ben Noordhuis)
+
+* unix, windows: don't treat uv_run_mode as a bitmask (Saúl Ibarra Corretgé)
+
+* unix, windows: fix UV_RUN_ONCE mode if progress was made (Saúl Ibarra
+ Corretgé)
+
+
+2014.12.25, Version 0.10.31 (Stable), 4dbd27e2219069a6daa769fb37f98673b77b4261
+
+Changes since version 0.10.30:
+
+* test: test that closing a poll handle doesn't corrupt the stack (Bert Belder)
+
+* win: fix compilation of tests (Marc Schlaich)
+
+* Revert "win: keep a reference to AFD_POLL_INFO in cancel poll" (Bert Belder)
+
+* win: avoid stack corruption when closing a poll handle (Bert Belder)
+
+* gitignore: ignore Visual Studio files (Marc Schlaich)
+
+* win: set fallback message if FormatMessage fails (Marc Schlaich)
+
+* win: fall back to default language in uv_dlerror (Marc Schlaich)
+
+* test: improve compatibility for dlerror test (Marc Schlaich)
+
+* test: check dlerror is "no error" in no error case (Marc Schlaich)
+
+* build: link against -pthread (Logan Rosen)
+
+* win: scandir use 'ls' for formatting long strings (Kenneth Perry)
+
+
+2014.12.10, Version 1.0.2 (Stable), eec671f0059953505f9a3c9aeb7f9f31466dd7cd
+
+Changes since version 1.0.1:
+
+* linux: fix sigmask size arg in epoll_pwait() call (Ben Noordhuis)
+
+* linux: handle O_NONBLOCK != SOCK_NONBLOCK case (Helge Deller)
+
+* doc: fix spelling (Joey Geralnik)
+
+* unix, windows: fix typos in comments (Joey Geralnik)
+
+* test: canonicalize test runner path (Ben Noordhuis)
+
+* test: fix compilation warnings (Saúl Ibarra Corretgé)
+
+* test: skip tty test if detected width and height are 0 (Saúl Ibarra Corretgé)
+
+* doc: update README with IRC channel (Saúl Ibarra Corretgé)
+
+* Revert "unix: use cfmakeraw() for setting raw TTY mode" (Ben Noordhuis)
+
+* doc: document how to get result of uv_fs_mkdtemp (Tim Caswell)
+
+* unix: add flag for blocking SIGPROF during poll (Ben Noordhuis)
+
+* unix, windows: add uv_loop_configure() function (Ben Noordhuis)
+
+* win: keep a reference to AFD_POLL_INFO in cancel poll (Marc Schlaich)
+
+* test: raise fd limit for OSX select test (Saúl Ibarra Corretgé)
+
+* unix: remove overzealous assert in uv_read_stop (Saúl Ibarra Corretgé)
+
+* unix: reset the reading flag when a stream gets EOF (Saúl Ibarra Corretgé)
+
+* unix: stop reading if an error is produced (Saúl Ibarra Corretgé)
+
+* cleanup: remove all dead assignments (Maciej Małecki)
+
+* linux: return early if we have no interfaces (Maciej Małecki)
+
+* cleanup: remove a dead increment (Maciej Małecki)
+
+
+2014.12.10, Version 0.10.30 (Stable), 5a63f5e9546dca482eeebc3054139b21f509f21f
+
+Changes since version 0.10.29:
+
+* linux: fix sigmask size arg in epoll_pwait() call (Ben Noordhuis)
+
+* linux: handle O_NONBLOCK != SOCK_NONBLOCK case (Helge Deller)
+
+* doc: update project links (Ben Noordhuis)
+
+* windows: fix compilation of tests (Marc Schlaich)
+
+* unix: add flag for blocking SIGPROF during poll (Ben Noordhuis)
+
+* unix, windows: add uv_loop_configure() function (Ben Noordhuis)
+
+* win: keep a reference to AFD_POLL_INFO in cancel poll (Marc Schlaich)
+
+
+2014.11.27, Version 1.0.1 (Stable), 0a8e81374e861d425b56c45c8599595d848911d2
+
+Changes since version 1.0.0:
+
+* readme: remove Rust from users (Elijah Andrews)
+
+* doc,build,include: update project links (Ben Noordhuis)
+
+* doc: fix typo: Strcutures -> Structures (Michael Ira Krufky)
+
+* unix: fix processing process handles queue (Saúl Ibarra Corretgé)
+
+* win: replace non-ansi characters in source file (Bert Belder)
+
+
+2014.11.21, Version 1.0.0 (Stable), feb2a9e6947d892f449b2770c4090f7d8c88381b
+
+Changes since version 1.0.0-rc2:
+
+* doc: fix git/svn url for gyp repo in README (Emmanuel Odeke)
+
+* windows: fix fs_read with nbufs > 1 and offset (Unknown W. Brackets)
+
+* win: add missing IP_ADAPTER_UNICAST_ADDRESS_LH definition for MinGW
+ (huxingyi)
+
+* doc: mention homebrew in README (Mikhail Mukovnikov)
+
+* doc: add learnuv workshop to README (Thorsten Lorenz)
+
+* doc: fix parameter name in uv_fs_access (Saúl Ibarra Corretgé)
+
+* unix: use cfmakeraw() for setting raw TTY mode (Yuri D'Elia)
+
+* win: fix uv_thread_self() (Alexis Campailla)
+
+* build: add x32 support to gyp build (Ben Noordhuis)
+
+* build: remove dtrace probes (Ben Noordhuis)
+
+* doc: fix link in misc.rst (Manos Nikolaidis)
+
+* mailmap: remove duplicated entries (Saúl Ibarra Corretgé)
+
+* gyp: fix comment regarding version info location (Saúl Ibarra Corretgé)
+
+
+2014.10.21, Version 1.0.0-rc2 (Pre-release)
+
+Changes since version 1.0.0-rc1:
+
+* build: add missing fixtures to distribution tarball (Rob Adams)
+
+* doc: update references to current stable branch (Zachary Newman)
+
+* fs: fix readdir on empty directory (Fedor Indutny)
+
+* fs: rename uv_fs_readdir to uv_fs_scandir (Saúl Ibarra Corretgé)
+
+* doc: document uv_alloc_cb (Saúl Ibarra Corretgé)
+
+* doc: add migration guide from version 0.10 (Saúl Ibarra Corretgé)
+
+* build: add DragonFly BSD support in autotools (Robin Hahling)
+
+* doc: document missing stream related structures (Saúl Ibarra Corretgé)
+
+* doc: clarify uv_loop_t.data field lifetime (Saúl Ibarra Corretgé)
+
+* doc: add documentation for missing functions and structures (Saúl Ibarra
+ Corretgé)
+
+* doc: fix punctuation and grammar in README (Jeff Widman)
+
+* windows: return libuv error codes in uv_poll_init() (cjihrig)
+
+* unix, windows: add uv_fs_access() (cjihrig)
+
+* windows: fix netmask detection (Alexis Campailla)
+
+* unix, windows: don't include null byte in uv_cwd size (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_thread_equal (Tomasz Kołodziejski)
+
+* windows: fix fs_write with nbufs > 1 and offset (Unknown W. Brackets)
+
+
+2014.10.21, Version 0.10.29 (Stable), 2d728542d3790183417f8f122a110693cd85db14
+
+Changes since version 0.10.28:
+
+* darwin: allocate enough space for select() hack (Fedor Indutny)
+
+* linux: try epoll_pwait if epoll_wait is missing (Michael Hudson-Doyle)
+
+* windows: map ERROR_INVALID_DRIVE to UV_ENOENT (Saúl Ibarra Corretgé)
+
+
+2014.09.18, Version 1.0.0-rc1 (Unstable), 0c28bbf7b42882853d1799ab96ff68b07f7f8d49
+
+Changes since version 0.11.29:
+
+* windows: improve timer precision (Alexis Campailla)
+
+* build, gyp: set xcode flags (Recep ASLANTAS)
+
+* ignore: include m4 files which are created manually (Recep ASLANTAS)
+
+* build: add m4 for feature/flag-testing (Recep ASLANTAS)
+
+* ignore: ignore Xcode project and workspace files (Recep ASLANTAS)
+
+* unix: fix warnings about dollar symbol usage in identifiers (Recep ASLANTAS)
+
+* unix: fix warnings when loading functions with dlsym (Recep ASLANTAS)
+
+* linux: try epoll_pwait if epoll_wait is missing (Michael Hudson-Doyle)
+
+* test: add test for closing and recreating default loop (Saúl Ibarra Corretgé)
+
+* windows: properly close the default loop (Saúl Ibarra Corretgé)
+
+* version: add ability to specify a version suffix (Saúl Ibarra Corretgé)
+
+* doc: add API documentation (Saúl Ibarra Corretgé)
+
+* test: don't close connection on write error (Trevor Norris)
+
+* windows: further simplify the code for timers (Saúl Ibarra Corretgé)
+
+* gyp: remove UNLIMITED_SELECT from dependent define (Fedor Indutny)
+
+* darwin: allocate enough space for select() hack (Fedor Indutny)
+
+* unix, windows: don't allow a NULL callback on timers (Saúl Ibarra Corretgé)
+
+* windows: simplify code in uv_timer_again (Saúl Ibarra Corretgé)
+
+* test: use less requests on tcp-write-queue-order (Saúl Ibarra Corretgé)
+
+* unix: stop child process watcher after last one exits (Saúl Ibarra Corretgé)
+
+* unix: simplify how process handle queue is managed (Saúl Ibarra Corretgé)
+
+* windows: remove duplicated field (mattn)
+
+* core: add a reserved field to uv_handle_t and uv_req_t (Saúl Ibarra Corretgé)
+
+* windows: fix buffer leak after failed udp send (Bert Belder)
+
+* windows: make sure sockets and handles are reset on close (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_fileno (Saúl Ibarra Corretgé)
+
+* build: use same CFLAGS in autotools build as in gyp (Saúl Ibarra Corretgé)
+
+* build: remove unneeded define in uv.gyp (Saúl Ibarra Corretgé)
+
+* test: fix watcher_cross_stop on Windows (Saúl Ibarra Corretgé)
+
+* unix, windows: move includes for EAI constants (Saúl Ibarra Corretgé)
+
+* unix: fix exposing EAI_* glibc-isms (Saúl Ibarra Corretgé)
+
+* unix: fix tcp write after bad connect freezing (Andrius Bentkus)
+
+
+2014.08.20, Version 0.11.29 (Unstable), 35451fed830807095bbae8ef981af004a4b9259e
+
+Changes since version 0.11.28:
+
+* windows: make uv_read_stop immediately stop reading (Jameson Nash)
+
+* windows: fix uv__getaddrinfo_translate_error (Alexis Campailla)
+
+* netbsd: fix build (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_recv_buffer_size and uv_send_buffer_size (Andrius
+ Bentkus)
+
+* windows: add support for UNC paths on uv_spawn (Paul Goldsmith)
+
+* windows: replace use of inet_addr with uv_inet_pton (Saúl Ibarra Corretgé)
+
+* unix: replace some asserts with returning errors (Andrius Bentkus)
+
+* windows: use OpenBSD implementation for uv_fs_mkdtemp (Pavel Platto)
+
+* windows: fix GetNameInfoW error handling (Alexis Campailla)
+
+* fs: introduce uv_readdir_next() and report types (Fedor Indutny)
+
+* fs: extend reported types in uv_fs_readdir_next (Saúl Ibarra Corretgé)
+
+* unix: read on stream even when UV__POLLHUP set. (Julien Gilli)
+
+
+2014.08.08, Version 0.11.28 (Unstable), fc9e2a0bc487b299c0cd3b2c9a23aeb554b5d8d1
+
+Changes since version 0.11.27:
+
+* unix, windows: const-ify handle in uv_udp_getsockname (Rasmus Pedersen)
+
+* windows: use UV_ECANCELED for aborted TCP writes (Saúl Ibarra Corretgé)
+
+* windows: add more required environment variables (Jameson Nash)
+
+* windows: sort environment variables before calling CreateProcess (Jameson
+ Nash)
+
+* unix, windows: move uv_loop_close out of assert (John Firebaugh)
+
+* windows: fix buffer overflow on uv__getnameinfo_work() (lilohuang)
+
+* windows: add uv_backend_timeout (Jameson Nash)
+
+* test: disable tcp_close_accept on Windows (Saúl Ibarra Corretgé)
+
+* windows: read the PATH env var of the child (Alex Crichton)
+
+* include: avoid using C++ 'template' reserved word (Iñaki Baz Castillo)
+
+* include: fix version number (Saúl Ibarra Corretgé)
+
+
+2014.07.32, Version 0.11.27 (Unstable), ffe24f955032d060968ea0289af365006afed55e
+
+Changes since version 0.11.26:
+
+* unix, windows: use the same threadpool implementation (Saúl Ibarra Corretgé)
+
+* unix: use struct sockaddr_storage for target UDP addr (Saúl Ibarra Corretgé)
+
+* doc: add documentation to uv_udp_start_recv (Andrius Bentkus)
+
+* common: use common uv__count_bufs code (Andrius Bentkus)
+
+* unix, win: add send_queue_size and send_queue_count to uv_udp_t (Andrius
+ Bentkus)
+
+* unix, win: add uv_udp_try_send (Andrius Bentkus)
+
+* unix: return UV_EAGAIN if uv_try_write cannot write any data (Saúl Ibarra
+ Corretgé)
+
+* windows: fix compatibility with cygwin pipes (Jameson Nash)
+
+* windows: count queued bytes even if request completed immediately (Saúl
+ Ibarra Corretgé)
+
+* windows: disable CRT debug handler on MinGW32 (Saúl Ibarra Corretgé)
+
+* windows: map ERROR_INVALID_DRIVE to UV_ENOENT (Saúl Ibarra Corretgé)
+
+* unix: try to write immediately in uv_udp_send (Saúl Ibarra Corretgé)
+
+* unix: remove incorrect assert (Saúl Ibarra Corretgé)
+
+* openbsd: avoid requiring privileges for uv_resident_set_memory (Aaron Bieber)
+
+* unix: guarantee write queue cb execution order in streams (Andrius Bentkus)
+
+* img: add logo files (Saúl Ibarra Corretgé)
+
+* aix: improve AIX compatibility (Andrew Low)
+
+* windows: return bind error immediately when implicitly binding (Saúl Ibarra
+ Corretgé)
+
+* windows: don't use atexit for cleaning up the threadpool (Saúl Ibarra
+ Corretgé)
+
+* windows: destroy work queue elements when colsing a loop (Saúl Ibarra
+ Corretgé)
+
+* unix, windows: add uv_fs_mkdtemp (Pavel Platto)
+
+* build: handle platforms without multiprocessing.synchronize (Saúl Ibarra
+ Corretgé)
+
+* windows: change GENERIC_ALL to GENERIC_WRITE in fs__create_junction (Tony
+ Kelman)
+
+* windows: relay TCP bind errors via ipc (Alexis Campailla)
+
+
+2014.07.32, Version 0.10.28 (Stable), 9c14b616f5fb84bfd7d45707bab4bbb85894443e
+
+Changes since version 0.10.27:
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* unix: return system error on EAI_SYSTEM (Saúl Ibarra Corretgé)
+
+* unix: fix bogus structure field name (Saúl Ibarra Corretgé)
+
+* darwin: invoke `mach_timebase_info` only once (Fedor Indutny)
+
+
+2014.06.28, Version 0.11.26 (Unstable), 115281a1058c4034d5c5ccedacb667fe3f6327ea
+
+Changes since version 0.11.25:
+
+* windows: add VT100 codes ?25l and ?25h (JD Ballard)
+
+* windows: add invert ANSI (7 / 27) emulation (JD Ballard)
+
+* unix: fix handling error on UDP socket creation (Saúl Ibarra Corretgé)
+
+* unix, windows: getnameinfo implementation (Rasmus Pedersen)
+
+* heap: fix `heap_remove()` (Fedor Indutny)
+
+* unix, windows: fix parsing scoped IPv6 addresses (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* thread: barrier functions (Ben Noordhuis)
+
+* windows: fix PYTHON environment variable usage (Jay Satiro)
+
+* unix, windows: return system error on EAI_SYSTEM (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* unix: don't run i/o callbacks after prepare callbacks (Saúl Ibarra Corretgé)
+
+* windows: add tty unicode support for input (Peter Atashian)
+
+* header: introduce `uv_loop_size()` (Andrius Bentkus)
+
+* darwin: invoke `mach_timebase_info` only once (Fedor Indutny)
+
+
+2014.05.02, Version 0.11.25 (Unstable), 2acd544cff7142e06aa3b09ec64b4a33dd9ab996
+
+Changes since version 0.11.24:
+
+* osx: pass const handle pointer to uv___stream_fd (Chernyshev Viacheslav)
+
+* unix, windows: pass const handle ptr to uv_tcp_get*name (Chernyshev
+ Viacheslav)
+
+* common: pass const sockaddr ptr to uv_ip*_name (Chernyshev Viacheslav)
+
+* unix, windows: validate flags on uv_udp|tcp_bind (Saúl Ibarra Corretgé)
+
+* unix: handle case when addr is not initialized after recvmsg (Saúl Ibarra
+ Corretgé)
+
+* unix, windows: uv_now constness (Rasmus Pedersen)
+
+
+2014.04.15, Version 0.11.24 (Unstable), ed948c29f6e8c290f79325a6f0bc9ef35bcde644
+
+Changes since version 0.11.23:
+
+* linux: reduce file descriptor count of async pipe (Ben Noordhuis)
+
+* sunos: support IPv6 qualified link-local addresses (Saúl Ibarra Corretgé)
+
+* windows: fix opening of read-only stdin pipes (Alexis Campailla)
+
+* windows: Fix an infinite loop in uv_spawn (Alex Crichton)
+
+* windows: fix console signal handler refcount (李港平)
+
+* inet: allow scopeid in uv_inet_pton (Fedor Indutny)
+
+
+2014.04.07, Version 0.11.23 (Unstable), e54de537efcacd593f36fcaaf8b4cb9e64313275
+
+Changes since version 0.11.22:
+
+* fs: avoid using readv/writev where possible (Fedor Indutny)
+
+* mingw: fix build with autotools (Saúl Ibarra Corretgé)
+
+* bsd: support IPv6 qualified link-local addresses (Saúl Ibarra Corretgé)
+
+* unix: add UV_HANDLE_IPV6 flag to tcp and udp handles (Saúl Ibarra Corretgé)
+
+* unix, windows: do not set SO_REUSEADDR by default on udp (Saúl Ibarra
+ Corretgé)
+
+* windows: fix check in uv_tty_endgame() (Maks Naumov)
+
+* unix, windows: add IPv6 support for uv_udp_multicast_interface (Saúl Ibarra
+ Corretgé)
+
+* unix: fallback to blocking writes if reopening a tty fails (Saúl Ibarra
+ Corretgé)
+
+* unix: fix handling uv__open_cloexec failure (Saúl Ibarra Corretgé)
+
+* unix, windows: add IPv6 support to uv_udp_set_membership (Saúl Ibarra
+ Corretgé)
+
+* unix, windows: removed unused status parameter (Saúl Ibarra Corretgé)
+
+* android: add support of ifaddrs in android (Javier Hernández)
+
+* build: fix SunOS and AIX build with autotools (Saúl Ibarra Corretgé)
+
+* build: freebsd link with libelf if dtrace enabled (Saúl Ibarra Corretgé)
+
+* stream: do not leak `alloc_cb` buffers on error (Fedor Indutny)
+
+* unix: fix setting written size on uv_wd (Saúl Ibarra Corretgé)
+
+
+2014.03.11, Version 0.11.22 (Unstable), cd0c19b1d3c56acf0ade7687006e12e75fbda36d
+
+Changes since version 0.11.21:
+
+* unix, windows: map ERANGE errno (Saúl Ibarra Corretgé)
+
+* unix, windows: make uv_cwd be consistent with uv_exepath (Saúl Ibarra
+ Corretgé)
+
+* process: remove debug perror() prints (Fedor Indutny)
+
+* windows: fall back for volume info query (Isaiah Norton)
+
+* pipe: allow queueing pending handles (Fedor Indutny)
+
+* windows: fix winsock status codes for address errors (Raul Martins)
+
+* windows: Remove unused variable from uv__pipe_insert_pending_socket (David
+ Capello)
+
+* unix: workaround broken pthread_sigmask on Android (Paul Tan)
+
+* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
+
+* freebsd: use accept4, introduced in version 10 (Saúl Ibarra Corretgé)
+
+* windows: fix warnings of MinGW -Wall -O3 (StarWing)
+
+* openbsd, osx: fix compilation warning on scandir (Saúl Ibarra Corretgé)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* unix: reopen tty as /dev/tty (Saúl Ibarra Corretgé)
+
+* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
+
+
+2014.02.28, Version 0.11.21 (Unstable), 3ef958158ae1019e027ebaa93114160099db5206
+
+Changes since version 0.11.20:
+
+* unix: fix uv_fs_write when using an empty buffer (Saúl Ibarra Corretgé)
+
+* unix, windows: add assertion in uv_loop_delete (Saúl Ibarra Corretgé)
+
+
+2014.02.27, Version 0.11.20 (Unstable), 88355e081b51c69ee1e2b6b0015a4e3d38bd0579
+
+Changes since version 0.11.19:
+
+* stream: start thread after assignments (Oguz Bastemur)
+
+* fs: `uv__cloexec()` opened fd (Fedor Indutny)
+
+* gyp: qualify `library` variable (Fedor Indutny)
+
+* unix, win: add uv_udp_set_multicast_interface() (Austin Foxley)
+
+* unix: fix uv_tcp_nodelay return value in case of error (Saúl Ibarra Corretgé)
+
+* unix: call setgoups before calling setuid/setgid (Saúl Ibarra Corretgé)
+
+* include: mark close_cb field as private (Saúl Ibarra Corretgé)
+
+* unix, windows: map EFBIG errno (Saúl Ibarra Corretgé)
+
+* unix: correct error when calling uv_shutdown twice (Keno Fischer)
+
+* windows: fix building on MinGW (Alex Crichton)
+
+* windows: always initialize uv_process_t (Alex Crichton)
+
+* include: expose libuv version in header files (Saúl Ibarra Corretgé)
+
+* fs: vectored IO API for filesystem read/write (Benjamin Saunders)
+
+* windows: freeze in uv_tcp_endgame (Alexis Campailla)
+
+* sunos: handle rearm errors (Fedor Indutny)
+
+* unix: use a heap for timers (Ben Noordhuis)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* linux: include grp.h for setgroups() (William Light)
+
+* unix, windows: add uv_loop_init and uv_loop_close (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_getrusage() function (Oleg Efimov)
+
+* win: minor error handle fix to uv_pipe_write_impl (Rasmus Pedersen)
+
+* heap: fix node removal (Keno Fischer)
+
+* win: fix C99/C++ comment (Rasmus Pedersen)
+
+* fs: vectored IO API for filesystem read/write (Benjamin Saunders)
+
+* unix, windows: add uv_pipe_getsockname (Saúl Ibarra Corretgé)
+
+* unix, windows: map ENOPROTOOPT errno (Saúl Ibarra Corretgé)
+
+* errno: add ETXTBSY (Fedor Indutny)
+
+* fsevent: rename filename field to path (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_fs_event_getpath (Saúl Ibarra Corretgé)
+
+* unix, windows: add uv_fs_poll_getpath (Saúl Ibarra Corretgé)
+
+* unix, windows: map ERANGE errno (Saúl Ibarra Corretgé)
+
+* unix, windows: set required size on UV_ENOBUFS (Saúl Ibarra Corretgé)
+
+* unix, windows: clarify what uv_stream_set_blocking does (Saúl Ibarra
+ Corretgé)
+
+* fs: use preadv on Linux if available (Brian White)
+
+
+2014.01.30, Version 0.11.19 (Unstable), 336a1825309744f920230ec3e427e78571772347
+
+Changes since version 0.11.18:
+
+* linux: move sscanf() out of the assert() (Trevor Norris)
+
+* linux: fix C99/C++ comment (Fedor Indutny)
+
+
+2014.05.02, Version 0.10.27 (Stable), 6e24ce23b1e7576059f85a608eca13b766458a01
+
+Changes since version 0.10.26:
+
+* windows: fix console signal handler refcount (Saúl Ibarra Corretgé)
+
+* win: always leave crit section in get_proc_title (Fedor Indutny)
+
+
+2014.04.07, Version 0.10.26 (Stable), d864907611c25ec986c5e77d4d6d6dee88f26926
+
+Changes since version 0.10.25:
+
+* process: don't close stdio fds during spawn (Tonis Tiigi)
+
+* build, windows: do not fail on Windows SDK Prompt (Marc Schlaich)
+
+* build, windows: fix x64 configuration issue (Marc Schlaich)
+
+* win: fix buffer leak on error in pipe.c (Fedor Indutny)
+
+* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
+
+
+2014.02.19, Version 0.10.25 (Stable), d778dc588507588b12b9f9d2905078db542ed751
+
+Changes since version 0.10.24:
+
+* stream: start thread after assignments (Oguz Bastemur)
+
+* unix: correct error when calling uv_shutdown twice (Saúl Ibarra Corretgé)
+
+2014.01.30, Version 0.10.24 (Stable), aecd296b6bce9b40f06a61c5c94e43d45ac7308a
+
+Changes since version 0.10.23:
+
+* linux: move sscanf() out of the assert() (Trevor Norris)
+
+* linux: fix C99/C++ comment (Fedor Indutny)
+
+
+2014.01.23, Version 0.11.18 (Unstable), d47962e9d93d4a55a9984623feaf546406c9cdbb
+
+Changes since version 0.11.17:
+
+* osx: Fix a possible segfault in uv__io_poll (Alex Crichton)
+
+* windows: improved handling of invalid FDs (Alexis Campailla)
+
+* doc: adding ARCHS flag to OS X build command (Nathan Sweet)
+
+* tcp: reveal bind-time errors before listen (Alexis Campailla)
+
+* tcp: uv_tcp_dualstack() (Fedor Indutny)
+
+* linux: relax assumption on /proc/stat parsing (Luca Bruno)
+
+* openbsd: fix obvious bug in uv_cpu_info (Fedor Indutny)
+
+* process: close stdio after dup2'ing it (Fedor Indutny)
+
+* linux: move sscanf() out of the assert() (Trevor Norris)
+
+
+2014.01.23, Version 0.10.23 (Stable), dbd218e699fec8be311d85e4788be9e28ae884f8
+
+Changes since version 0.10.22:
+
+* linux: relax assumption on /proc/stat parsing (Luca Bruno)
+
+* openbsd: fix obvious bug in uv_cpu_info (Fedor Indutny)
+
+* process: close stdio after dup2'ing it (Fedor Indutny)
+
+
+2014.01.08, Version 0.10.22 (Stable), f526c90eeff271d9323a9107b9a64a4671fd3103
+
+Changes since version 0.10.21:
+
+* windows: avoid assertion failure when pipe server is closed (Bert Belder)
+
+
+2013.12.32, Version 0.11.17 (Unstable), 589c224d4c2e79fec65db01d361948f1e4976858
+
+Changes since version 0.11.16:
+
+* stream: allow multiple buffers for uv_try_write (Fedor Indutny)
+
+* unix: fix a possible memory leak in uv_fs_readdir (Alex Crichton)
+
+* unix, windows: add uv_loop_alive() function (Sam Roberts)
+
+* windows: avoid assertion failure when pipe server is closed (Bert Belder)
+
+* osx: Fix a possible segfault in uv__io_poll (Alex Crichton)
+
+* stream: fix uv__stream_osx_select (Fedor Indutny)
+
+
+2013.12.14, Version 0.11.16 (Unstable), ae0ed8c49d0d313c935c22077511148b6e8408a4
+
+Changes since version 0.11.15:
+
+* fsevents: remove kFSEventStreamCreateFlagNoDefer polyfill (ci-innoq)
+
+* libuv: add more getaddrinfo errors (Steven Kabbes)
+
+* unix: fix accept() EMFILE error handling (Ben Noordhuis)
+
+* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis)
+
+* fsevents: fix subfolder check (Fedor Indutny)
+
+* fsevents: fix invalid memory access (huxingyi)
+
+* windows/timer: fix uv_hrtime discontinuity (Bert Belder)
+
+* unix: fix various memory leaks and undef behavior (Fedor Indutny)
+
+* unix, windows: always update loop time (Saúl Ibarra Corretgé)
+
+* windows: translate system errors in uv_spawn (Alexis Campailla)
+
+* windows: uv_spawn code refactor (Alexis Campailla)
+
+* unix, windows: detect errors in uv_ip4/6_addr (Yorkie)
+
+* stream: introduce uv_try_write(...) (Fedor Indutny)
+
+
+2013.12.13, Version 0.10.20 (Stable), 04141464dd0fba90ace9aa6f7003ce139b888a40
+
+Changes since version 0.10.19:
+
+* linux: fix up SO_REUSEPORT back-port (Ben Noordhuis)
+
+* fs-event: fix invalid memory access (huxingyi)
+
+
+2013.11.21, Version 0.11.15 (Unstable), bfe645ed7e99ca5670d9279ad472b604c129d2e5
+
+Changes since version 0.11.14:
+
+* fsevents: report errors to user (Fedor Indutny)
+
+* include: UV_FS_EVENT_RECURSIVE is a flag (Fedor Indutny)
+
+* linux: use CLOCK_MONOTONIC_COARSE if available (Ben Noordhuis)
+
+* build: make systemtap probes work with gyp build (Ben Noordhuis)
+
+* unix: update events from pevents between polls (Fedor Indutny)
+
+* fsevents: support japaneese characters in path (Chris Bank)
+
+* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
+
+* queue: strengthen type checks (Ben Noordhuis)
+
+* include: remove uv_strlcat() and uv_strlcpy() (Ben Noordhuis)
+
+* build: fix windows smp build with gyp (Geert Jansen)
+
+* unix: return exec errors from uv_spawn, not async (Alex Crichton)
+
+* fsevents: use native character encoding file paths (Ben Noordhuis)
+
+* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
+
+* windows: use _snwprintf(), not swprintf() (Ben Noordhuis)
+
+* fsevents: use FlagNoDefer for FSEventStreamCreate (Fedor Indutny)
+
+* unix: fix reopened fd bug (Fedor Indutny)
+
+* core: fix fake watcher list and count preservation (Fedor Indutny)
+
+* unix: set close-on-exec flag on received fds (Ben Noordhuis)
+
+* netbsd, openbsd: enable futimes() wrapper (Ben Noordhuis)
+
+* unix: nicer error message when kqueue() fails (Ben Noordhuis)
+
+* samples: add socks5 proxy sample application (Ben Noordhuis)
+
+
+2013.11.13, Version 0.10.19 (Stable), 33959f7524090b8d2c6c41e2400ca77e31755059
+
+Changes since version 0.10.18:
+
+* darwin: avoid calling GetCurrentProcess (Fedor Indutny)
+
+* unix: update events from pevents between polls (Fedor Indutny)
+
+* fsevents: support japaneese characters in path (Chris Bank)
+
+* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
+
+* build: fix windows smp build with gyp (Geert Jansen)
+
+* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
+
+* unix: fix reopened fd bug (Fedor Indutny)
+
+* core: fix fake watcher list and count preservation (Fedor Indutny)
+
+
+2013.10.30, Version 0.11.14 (Unstable), d7a6482f45c1b4eb4a853dbe1a9ce8090a35633a
+
+Changes since version 0.11.13:
+
+* darwin: create fsevents thread on demand (Ben Noordhuis)
+
+* fsevents: FSEvents is most likely not thread-safe (Fedor Indutny)
+
+* fsevents: use shared FSEventStream (Fedor Indutny)
+
+* windows: make uv_fs_chmod() report errors correctly (Bert Belder)
+
+* windows: make uv_shutdown() for write-only pipes work (Bert Belder)
+
+* windows/fs: wrap multi-statement macros in do..while block (Bert Belder)
+
+* windows/fs: make uv_fs_open() report EINVAL correctly (Bert Belder)
+
+* windows/fs: handle _open_osfhandle() failure correctly (Bert Belder)
+
+* windows/fs: wrap multi-statement macros in do..while block (Bert Belder)
+
+* windows/fs: make uv_fs_open() report EINVAL correctly (Bert Belder)
+
+* windows/fs: handle _open_osfhandle() failure correctly (Bert Belder)
+
+* build: clarify instructions for Windows (Brian Kaisner)
+
+* build: remove GCC_WARN_ABOUT_MISSING_NEWLINE (Ben Noordhuis)
+
+* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis)
+
+* windows: run close callbacks after polling for i/o (Saúl Ibarra Corretgé)
+
+* include: clarify uv_tcp_bind() behavior (Ben Noordhuis)
+
+* include: clean up includes in uv.h (Ben Noordhuis)
+
+* include: remove UV_IO_PRIVATE_FIELDS macro (Ben Noordhuis)
+
+* include: fix typo in comment in uv.h (Ben Noordhuis)
+
+* include: update uv_is_active() documentation (Ben Noordhuis)
+
+* include: make uv_process_options_t.cwd const (Ben Noordhuis)
+
+* unix: wrap long lines at 80 columns (Ben Noordhuis)
+
+* unix, windows: make uv_is_*() always return 0 or 1 (Ben Noordhuis)
+
+* bench: measure total/init/dispatch/cleanup times (Ben Noordhuis)
+
+* build: use -pthread on sunos (Timothy J. Fontaine)
+
+* windows: remove duplicate check in stream.c (Ben Noordhuis)
+
+* unix: sanity-check fds before closing (Ben Noordhuis)
+
+* unix: remove uv__pipe_accept() (Ben Noordhuis)
+
+* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis)
+
+* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis)
+
+* unix: revert recent FSEvent changes (Ben Noordhuis)
+
+* fsevents: fix clever rescheduling (Fedor Indutny)
+
+* linux: ignore fractional time in uv_uptime() (Ben Noordhuis)
+
+* unix: fix SIGCHLD waitpid() race in process.c (Ben Noordhuis)
+
+* unix, windows: add uv_fs_event_start/stop functions (Saúl Ibarra Corretgé)
+
+* unix: fix non-synchronized access in signal.c (Ben Noordhuis)
+
+* unix: add atomic-ops.h (Ben Noordhuis)
+
+* unix: add spinlock.h (Ben Noordhuis)
+
+* unix: clean up uv_tty_set_mode() a little (Ben Noordhuis)
+
+* unix: make uv_tty_reset_mode() async signal-safe (Ben Noordhuis)
+
+* include: add E2BIG status code mapping (Ben Noordhuis)
+
+* windows: fix duplicate case build error (Ben Noordhuis)
+
+* windows: remove unneeded check (Saúl Ibarra Corretgé)
+
+* include: document pipe path truncation behavior (Ben Noordhuis)
+
+* fsevents: increase stack size for OSX 10.9 (Fedor Indutny)
+
+* windows: _snprintf expected wrong parameter type in string (Maks Naumov)
+
+* windows: "else" keyword is missing (Maks Naumov)
+
+* windows: incorrect check for SOCKET_ERROR (Maks Naumov)
+
+* windows: add stdlib.h to satisfy reference to abort (Sean Farrell)
+
+* build: fix check target for mingw (Sean Farrell)
+
+* unix: move uv_shutdown() assertion (Keno Fischer)
+
+* darwin: avoid calling GetCurrentProcess (Fedor Indutny)
+
+
+2013.10.19, Version 0.10.18 (Stable), 9ec52963b585e822e87bdc5de28d6143aff0d2e5
+
+Changes since version 0.10.17:
+
+* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis)
+
+* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis)
+
+* unix: revert recent FSEvent changes (Ben Noordhuis)
+
+* unix: fix non-synchronized access in signal.c (Ben Noordhuis)
+
+
+2013.09.25, Version 0.10.17 (Stable), 9670e0a93540c2f0d86c84a375f2303383c11e7e
+
+Changes since version 0.10.16:
+
+* build: remove GCC_WARN_ABOUT_MISSING_NEWLINE (Ben Noordhuis)
+
+* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis)
+
+
+2013.09.06, Version 0.10.16 (Stable), 2bce230d81f4853a23662cbeb26fe98010b1084b
+
+Changes since version 0.10.15:
+
+* windows: make uv_shutdown() for write-only pipes work (Bert Belder)
+
+* windows: make uv_fs_open() report EINVAL when invalid arguments are passed
+ (Bert Belder)
+
+* windows: make uv_fs_open() report _open_osfhandle() failure correctly (Bert
+ Belder)
+
+* windows: make uv_fs_chmod() report errors correctly (Bert Belder)
+
+* windows: wrap multi-statement macros in do..while block (Bert Belder)
+
+
+2013.09.05, Version 0.11.13 (Unstable), f5b6db6c1d7f93d28281207fd47c3841c9a9792e
+
+Changes since version 0.11.12:
+
+* unix: define _GNU_SOURCE, exposes glibc-isms (Ben Noordhuis)
+
+* windows: check for nonconforming swprintf arguments (Brent Cook)
+
+* build: include internal headers in source list (Brent Cook)
+
+* include: merge uv_tcp_bind and uv_tcp_bind6 (Ben Noordhuis)
+
+* include: merge uv_tcp_connect and uv_tcp_connect6 (Ben Noordhuis)
+
+* include: merge uv_udp_bind and uv_udp_bind6 (Ben Noordhuis)
+
+* include: merge uv_udp_send and uv_udp_send6 (Ben Noordhuis)
+
+
+2013.09.03, Version 0.11.12 (Unstable), 82d01d5f6780d178f5176a01425ec297583c0811
+
+Changes since version 0.11.11:
+
+* test: fix epoll_wait() usage in test-embed.c (Ben Noordhuis)
+
+* include: uv_alloc_cb now takes uv_buf_t* (Ben Noordhuis)
+
+* include: uv_read{2}_cb now takes const uv_buf_t* (Ben Noordhuis)
+
+* include: uv_ip[46]_addr now takes sockaddr_in* (Ben Noordhuis)
+
+* include: uv_tcp_bind{6} now takes sockaddr_in* (Ben Noordhuis)
+
+* include: uv_tcp_connect{6} now takes sockaddr_in* (Ben Noordhuis)
+
+* include: uv_udp_recv_cb now takes const uv_buf_t* (Ben Noordhuis)
+
+* include: uv_udp_bind{6} now takes sockaddr_in* (Ben Noordhuis)
+
+* include: uv_udp_send{6} now takes sockaddr_in* (Ben Noordhuis)
+
+* include: uv_spawn takes const uv_process_options_t* (Ben Noordhuis)
+
+* include: make uv_write{2} const correct (Ben Noordhuis)
+
+* windows: fix flags assignment in uv_fs_readdir() (Ben Noordhuis)
+
+* windows: fix stray comments (Ben Noordhuis)
+
+* windows: remove unused is_path_dir() function (Ben Noordhuis)
+
+
+2013.08.30, Version 0.11.11 (Unstable), ba876d53539ed0427c52039012419cd9374c6f0d
+
+Changes since version 0.11.10:
+
+* unix, windows: add thread-local storage API (Ben Noordhuis)
+
+* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
+
+* darwin: fix 10.6 build error in fsevents.c (Ben Noordhuis)
+
+* windows: make uv_shutdown() for write-only pipes work (Bert Belder)
+
+* include: update uv_udp_open() / uv_udp_bind() docs (Ben Noordhuis)
+
+* unix: req queue must be empty when destroying loop (Ben Noordhuis)
+
+* unix: move loop functions from core.c to loop.c (Ben Noordhuis)
+
+* darwin: remove CoreFoundation dependency (Ben Noordhuis)
+
+* windows: make autotools build system work with mingw (Keno Fischer)
+
+* windows: fix mingw build (Alex Crichton)
+
+* windows: tweak Makefile.mingw for easier usage (Alex Crichton)
+
+* build: remove _GNU_SOURCE macro definition (Ben Noordhuis)
+
+
+2013.08.25, Version 0.11.10 (Unstable), 742dadcb7154cc7bb89c0c228a223b767a36cf0d
+
+* windows: Re-implement uv_fs_stat. The st_ctime field now contains the change
+ time, not the creation time, like on unix systems. st_dev, st_ino, st_blocks
+ and st_blksize are now also filled out. (Bert Belder)
+
+* linux: fix setsockopt(SO_REUSEPORT) error handling (Ben Noordhuis)
+
+* windows: report uv_process_t exit code correctly (Bert Belder)
+
+* windows: make uv_fs_chmod() report errors correctly (Bert Belder)
+
+* windows: make some more NT apis available for libuv's internal use (Bert
+ Belder)
+
+* windows: squelch some compiler warnings (Bert Belder)
+
+
+2013.08.24, Version 0.11.9 (Unstable), a2d29b5b068cbac93dc16138fb30a74e2669daad
+
+Changes since version 0.11.8:
+
+* fsevents: share FSEventStream between multiple FS watchers, which removes a
+ limit on the maximum number of file watchers that can be created on OS X.
+ (Fedor Indutny)
+
+* process: the `exit_status` parameter for a uv_process_t's exit callback now
+ is an int64_t, and no longer an int. (Bert Belder)
+
+* process: make uv_spawn() return some types of errors immediately on windows,
+ instead of passing the error code the the exit callback. This brings it on
+ par with libuv's behavior on unix. (Bert Belder)
+
+
+2013.08.24, Version 0.10.15 (Stable), 221078a8fdd9b853c6b557b3d9a5dd744b4fdd6b
+
+Changes since version 0.10.14:
+
+* fsevents: create FSEvents thread on demand (Ben Noordhuis)
+
+* fsevents: use a single thread for interacting with FSEvents, because it's not
+ thread-safe. (Fedor Indutny)
+
+* fsevents: share FSEventStream between multiple FS watchers, which removes a
+ limit on the maximum number of file watchers that can be created on OS X.
+ (Fedor Indutny)
+
+
+2013.08.22, Version 0.11.8 (Unstable), a5260462db80ab0deab6b9e6a8991dd8f5a9a2f8
+
+Changes since version 0.11.7:
+
+* unix: fix missing return value warning in stream.c (Ben Noordhuis)
+
+* build: serial-tests was added in automake v1.12 (Ben Noordhuis)
+
+* windows: fix uninitialized local variable warning (Ben Noordhuis)
+
+* windows: fix missing return value warning (Ben Noordhuis)
+
+* build: fix string comparisons in autogen.sh (Ben Noordhuis)
+
+* windows: move INLINE macro, remove UNUSED (Ben Noordhuis)
+
+* unix: clean up __attribute__((quux)) usage (Ben Noordhuis)
+
+* sunos: remove futimes() macro (Ben Noordhuis)
+
+* unix: fix uv__signal_unlock() prototype (Ben Noordhuis)
+
+* unix, windows: allow NULL async callback (Ben Noordhuis)
+
+* build: apply dtrace -G to all object files (Timothy J. Fontaine)
+
+* darwin: fix indentation in uv__hrtime() (Ben Noordhuis)
+
+* darwin: create fsevents thread on demand (Ben Noordhuis)
+
+* darwin: reduce fsevents thread stack size (Ben Noordhuis)
+
+* darwin: call pthread_setname_np() if available (Ben Noordhuis)
+
+* build: fix automake serial-tests check again (Ben Noordhuis)
+
+* unix: retry waitpid() on EINTR (Ben Noordhuis)
+
+* darwin: fix ios build error (Ben Noordhuis)
+
+* darwin: fix ios compiler warning (Ben Noordhuis)
+
+* test: simplify test-ip6-addr.c (Ben Noordhuis)
+
+* unix, windows: fix ipv6 link-local address parsing (Ben Noordhuis)
+
+* fsevents: FSEvents is most likely not thread-safe (Fedor Indutny)
+
+* windows: omit stdint.h, fix msvc 2008 build error (Ben Noordhuis)
+
+
+2013.08.22, Version 0.10.14 (Stable), 15d64132151c18b26346afa892444b95e2addad0
+
+Changes since version 0.10.13:
+
+* unix: retry waitpid() on EINTR (Ben Noordhuis)
+
+
+2013.08.07, Version 0.11.7 (Unstable), 3cad361f8776f70941b39d65bd9426bcb1aa817b
+
+Changes since version 0.11.6:
+
+* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis)
+
+* unix, windows: remove unused variables (Brian White)
+
+* test: fix signed/unsigned comparison warnings (Ben Noordhuis)
+
+* build: dtrace shouldn't break out of tree builds (Timothy J. Fontaine)
+
+* unix, windows: don't read/recv if buf.len==0 (Ben Noordhuis)
+
+* build: add mingw makefile (Ben Noordhuis)
+
+* unix, windows: add MAC to uv_interface_addresses() (Brian White)
+
+* build: enable AM_INIT_AUTOMAKE([subdir-objects]) (Ben Noordhuis)
+
+* unix, windows: make buf arg to uv_fs_write const (Ben Noordhuis)
+
+* sunos: fix build breakage introduced in e3a657c (Ben Noordhuis)
+
+* aix: fix build breakage introduced in 3ee4d3f (Ben Noordhuis)
+
+* windows: fix mingw32 build, define JOB_OBJECT_XXX (Yasuhiro Matsumoto)
+
+* windows: fix mingw32 build, include limits.h (Yasuhiro Matsumoto)
+
+* test: replace sprintf() with snprintf() (Ben Noordhuis)
+
+* test: replace strcpy() with strncpy() (Ben Noordhuis)
+
+* openbsd: fix uv_ip6_addr() unused variable warnings (Ben Noordhuis)
+
+* openbsd: fix dlerror() const correctness warning (Ben Noordhuis)
+
+* openbsd: fix uv_fs_sendfile() unused variable warnings (Ben Noordhuis)
+
+* build: disable parallel automake tests (Ben Noordhuis)
+
+* test: add windows-only snprintf() function (Ben Noordhuis)
+
+* build: add automake serial-tests version check (Ben Noordhuis)
+
+
+2013.07.26, Version 0.10.13 (Stable), 381312e1fe6fecbabc943ccd56f0e7d114b3d064
+
+Changes since version 0.10.12:
+
+* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis)
+
+
+2013.07.21, Version 0.11.6 (Unstable), 6645b93273e0553d23823c576573b82b129bf28c
+
+Changes since version 0.11.5:
+
+* test: open stdout fd in write-only mode (Ben Noordhuis)
+
+* windows: uv_spawn shouldn't reject reparse points (Bert Belder)
+
+* windows: use WSAGetLastError(), not errno (Ben Noordhuis)
+
+* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis)
+
+* test: fix signed/unsigned compiler warning (Ben Noordhuis)
+
+* test: add 'start timer from check handle' test (Ben Noordhuis)
+
+* build: `all` now builds static and dynamic lib (Ben Noordhuis)
+
+* unix, windows: add extra fields to uv_stat_t (Saúl Ibarra Corretgé)
+
+* build: add install target to the makefile (Navaneeth Kedaram Nambiathan)
+
+* build: switch to autotools (Ben Noordhuis)
+
+* build: use AM_PROG_AR conditionally (Ben Noordhuis)
+
+* test: fix fs_fstat test on sunos (Ben Noordhuis)
+
+* test: fix fs_chown when running as root (Ben Noordhuis)
+
+* test: fix spawn_setgid_fails and spawn_setuid_fails (Ben Noordhuis)
+
+* build: use AM_SILENT_RULES conditionally (Ben Noordhuis)
+
+* build: add DTrace detection for autotools (Timothy J. Fontaine)
+
+* linux,darwin,win: link-local IPv6 addresses (Miroslav Bajtoš)
+
+* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis)
+
+* unix, windows: return error codes directly (Ben Noordhuis)
+
+
+2013.07.10, Version 0.10.12 (Stable), 58a46221bba726746887a661a9f36fe9ff204209
+
+Changes since version 0.10.11:
+
+* linux: add support for MIPS (Andrei Sedoi)
+
+* windows: uv_spawn shouldn't reject reparse points (Bert Belder)
+
+* windows: use WSAGetLastError(), not errno (Ben Noordhuis)
+
+* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis)
+
+* build: `all` now builds static and dynamic lib (Ben Noordhuis)
+
+* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis)
+
+
+2013.06.27, Version 0.11.5 (Unstable), e3c63ff1627a14e96f54c1c62b0d68b446d8425b
+
+Changes since version 0.11.4:
+
+* build: remove CSTDFLAG, use only CFLAGS (Ben Noordhuis)
+
+* unix: support for android builds (Linus Mårtensson)
+
+* unix: avoid extra read, short-circuit on POLLHUP (Ben Noordhuis)
+
+* uv: support android libuv standalone build (Linus Mårtensson)
+
+* src: make queue.h c++ compatible (Ben Noordhuis)
+
+* unix: s/ngx-queue.h/queue.h/ in checksparse.sh (Ben Noordhuis)
+
+* unix: unconditionally stop handle on close (Ben Noordhuis)
+
+* freebsd: don't enable dtrace if it's not available (Brian White)
+
+* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine)
+
+* unix: remove overzealous assert (Ben Noordhuis)
+
+* unix: remove unused function uv_fatal_error() (Ben Noordhuis)
+
+* unix, windows: clean up uv_thread_create() (Ben Noordhuis)
+
+* queue: fix pointer truncation on LLP64 platforms (Bert Belder)
+
+* build: set OS=="android" for android builds (Linus Mårtensson)
+
+* windows: don't use uppercase in include filename (Ben Noordhuis)
+
+* stream: add an API to make streams do blocking writes (Henry Rawas)
+
+* windows: use WSAGetLastError(), not errno (Ben Noordhuis)
+
+
+2013.06.13, Version 0.10.11 (Stable), c3b75406a66a10222a589cb173e8f469e9665c7e
+
+Changes since version 0.10.10:
+
+* unix: unconditionally stop handle on close (Ben Noordhuis)
+
+* freebsd: don't enable dtrace if it's not available (Brian White)
+
+* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine)
+
+* unix: remove overzealous assert (Ben Noordhuis)
+
+* unix: clear UV_STREAM_SHUTTING after shutdown() (Ben Noordhuis)
+
+* unix: fix busy loop, write if POLLERR or POLLHUP (Ben Noordhuis)
+
+
+2013.06.05, Version 0.10.10 (Stable), 0d95a88bd35fce93863c57a460be613aea34d2c5
+
+Changes since version 0.10.9:
+
+* include: document uv_update_time() and uv_now() (Ben Noordhuis)
+
+* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis)
+
+* linux: fix a memory leak in uv_cpu_info() error path (Ben Noordhuis)
+
+* linux: don't ignore out-of-memory errors in uv_cpu_info() (Ben Noordhuis)
+
+* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis)
+
+* test: fix a compilation problem in test-osx-select.c that was caused by the
+ use of c-style comments (Bert Belder)
+
+* darwin: use uv_fs_sendfile() use the sendfile api correctly (Wynn Wilkes)
+
+
+2013.05.30, Version 0.11.4 (Unstable), e43e5b3d954a0989db5588aa110e1fe4fe6e0219
+
+Changes since version 0.11.3:
+
+* windows: make uv_spawn not fail when the libuv embedding application is run
+ under external job control (Bert Belder)
+
+* darwin: assume CFRunLoopStop() isn't thread-safe, fixing a race condition
+ when stopping the 'stdin select hack' thread (Fedor Indutny)
+
+* win: fix UV_EALREADY not being reported correctly to the libuv user in some
+ cases (Bert Belder)
+
+* darwin: make the uv__cf_loop_runner and uv__cf_loop_cb functions static (Ben
+ Noordhuis)
+
+* darwin: task_info() cannot fail (Ben Noordhuis)
+
+* unix: add error mapping for ENETDOWN (Ben Noordhuis)
+
+* unix: implicitly signal write errors to the libuv user (Ben Noordhuis)
+
+* unix: fix assertion error on signal pipe overflow (Bert Belder)
+
+* unix: turn off POLLOUT after stream connect (Ben Noordhuis)
+
+* unix: fix stream refcounting buglet (Ben Noordhuis)
+
+* unix: remove assert statements that are no longer correct (Ben Noordhuis)
+
+* unix: appease warning about non-standard `inline` (Sean Silva)
+
+* unix: add uv__is_closing() macro (Ben Noordhuis)
+
+* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis)
+
+* include: document uv_update_time() and uv_now() (Ben Noordhuis)
+
+* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis)
+
+* linux: fix a memory leak in uv_cpu_info() error path (Ben Noordhuis)
+
+* linux: don't ignore out-of-memory errors in uv_cpu_info() (Ben Noordhuis)
+
+* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis)
+
+* test: fix a compilation problem in test-osx-select.c that was caused by the
+ use of c-style comments (Bert Belder)
+
+* darwin: use uv_fs_sendfile() use the sendfile api correctly (Wynn Wilkes)
+
+* windows: call idle handles on every loop iteration, something the unix
+ implementation already did (Bert Belder)
+
+* test: update the idle-starvation test to verify that idle handles are called
+ in every loop iteration (Bert Belder)
+
+* unix, windows: ensure that uv_run() in RUN_ONCE mode calls timers that expire
+ after blocking (Ben Noordhuis)
+
+
+2013.05.29, Version 0.10.9 (Stable), a195f9ace23d92345baf57582678bfc3017e6632
+
+Changes since version 0.10.8:
+
+* unix: fix stream refcounting buglet (Ben Noordhuis)
+
+* unix: remove erroneous asserts (Ben Noordhuis)
+
+* unix: add uv__is_closing() macro (Ben Noordhuis)
+
+* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis)
+
+
+2013.05.25, Version 0.10.8 (Stable), 0f39be12926fe2d8766a9f025797a473003e6504
+
+Changes since version 0.10.7:
+
+* windows: make uv_spawn not fail under job control (Bert Belder)
+
+* darwin: assume CFRunLoopStop() isn't thread-safe (Fedor Indutny)
+
+* win: fix UV_EALREADY incorrectly set (Bert Belder)
+
+* darwin: make two uv__cf_*() functions static (Ben Noordhuis)
+
+* darwin: task_info() cannot fail (Ben Noordhuis)
+
+* unix: add mapping for ENETDOWN (Ben Noordhuis)
+
+* unix: implicitly signal write errors to libuv user (Ben Noordhuis)
+
+* unix: fix assert on signal pipe overflow (Bert Belder)
+
+* unix: turn off POLLOUT after stream connect (Ben Noordhuis)
+
+
+2013.05.16, Version 0.11.3 (Unstable), 0a48c05b5988aea84c605751900926fa25443b34
+
+Changes since version 0.11.2:
+
+* unix: clean up uv_accept() (Ben Noordhuis)
+
+* unix: remove errno preserving code (Ben Noordhuis)
+
+* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis)
+
+* windows: kill child processes when the parent dies (Bert Belder)
+
+* build: set soname in shared library (Ben Noordhuis)
+
+* build: make `make test` link against .a again (Ben Noordhuis)
+
+* build: only set soname on shared object builds (Timothy J. Fontaine)
+
+* build: convert predefined $PLATFORM to lower case (Elliot Saba)
+
+* test: fix process_title failing on linux (Miroslav Bajtoš)
+
+* test, sunos: disable process_title test (Miroslav Bajtoš)
+
+* test: add error logging to tty unit test (Miroslav Bajtoš)
+
+
+2013.05.15, Version 0.10.7 (Stable), 028baaf0846b686a81e992cb2f2f5a9b8e841fcf
+
+Changes since version 0.10.6:
+
+* windows: kill child processes when the parent dies (Bert Belder)
+
+
+2013.05.15, Version 0.10.6 (Stable), 11e6613e6260d95c8cf11bf89a2759c24649319a
+
+Changes since version 0.10.5:
+
+* stream: fix osx select hack (Fedor Indutny)
+
+* stream: fix small nit in select hack, add test (Fedor Indutny)
+
+* build: link with libkvm on openbsd (Ben Noordhuis)
+
+* stream: use harder sync restrictions for osx-hack (Fedor Indutny)
+
+* unix: fix EMFILE error handling (Ben Noordhuis)
+
+* darwin: fix unnecessary include headers (Daisuke Murase)
+
+* darwin: rename darwin-getproctitle.m (Ben Noordhuis)
+
+* build: convert predefined $PLATFORM to lower case (Elliot Saba)
+
+* build: set soname in shared library (Ben Noordhuis)
+
+* build: make `make test` link against .a again (Ben Noordhuis)
+
+* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis)
+
+* build: only set soname on shared object builds (Timothy J. Fontaine)
+
+
+2013.05.11, Version 0.11.2 (Unstable), 3fba0bf65f091b91a9760530c05c6339c658d88b
+
+Changes since version 0.11.1:
+
+* darwin: look up file path with F_GETPATH (Ben Noordhuis)
+
+* unix, windows: add uv_has_ref() function (Saúl Ibarra Corretgé)
+
+* build: avoid double / in paths for dtrace (Timothy J. Fontaine)
+
+* unix: remove src/unix/cygwin.c (Ben Noordhuis)
+
+* windows: deal with the fact that GetTickCount might lag (Bert Belder)
+
+* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis)
+
+* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis)
+
+
+2013.04.24, Version 0.10.5 (Stable), 6595a7732c52eb4f8e57c88655f72997a8567a67
+
+Changes since version 0.10.4:
+
+* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis)
+
+* windows: make timers handle large timeouts (Miroslav Bajtoš)
+
+* windows: remove superfluous assert statement (Bert Belder)
+
+* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis)
+
+* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis)
+
+
+2013.04.12, Version 0.10.4 (Stable), 85827e26403ac6dfa331af8ec9916ea7e27bd833
+
+Changes since version 0.10.3:
+
+* include: update uv_backend_fd() documentation (Ben Noordhuis)
+
+* unix: include uv.h in src/version.c (Ben Noordhuis)
+
+* unix: don't write more than IOV_MAX iovecs (Fedor Indutny)
+
+* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier)
+
+* build: gyp disable thin archives (Timothy J. Fontaine)
+
+* sunos: re-export entire library when static (Timothy J. Fontaine)
+
+* unix: dtrace probes for tick-start and tick-stop (Timothy J. Fontaine)
+
+* windows: fix memory leak in fs__sendfile (Shannen Saez)
+
+* windows: remove double initialization in uv_tty_init (Shannen Saez)
+
+* build: fix dtrace-enabled out of tree build (Ben Noordhuis)
+
+* build: squelch -Wdollar-in-identifier-extension warnings (Ben Noordhuis)
+
+* inet: snprintf returns int, not size_t (Brian White)
+
+* win: refactor uv_cpu_info (Bert Belder)
+
+* build: add support for Visual Studio 2012 (Nicholas Vavilov)
+
+* build: -Wno-dollar-in-identifier-extension is clang only (Ben Noordhuis)
+
+
+2013.04.11, Version 0.11.1 (Unstable), 5c10e82ae0bc99eff86d4b9baff1f1aa0bf84c0a
+
+This is the first versioned release from the current unstable libuv branch.
+
+Changes since Node.js v0.11.0:
+
+* all platforms: nanosecond resolution support for uv_fs_[fl]stat (Timothy J.
+ Fontaine)
+
+* all platforms: add netmask to uv_interface_address (Ben Kelly)
+
+* unix: make sure the `status` parameter passed to the `uv_getaddrinfo` is 0 or
+ -1 (Ben Noordhuis)
+
+* unix: limit the number of iovecs written in a single `writev` syscall to
+ IOV_MAX (Fedor Indutny)
+
+* unix: add dtrace probes for tick-start and tick-stop (Timothy J. Fontaine)
+
+* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier)
+
+* windows: fix memory leak in fs__sendfile (Shannen Saez)
+
+* windows: fix edge case bugs in uv_cpu_info (Bert Belder)
+
+* include: no longer ship with / include ngx-queue.h (Ben Noordhuis)
+
+* include: remove UV_VERSION_* macros from uv.h (Ben Noordhuis)
+
+* documentation updates (Kristian Evensen, Ben Kelly, Ben Noordhuis)
+
+* build: fix dtrace-enabled builds (Ben Noordhuis, Timothy J. Fontaine)
+
+* build: gyp disable thin archives (Timothy J. Fontaine)
+
+* build: add support for Visual Studio 2012 (Nicholas Vavilov)
+
+
+2013.03.28, Version 0.10.3 (Stable), 31ebe23973dd98fd8a24c042b606f37a794e99d0
+
+Changes since version 0.10.2:
+
+* include: remove extraneous const from uv_version() (Ben Noordhuis)
+
+* doc: update README, replace `OS` by `PLATFORM` (Ben Noordhuis)
+
+* build: simplify .buildstamp rule (Ben Noordhuis)
+
+* build: disable -Wstrict-aliasing on darwin (Ben Noordhuis)
+
+* darwin: don't select(&exceptfds) in fallback path (Ben Noordhuis)
+
+* unix: don't clear flags after closing UDP handle (Saúl Ibarra Corretgé)
+
+
+2013.03.25, Version 0.10.2 (Stable), 0f36a00568f3e7608f97f6c6cdb081f4800a50c9
+
+This is the first officially versioned release of libuv. Starting now
+libuv will make releases independently of Node.js.
+
+Changes since Node.js v0.10.0:
+
+* test: add tap output for windows (Timothy J. Fontaine)
+
+* unix: fix uv_tcp_simultaneous_accepts() logic (Ben Noordhuis)
+
+* include: bump UV_VERSION_MINOR (Ben Noordhuis)
+
+* unix: improve uv_guess_handle() implementation (Ben Noordhuis)
+
+* stream: run try_select only for pipes and ttys (Fedor Indutny)
+
+Changes since Node.js v0.10.1:
+
+* build: rename OS to PLATFORM (Ben Noordhuis)
+
+* unix: make uv_timer_init() initialize repeat (Brian Mazza)
+
+* unix: make timers handle large timeouts (Ben Noordhuis)
+
+* build: add OBJC makefile var (Ben Noordhuis)
+
+* Add `uv_version()` and `uv_version_string()` APIs (Bert Belder)
diff --git a/3rdparty/libuv/LICENSE b/3rdparty/libuv/LICENSE
new file mode 100644
index 00000000000..4d411670e3f
--- /dev/null
+++ b/3rdparty/libuv/LICENSE
@@ -0,0 +1,46 @@
+libuv is part of the Node project: http://nodejs.org/
+libuv may be distributed alone under Node's license:
+
+====
+
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+====
+
+This license applies to all parts of libuv that are not externally
+maintained libraries.
+
+The externally maintained libraries used by libuv are:
+
+ - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.
+
+ - inet_pton and inet_ntop implementations, contained in src/inet.c, are
+ copyright the Internet Systems Consortium, Inc., and licensed under the ISC
+ license.
+
+ - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
+ clause BSD license.
+
+ - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
+ Communications AB. Three clause BSD license.
+
+ - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
+ Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
+ n° 289016). Three clause BSD license.
diff --git a/3rdparty/libuv/MAINTAINERS.md b/3rdparty/libuv/MAINTAINERS.md
new file mode 100644
index 00000000000..4db2f5130c0
--- /dev/null
+++ b/3rdparty/libuv/MAINTAINERS.md
@@ -0,0 +1,36 @@
+
+# Project Maintainers
+
+libuv is currently managed by the following individuals:
+
+* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
+ - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
+* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
+* **Fedor Indutny** ([@indutny](https://github.com/indutny))
+ - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
+* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
+ - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul)
+
+## Storing a maintainer key in Git
+
+It's quite handy to store a maintainer's signature as a git blob, and have
+that object tagged and signed with such key.
+
+Export your public key:
+
+ $ gpg --armor --export saghul@gmail.com > saghul.asc
+
+Store it as a blob on the repo:
+
+ $ git hash-object -w saghul.asc
+
+The previous command returns a hash, copy it. For the sake of this explanation,
+we'll assume it's 'abcd1234'. Storing the blob in git is not enough, it could
+be garbage collected since nothing references it, so we'll create a tag for it:
+
+ $ git tag -s pubkey-saghul abcd1234
+
+Commit the changes and push:
+
+ $ git push origin pubkey-saghul
+
diff --git a/3rdparty/libuv/Makefile.am b/3rdparty/libuv/Makefile.am
new file mode 100644
index 00000000000..0ef781ff198
--- /dev/null
+++ b/3rdparty/libuv/Makefile.am
@@ -0,0 +1,344 @@
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src
+
+include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h
+
+CLEANFILES =
+
+lib_LTLIBRARIES = libuv.la
+libuv_la_CFLAGS = @CFLAGS@
+libuv_la_LDFLAGS = -no-undefined -version-info 1:0:0
+libuv_la_SOURCES = src/fs-poll.c \
+ src/heap-inl.h \
+ src/inet.c \
+ src/queue.h \
+ src/threadpool.c \
+ src/uv-common.c \
+ src/uv-common.h \
+ src/version.c
+
+if SUNOS
+# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
+# on other platforms complain that the argument is unused during compilation.
+libuv_la_CFLAGS += -pthread
+endif
+
+if WINNT
+
+include_HEADERS += include/uv-win.h include/tree.h
+AM_CPPFLAGS += -I$(top_srcdir)/src/win \
+ -DWIN32_LEAN_AND_MEAN \
+ -D_WIN32_WINNT=0x0600
+LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv
+libuv_la_SOURCES += src/win/async.c \
+ src/win/atomicops-inl.h \
+ src/win/core.c \
+ src/win/dl.c \
+ src/win/error.c \
+ src/win/fs-event.c \
+ src/win/fs.c \
+ src/win/getaddrinfo.c \
+ src/win/getnameinfo.c \
+ src/win/handle.c \
+ src/win/handle-inl.h \
+ src/win/internal.h \
+ src/win/loop-watcher.c \
+ src/win/pipe.c \
+ src/win/poll.c \
+ src/win/process-stdio.c \
+ src/win/process.c \
+ src/win/req.c \
+ src/win/req-inl.h \
+ src/win/signal.c \
+ src/win/stream.c \
+ src/win/stream-inl.h \
+ src/win/tcp.c \
+ src/win/thread.c \
+ src/win/timer.c \
+ src/win/tty.c \
+ src/win/udp.c \
+ src/win/util.c \
+ src/win/winapi.c \
+ src/win/winapi.h \
+ src/win/winsock.c \
+ src/win/winsock.h
+
+else # WINNT
+
+include_HEADERS += include/uv-unix.h
+AM_CPPFLAGS += -I$(top_srcdir)/src/unix
+libuv_la_SOURCES += src/unix/async.c \
+ src/unix/atomic-ops.h \
+ src/unix/core.c \
+ src/unix/dl.c \
+ src/unix/fs.c \
+ src/unix/getaddrinfo.c \
+ src/unix/getnameinfo.c \
+ src/unix/internal.h \
+ src/unix/loop-watcher.c \
+ src/unix/loop.c \
+ src/unix/pipe.c \
+ src/unix/poll.c \
+ src/unix/process.c \
+ src/unix/signal.c \
+ src/unix/spinlock.h \
+ src/unix/stream.c \
+ src/unix/tcp.c \
+ src/unix/thread.c \
+ src/unix/timer.c \
+ src/unix/tty.c \
+ src/unix/udp.c
+
+endif # WINNT
+
+EXTRA_DIST = test/fixtures/empty_file \
+ test/fixtures/load_error.node \
+ include \
+ test \
+ docs \
+ img \
+ samples \
+ android-configure \
+ CONTRIBUTING.md \
+ LICENSE \
+ README.md \
+ checksparse.sh \
+ vcbuild.bat \
+ Makefile.mingw \
+ common.gypi \
+ gyp_uv.py \
+ uv.gyp
+
+
+
+TESTS = test/run-tests
+check_PROGRAMS = test/run-tests
+test_run_tests_CFLAGS =
+test_run_tests_SOURCES = test/blackhole-server.c \
+ test/dns-server.c \
+ test/echo-server.c \
+ test/run-tests.c \
+ test/runner.c \
+ test/runner.h \
+ test/task.h \
+ test/test-active.c \
+ test/test-async.c \
+ test/test-async-null-cb.c \
+ test/test-barrier.c \
+ test/test-callback-order.c \
+ test/test-callback-stack.c \
+ test/test-close-fd.c \
+ test/test-close-order.c \
+ test/test-condvar.c \
+ test/test-connection-fail.c \
+ test/test-cwd-and-chdir.c \
+ test/test-default-loop-close.c \
+ test/test-delayed-accept.c \
+ test/test-dlerror.c \
+ test/test-embed.c \
+ test/test-emfile.c \
+ test/test-error.c \
+ test/test-fail-always.c \
+ test/test-fs-event.c \
+ test/test-fs-poll.c \
+ test/test-fs.c \
+ test/test-get-currentexe.c \
+ test/test-get-loadavg.c \
+ test/test-get-memory.c \
+ test/test-getaddrinfo.c \
+ test/test-getnameinfo.c \
+ test/test-getsockname.c \
+ test/test-handle-fileno.c \
+ test/test-homedir.c \
+ test/test-hrtime.c \
+ test/test-idle.c \
+ test/test-ip4-addr.c \
+ test/test-ip6-addr.c \
+ test/test-ipc-send-recv.c \
+ test/test-ipc.c \
+ test/test-list.h \
+ test/test-loop-handles.c \
+ test/test-loop-alive.c \
+ test/test-loop-close.c \
+ test/test-loop-stop.c \
+ test/test-loop-time.c \
+ test/test-loop-configure.c \
+ test/test-multiple-listen.c \
+ test/test-mutexes.c \
+ test/test-osx-select.c \
+ test/test-pass-always.c \
+ test/test-ping-pong.c \
+ test/test-pipe-bind-error.c \
+ test/test-pipe-connect-error.c \
+ test/test-pipe-connect-multiple.c \
+ test/test-pipe-connect-prepare.c \
+ test/test-pipe-getsockname.c \
+ test/test-pipe-pending-instances.c \
+ test/test-pipe-sendmsg.c \
+ test/test-pipe-server-close.c \
+ test/test-pipe-close-stdout-read-stdin.c \
+ test/test-pipe-set-non-blocking.c \
+ test/test-platform-output.c \
+ test/test-poll-close.c \
+ test/test-poll-close-doesnt-corrupt-stack.c \
+ test/test-poll-closesocket.c \
+ test/test-poll.c \
+ test/test-process-title.c \
+ test/test-queue-foreach-delete.c \
+ test/test-ref.c \
+ test/test-run-nowait.c \
+ test/test-run-once.c \
+ test/test-semaphore.c \
+ test/test-shutdown-close.c \
+ test/test-shutdown-eof.c \
+ test/test-shutdown-twice.c \
+ test/test-signal-multiple-loops.c \
+ test/test-signal.c \
+ test/test-socket-buffer-size.c \
+ test/test-spawn.c \
+ test/test-stdio-over-pipes.c \
+ test/test-tcp-bind-error.c \
+ test/test-tcp-bind6-error.c \
+ test/test-tcp-close-accept.c \
+ test/test-tcp-close-while-connecting.c \
+ test/test-tcp-close.c \
+ test/test-tcp-create-socket-early.c \
+ test/test-tcp-connect-error-after-write.c \
+ test/test-tcp-connect-error.c \
+ test/test-tcp-connect-timeout.c \
+ test/test-tcp-connect6-error.c \
+ test/test-tcp-flags.c \
+ test/test-tcp-open.c \
+ test/test-tcp-read-stop.c \
+ test/test-tcp-shutdown-after-write.c \
+ test/test-tcp-unexpected-read.c \
+ test/test-tcp-oob.c \
+ test/test-tcp-write-to-half-open-connection.c \
+ test/test-tcp-write-after-connect.c \
+ test/test-tcp-writealot.c \
+ test/test-tcp-write-fail.c \
+ test/test-tcp-try-write.c \
+ test/test-tcp-write-queue-order.c \
+ test/test-thread-equal.c \
+ test/test-thread.c \
+ test/test-threadpool-cancel.c \
+ test/test-threadpool.c \
+ test/test-timer-again.c \
+ test/test-timer-from-check.c \
+ test/test-timer.c \
+ test/test-tty.c \
+ test/test-udp-bind.c \
+ test/test-udp-create-socket-early.c \
+ test/test-udp-dgram-too-big.c \
+ test/test-udp-ipv6.c \
+ test/test-udp-multicast-interface.c \
+ test/test-udp-multicast-interface6.c \
+ test/test-udp-multicast-join.c \
+ test/test-udp-multicast-join6.c \
+ test/test-udp-multicast-ttl.c \
+ test/test-udp-open.c \
+ test/test-udp-options.c \
+ test/test-udp-send-and-recv.c \
+ test/test-udp-send-immediate.c \
+ test/test-udp-send-unreachable.c \
+ test/test-udp-try-send.c \
+ test/test-walk-handles.c \
+ test/test-watcher-cross-stop.c
+test_run_tests_LDADD = libuv.la
+
+if WINNT
+test_run_tests_SOURCES += test/runner-win.c \
+ test/runner-win.h
+else
+test_run_tests_SOURCES += test/runner-unix.c \
+ test/runner-unix.h
+endif
+
+if AIX
+test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
+endif
+
+if SUNOS
+test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
+endif
+
+
+if AIX
+libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
+include_HEADERS += include/uv-aix.h
+libuv_la_SOURCES += src/unix/aix.c
+endif
+
+if ANDROID
+include_HEADERS += include/android-ifaddrs.h \
+ include/pthread-fixes.h
+libuv_la_SOURCES += src/unix/android-ifaddrs.c \
+ src/unix/pthread-fixes.c
+endif
+
+if DARWIN
+include_HEADERS += include/uv-darwin.h
+libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
+libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
+libuv_la_SOURCES += src/unix/darwin.c \
+ src/unix/darwin-proctitle.c \
+ src/unix/fsevents.c \
+ src/unix/kqueue.c \
+ src/unix/proctitle.c
+endif
+
+if DRAGONFLY
+include_HEADERS += include/uv-bsd.h
+endif
+
+if FREEBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
+endif
+
+if LINUX
+include_HEADERS += include/uv-linux.h
+libuv_la_CFLAGS += -D_GNU_SOURCE
+libuv_la_SOURCES += src/unix/linux-core.c \
+ src/unix/linux-inotify.c \
+ src/unix/linux-syscalls.c \
+ src/unix/linux-syscalls.h \
+ src/unix/proctitle.c
+endif
+
+if NETBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c
+endif
+
+if OPENBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c
+endif
+
+if SUNOS
+include_HEADERS += include/uv-sunos.h
+libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
+libuv_la_SOURCES += src/unix/sunos.c
+endif
+
+if HAVE_PKG_CONFIG
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = @PACKAGE_NAME@.pc
+endif
diff --git a/3rdparty/libuv/Makefile.mingw b/3rdparty/libuv/Makefile.mingw
new file mode 100644
index 00000000000..156f15dab15
--- /dev/null
+++ b/3rdparty/libuv/Makefile.mingw
@@ -0,0 +1,84 @@
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+CC ?= gcc
+
+CFLAGS += -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -Iinclude \
+ -Isrc \
+ -Isrc/win \
+ -DWIN32_LEAN_AND_MEAN \
+ -D_WIN32_WINNT=0x0600
+
+INCLUDES = include/stdint-msvc2008.h \
+ include/tree.h \
+ include/uv-errno.h \
+ include/uv-threadpool.h \
+ include/uv-version.h \
+ include/uv-win.h \
+ include/uv.h \
+ src/heap-inl.h \
+ src/queue.h \
+ src/uv-common.h \
+ src/win/atomicops-inl.h \
+ src/win/handle-inl.h \
+ src/win/internal.h \
+ src/win/req-inl.h \
+ src/win/stream-inl.h \
+ src/win/winapi.h \
+ src/win/winsock.h
+
+OBJS = src/fs-poll.o \
+ src/inet.o \
+ src/threadpool.o \
+ src/uv-common.o \
+ src/version.o \
+ src/win/async.o \
+ src/win/core.o \
+ src/win/dl.o \
+ src/win/error.o \
+ src/win/fs-event.o \
+ src/win/fs.o \
+ src/win/getaddrinfo.o \
+ src/win/getnameinfo.o \
+ src/win/handle.o \
+ src/win/loop-watcher.o \
+ src/win/pipe.o \
+ src/win/poll.o \
+ src/win/process-stdio.o \
+ src/win/process.o \
+ src/win/req.o \
+ src/win/signal.o \
+ src/win/stream.o \
+ src/win/tcp.o \
+ src/win/thread.o \
+ src/win/timer.o \
+ src/win/tty.o \
+ src/win/udp.o \
+ src/win/util.o \
+ src/win/winapi.o \
+ src/win/winsock.o
+
+all: libuv.a
+
+clean:
+ -$(RM) $(OBJS) libuv.a
+
+libuv.a: $(OBJS)
+ $(AR) crs $@ $^
+
+$(OBJS): %.o : %.c $(INCLUDES)
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/3rdparty/libuv/README.md b/3rdparty/libuv/README.md
new file mode 100644
index 00000000000..dfd24ba79d1
--- /dev/null
+++ b/3rdparty/libuv/README.md
@@ -0,0 +1,245 @@
+![libuv][libuv_banner]
+
+## Overview
+
+libuv is a multi-platform support library with a focus on asynchronous I/O. It
+was primarily developed for use by [Node.js](http://nodejs.org), but it's also
+used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/),
+[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/wiki/Projects-that-use-libuv).
+
+## Feature highlights
+
+ * Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
+
+ * Asynchronous TCP and UDP sockets
+
+ * Asynchronous DNS resolution
+
+ * Asynchronous file and file system operations
+
+ * File system events
+
+ * ANSI escape code controlled TTY
+
+ * IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
+
+ * Child processes
+
+ * Thread pool
+
+ * Signal handling
+
+ * High resolution clock
+
+ * Threading and synchronization primitives
+
+## Versioning
+
+Starting with version 1.0.0 libuv follows the [semantic versioning](http://semver.org/)
+scheme. The API change and backwards compatibility rules are those indicated by
+SemVer. libuv will keep a stable ABI across major releases.
+
+## Community
+
+ * [Mailing list](http://groups.google.com/group/libuv)
+ * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4)
+
+## Documentation
+
+### Official API documentation
+
+Located in the docs/ subdirectory. It uses the [Sphinx](http://sphinx-doc.org/)
+framework, which makes it possible to build the documentation in multiple
+formats.
+
+Show different supported building options:
+
+ $ make help
+
+Build documentation as HTML:
+
+ $ make html
+
+Build documentation as man pages:
+
+ $ make man
+
+Build documentation as ePub:
+
+ $ make epub
+
+NOTE: Windows users need to use make.bat instead of plain 'make'.
+
+Documentation can be browsed online [here](http://docs.libuv.org).
+
+The [tests and benchmarks](https://github.com/libuv/libuv/tree/master/test)
+also serve as API specification and usage examples.
+
+### Other resources
+
+ * [An Introduction to libuv](http://nikhilm.github.com/uvbook/)
+ &mdash; An overview of libuv with tutorials.
+ * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4)
+ &mdash; High-level introductory talk about libuv.
+ * [libuv-dox](https://github.com/thlorenz/libuv-dox)
+ &mdash; Documenting types and methods of libuv, mostly by reading uv.h.
+ * [learnuv](https://github.com/thlorenz/learnuv)
+ &mdash; Learn uv for fun and profit, a self guided workshop to libuv.
+
+These resources are not handled by libuv maintainers and might be out of
+date. Please verify it before opening new issues.
+
+## Downloading
+
+libuv can be downloaded either from the
+[GitHub repository](https://github.com/libuv/libuv)
+or from the [downloads site](http://dist.libuv.org/dist/).
+
+Starting with libuv 1.7.0, binaries for Windows are also provided. This is to
+be considered EXPERIMENTAL.
+
+Before verifying the git tags or signature files, importing the relevant keys
+is necessary. Key IDs are listed in the
+[MAINTAINERS](https://github.com/libuv/libuv/blob/master/MAINTAINERS.md)
+file, but are also available as git blob objects for easier use.
+
+Importing a key the usual way:
+
+ $ gpg --keyserver pool.sks-keyservers.net \
+ --recv-keys AE9BC059
+
+Importing a key from a git blob object:
+
+ $ git show pubkey-saghul | gpg --import
+
+### Verifying releases
+
+Git tags are signed with the developer's key, they can be verified as follows:
+
+ $ git verify-tag v1.6.1
+
+Starting with libuv 1.7.0, the tarballs stored in the
+[downloads site](http://dist.libuv.org/dist/) are signed and an accompanying
+signature file sit alongside each. Once both the release tarball and the
+signature file are downloaded, the file can be verified as follows:
+
+ $ gpg --verify libuv-1.7.0.tar.gz.sign
+
+## Build Instructions
+
+For GCC there are two build methods: via autotools or via [GYP][].
+GYP is a meta-build system which can generate MSVS, Makefile, and XCode
+backends. It is best used for integration into other projects.
+
+To build with autotools:
+
+ $ sh autogen.sh
+ $ ./configure
+ $ make
+ $ make check
+ $ make install
+
+### Windows
+
+First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][].
+If python is not in your path, set the environment variable `PYTHON` to its
+location. For example: `set PYTHON=C:\Python27\python.exe`
+
+To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell)
+and run vcbuild.bat which will checkout the GYP code into build/gyp and
+generate uv.sln as well as related project files.
+
+To have GYP generate build script for another system, checkout GYP into the
+project tree manually:
+
+ $ git clone https://chromium.googlesource.com/external/gyp.git build/gyp
+
+### Unix
+
+Run:
+
+ $ ./gyp_uv.py -f make
+ $ make -C out
+
+Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries.
+
+### OS X
+
+Run:
+
+ $ ./gyp_uv.py -f xcode
+ $ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \
+ -configuration Release -target All
+
+Using Homebrew:
+
+ $ brew install --HEAD libuv
+
+Note to OS X users:
+
+Make sure that you specify the architecture you wish to build for in the
+"ARCHS" flag. You can specify more than one by delimiting with a space
+(e.g. "x86_64 i386").
+
+### Android
+
+Run:
+
+ $ source ./android-configure NDK_PATH gyp
+ $ make -C out
+
+Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
+`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
+
+### Using Ninja
+
+To use ninja for build on ninja supported platforms, run:
+
+ $ ./gyp_uv.py -f ninja
+ $ ninja -C out/Debug #for debug build OR
+ $ ninja -C out/Release
+
+
+### Running tests
+
+Run:
+
+ $ ./gyp_uv.py -f make
+ $ make -C out
+ $ ./out/Debug/run-tests
+
+## Supported Platforms
+
+Microsoft Windows operating systems since Windows XP SP2. It can be built
+with either Visual Studio or MinGW. Consider using
+[Visual Studio Express 2010][] or later if you do not have a full Visual
+Studio license.
+
+Linux using the GCC toolchain.
+
+OS X using the GCC or XCode toolchain.
+
+Solaris 121 and later using GCC toolchain.
+
+AIX 6 and later using GCC toolchain (see notes).
+
+### AIX Notes
+
+AIX support for filesystem events requires the non-default IBM `bos.ahafs`
+package to be installed. This package provides the AIX Event Infrastructure
+that is detected by `autoconf`.
+[IBM documentation](http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/)
+describes the package in more detail.
+
+AIX support for filesystem events is not compiled when building with `gyp`.
+
+## Patches
+
+See the [guidelines for contributing][].
+
+[node.js]: http://nodejs.org/
+[GYP]: http://code.google.com/p/gyp/
+[Python]: https://www.python.org/downloads/
+[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
+[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
+[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
diff --git a/3rdparty/libuv/android-configure b/3rdparty/libuv/android-configure
new file mode 100644
index 00000000000..e0b250fb634
--- /dev/null
+++ b/3rdparty/libuv/android-configure
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+export TOOLCHAIN=$PWD/android-toolchain
+mkdir -p $TOOLCHAIN
+$1/build/tools/make-standalone-toolchain.sh \
+ --toolchain=arm-linux-androideabi-4.8 \
+ --arch=arm \
+ --install-dir=$TOOLCHAIN \
+ --platform=android-21
+export PATH=$TOOLCHAIN/bin:$PATH
+export AR=arm-linux-androideabi-ar
+export CC=arm-linux-androideabi-gcc
+export CXX=arm-linux-androideabi-g++
+export LINK=arm-linux-androideabi-g++
+export PLATFORM=android
+
+if [ $2 -a $2 == 'gyp' ]
+ then
+ ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android
+fi
diff --git a/3rdparty/libuv/appveyor.yml b/3rdparty/libuv/appveyor.yml
new file mode 100644
index 00000000000..9aa63c5a5d2
--- /dev/null
+++ b/3rdparty/libuv/appveyor.yml
@@ -0,0 +1,36 @@
+version: v1.8.0.build{build}
+
+install:
+ - cinst -y nsis
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - platform: x86
+ configuration: Release
+ - platform: x64
+ configuration: Release
+
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Release
+
+build_script:
+ # Fixed tag version number if using a tag.
+ - cmd: if "%APPVEYOR_REPO_TAG%" == "true" set APPVEYOR_BUILD_VERSION=%APPVEYOR_REPO_TAG_NAME%
+ # vcbuild overwrites the platform variable.
+ - cmd: set ARCH=%platform%
+ - cmd: vcbuild.bat release %ARCH% shared
+
+after_build:
+ - '"%PROGRAMFILES(x86)%\NSIS\makensis" /DVERSION=%APPVEYOR_BUILD_VERSION% /DARCH=%ARCH% libuv.nsi'
+
+artifacts:
+ - name: Installer
+ path: 'libuv-*.exe'
+
+cache:
+ - C:\projects\libuv\build\gyp
diff --git a/3rdparty/libuv/autogen.sh b/3rdparty/libuv/autogen.sh
new file mode 100644
index 00000000000..0574778a4e1
--- /dev/null
+++ b/3rdparty/libuv/autogen.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+cd `dirname "$0"`
+
+if [ "$LIBTOOLIZE" = "" ] && [ "`uname`" = "Darwin" ]; then
+ LIBTOOLIZE=glibtoolize
+fi
+
+ACLOCAL=${ACLOCAL:-aclocal}
+AUTOCONF=${AUTOCONF:-autoconf}
+AUTOMAKE=${AUTOMAKE:-automake}
+LIBTOOLIZE=${LIBTOOLIZE:-libtoolize}
+
+automake_version=`"$AUTOMAKE" --version | head -n 1 | sed 's/[^.0-9]//g'`
+automake_version_major=`echo "$automake_version" | cut -d. -f1`
+automake_version_minor=`echo "$automake_version" | cut -d. -f2`
+
+UV_EXTRA_AUTOMAKE_FLAGS=
+if test "$automake_version_major" -gt 1 || \
+ test "$automake_version_major" -eq 1 && \
+ test "$automake_version_minor" -gt 11; then
+ # serial-tests is available in v1.12 and newer.
+ UV_EXTRA_AUTOMAKE_FLAGS="$UV_EXTRA_AUTOMAKE_FLAGS serial-tests"
+fi
+echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \
+ > m4/libuv-extra-automake-flags.m4
+
+set -ex
+"$LIBTOOLIZE"
+"$ACLOCAL" -I m4
+"$AUTOCONF"
+"$AUTOMAKE" --add-missing --copy
diff --git a/3rdparty/libuv/checksparse.sh b/3rdparty/libuv/checksparse.sh
new file mode 100644
index 00000000000..619cf6f8b67
--- /dev/null
+++ b/3rdparty/libuv/checksparse.sh
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+SPARSE=${SPARSE:-sparse}
+
+SPARSE_FLAGS=${SPARSE_FLAGS:-"
+-D__POSIX__
+-Wsparse-all
+-Wno-do-while
+-Wno-transparent-union
+-Iinclude
+-Isrc
+"}
+
+SOURCES="
+include/tree.h
+include/uv-unix.h
+include/uv.h
+src/fs-poll.c
+src/inet.c
+src/queue.h
+src/unix/async.c
+src/unix/core.c
+src/unix/dl.c
+src/unix/fs.c
+src/unix/getaddrinfo.c
+src/unix/internal.h
+src/unix/loop-watcher.c
+src/unix/loop.c
+src/unix/pipe.c
+src/unix/poll.c
+src/unix/process.c
+src/unix/signal.c
+src/unix/stream.c
+src/unix/tcp.c
+src/unix/thread.c
+src/unix/threadpool.c
+src/unix/timer.c
+src/unix/tty.c
+src/unix/udp.c
+src/uv-common.c
+src/uv-common.h
+"
+
+TESTS="
+test/benchmark-async-pummel.c
+test/benchmark-async.c
+test/benchmark-fs-stat.c
+test/benchmark-getaddrinfo.c
+test/benchmark-loop-count.c
+test/benchmark-million-async.c
+test/benchmark-million-timers.c
+test/benchmark-multi-accept.c
+test/benchmark-ping-pongs.c
+test/benchmark-pound.c
+test/benchmark-pump.c
+test/benchmark-sizes.c
+test/benchmark-spawn.c
+test/benchmark-tcp-write-batch.c
+test/benchmark-thread.c
+test/benchmark-udp-pummel.c
+test/blackhole-server.c
+test/dns-server.c
+test/echo-server.c
+test/run-benchmarks.c
+test/run-tests.c
+test/runner-unix.c
+test/runner-unix.h
+test/runner.c
+test/runner.h
+test/task.h
+test/test-active.c
+test/test-async.c
+test/test-barrier.c
+test/test-callback-order.c
+test/test-callback-stack.c
+test/test-condvar.c
+test/test-connection-fail.c
+test/test-cwd-and-chdir.c
+test/test-delayed-accept.c
+test/test-dlerror.c
+test/test-embed.c
+test/test-error.c
+test/test-fail-always.c
+test/test-fs-event.c
+test/test-fs-poll.c
+test/test-fs.c
+test/test-get-currentexe.c
+test/test-get-loadavg.c
+test/test-get-memory.c
+test/test-getaddrinfo.c
+test/test-getsockname.c
+test/test-homedir.c
+test/test-hrtime.c
+test/test-idle.c
+test/test-ip6-addr.c
+test/test-ipc-send-recv.c
+test/test-ipc.c
+test/test-loop-handles.c
+test/test-multiple-listen.c
+test/test-mutexes.c
+test/test-pass-always.c
+test/test-ping-pong.c
+test/test-pipe-bind-error.c
+test/test-pipe-connect-error.c
+test/test-pipe-sendmsg.c
+test/test-pipe-server-close.c
+test/test-platform-output.c
+test/test-poll-close.c
+test/test-poll.c
+test/test-process-title.c
+test/test-ref.c
+test/test-run-nowait.c
+test/test-run-once.c
+test/test-semaphore.c
+test/test-shutdown-close.c
+test/test-shutdown-eof.c
+test/test-signal-multiple-loops.c
+test/test-signal.c
+test/test-spawn.c
+test/test-stdio-over-pipes.c
+test/test-tcp-bind-error.c
+test/test-tcp-bind6-error.c
+test/test-tcp-close-while-connecting.c
+test/test-tcp-close-accept.c
+test/test-tcp-close.c
+test/test-tcp-connect-error-after-write.c
+test/test-tcp-connect-error.c
+test/test-tcp-connect-timeout.c
+test/test-tcp-connect6-error.c
+test/test-tcp-flags.c
+test/test-tcp-open.c
+test/test-tcp-read-stop.c
+test/test-tcp-shutdown-after-write.c
+test/test-tcp-unexpected-read.c
+test/test-tcp-oob.c
+test/test-tcp-write-error.c
+test/test-tcp-write-to-half-open-connection.c
+test/test-tcp-writealot.c
+test/test-thread.c
+test/test-threadpool-cancel.c
+test/test-threadpool.c
+test/test-timer-again.c
+test/test-timer.c
+test/test-tty.c
+test/test-udp-dgram-too-big.c
+test/test-udp-ipv6.c
+test/test-udp-multicast-join.c
+test/test-udp-multicast-ttl.c
+test/test-udp-open.c
+test/test-udp-options.c
+test/test-udp-send-and-recv.c
+test/test-walk-handles.c
+test/test-watcher-cross-stop.c
+"
+
+case `uname -s` in
+AIX)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D_AIX=1"
+ SOURCES="$SOURCES
+ src/unix/aix.c"
+ ;;
+Darwin)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1"
+ SOURCES="$SOURCES
+ include/uv-bsd.h
+ src/unix/darwin.c
+ src/unix/kqueue.c
+ src/unix/fsevents.c"
+ ;;
+DragonFly)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__DragonFly__=1"
+ SOURCES="$SOURCES
+ include/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/freebsd.c"
+ ;;
+FreeBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__FreeBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/freebsd.c"
+ ;;
+Linux)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__linux__=1"
+ SOURCES="$SOURCES
+ include/uv-linux.h
+ src/unix/linux-inotify.c
+ src/unix/linux-core.c
+ src/unix/linux-syscalls.c
+ src/unix/linux-syscalls.h"
+ ;;
+NetBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__NetBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/netbsd.c"
+ ;;
+OpenBSD)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__OpenBSD__=1"
+ SOURCES="$SOURCES
+ include/uv-bsd.h
+ src/unix/kqueue.c
+ src/unix/openbsd.c"
+ ;;
+SunOS)
+ SPARSE_FLAGS="$SPARSE_FLAGS -D__sun=1"
+ SOURCES="$SOURCES
+ include/uv-sunos.h
+ src/unix/sunos.c"
+ ;;
+esac
+
+for ARCH in __i386__ __x86_64__ __arm__ __mips__; do
+ $SPARSE $SPARSE_FLAGS -D$ARCH=1 $SOURCES
+done
+
+# Tests are architecture independent.
+$SPARSE $SPARSE_FLAGS -Itest $TESTS
diff --git a/3rdparty/libuv/common.gypi b/3rdparty/libuv/common.gypi
new file mode 100644
index 00000000000..7cebcde5f89
--- /dev/null
+++ b/3rdparty/libuv/common.gypi
@@ -0,0 +1,210 @@
+{
+ 'variables': {
+ 'visibility%': 'hidden', # V8's visibility setting
+ 'target_arch%': 'ia32', # set v8's target architecture
+ 'host_arch%': 'ia32', # set v8's host architecture
+ 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds
+ 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way
+ },
+
+ 'target_defaults': {
+ 'default_configuration': 'Debug',
+ 'configurations': {
+ 'Debug': {
+ 'defines': [ 'DEBUG', '_DEBUG' ],
+ 'cflags': [ '-g', '-O0', '-fwrapv' ],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'target_conditions': [
+ ['uv_library=="static_library"', {
+ 'RuntimeLibrary': 1, # static debug
+ }, {
+ 'RuntimeLibrary': 3, # DLL debug
+ }],
+ ],
+ 'Optimization': 0, # /Od, no optimization
+ 'MinimalRebuild': 'false',
+ 'OmitFramePointers': 'false',
+ 'BasicRuntimeChecks': 3, # /RTC1
+ },
+ 'VCLinkerTool': {
+ 'LinkIncremental': 2, # enable incremental linking
+ },
+ },
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ],
+ },
+ 'conditions': [
+ ['OS == "android"', {
+ 'cflags': [ '-fPIE' ],
+ 'ldflags': [ '-fPIE', '-pie' ]
+ }]
+ ]
+ },
+ 'Release': {
+ 'defines': [ 'NDEBUG' ],
+ 'cflags': [
+ '-O3',
+ '-fstrict-aliasing',
+ '-fomit-frame-pointer',
+ '-fdata-sections',
+ '-ffunction-sections',
+ ],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'target_conditions': [
+ ['uv_library=="static_library"', {
+ 'RuntimeLibrary': 0, # static release
+ }, {
+ 'RuntimeLibrary': 2, # debug release
+ }],
+ ],
+ 'Optimization': 3, # /Ox, full optimization
+ 'FavorSizeOrSpeed': 1, # /Ot, favour speed over size
+ 'InlineFunctionExpansion': 2, # /Ob2, inline anything eligible
+ 'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG
+ 'OmitFramePointers': 'true',
+ 'EnableFunctionLevelLinking': 'true',
+ 'EnableIntrinsicFunctions': 'true',
+ },
+ 'VCLibrarianTool': {
+ 'AdditionalOptions': [
+ '/LTCG', # link time code generation
+ ],
+ },
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': 1, # link-time code generation
+ 'OptimizeReferences': 2, # /OPT:REF
+ 'EnableCOMDATFolding': 2, # /OPT:ICF
+ 'LinkIncremental': 1, # disable incremental linking
+ },
+ },
+ }
+ },
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'StringPooling': 'true', # pool string literals
+ 'DebugInformationFormat': 3, # Generate a PDB
+ 'WarningLevel': 3,
+ 'BufferSecurityCheck': 'true',
+ 'ExceptionHandling': 1, # /EHsc
+ 'SuppressStartupBanner': 'true',
+ 'WarnAsError': 'false',
+ 'AdditionalOptions': [
+ '/MP', # compile across multiple CPUs
+ ],
+ },
+ 'VCLibrarianTool': {
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true',
+ 'RandomizedBaseAddress': 2, # enable ASLR
+ 'DataExecutionPrevention': 2, # enable DEP
+ 'AllowIsolation': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'target_conditions': [
+ ['_type=="executable"', {
+ 'SubSystem': 1, # console executable
+ }],
+ ],
+ },
+ },
+ 'conditions': [
+ ['OS == "win"', {
+ 'msvs_cygwin_shell': 0, # prevent actions from trying to use cygwin
+ 'defines': [
+ 'WIN32',
+ # we don't really want VC++ warning us about
+ # how dangerous C functions are...
+ '_CRT_SECURE_NO_DEPRECATE',
+ # ... or that C implementations shouldn't use
+ # POSIX names
+ '_CRT_NONSTDC_NO_DEPRECATE',
+ ],
+ 'target_conditions': [
+ ['target_arch=="x64"', {
+ 'msvs_configuration_platform': 'x64'
+ }]
+ ]
+ }],
+ ['OS in "freebsd dragonflybsd linux openbsd solaris android"', {
+ 'cflags': [ '-Wall' ],
+ 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ],
+ 'target_conditions': [
+ ['_type=="static_library"', {
+ 'standalone_static_library': 1, # disable thin archive which needs binutils >= 2.19
+ }],
+ ],
+ 'conditions': [
+ [ 'host_arch != target_arch and target_arch=="ia32"', {
+ 'cflags': [ '-m32' ],
+ 'ldflags': [ '-m32' ],
+ }],
+ [ 'target_arch=="x32"', {
+ 'cflags': [ '-mx32' ],
+ 'ldflags': [ '-mx32' ],
+ }],
+ [ 'OS=="linux"', {
+ 'cflags': [ '-ansi' ],
+ }],
+ [ 'OS=="solaris"', {
+ 'cflags': [ '-pthreads' ],
+ 'ldflags': [ '-pthreads' ],
+ }],
+ [ 'OS not in "solaris android"', {
+ 'cflags': [ '-pthread' ],
+ 'ldflags': [ '-pthread' ],
+ }],
+ [ 'visibility=="hidden"', {
+ 'cflags': [ '-fvisibility=hidden' ],
+ }],
+ ],
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'ALWAYS_SEARCH_USER_PATHS': 'NO',
+ 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks
+ 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
+ # (Equivalent to -fPIC)
+ 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions
+ 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
+ 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings
+ # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden
+ 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
+ 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
+ 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics
+ 'PREBINDING': 'NO', # No -Wl,-prebind
+ 'USE_HEADERMAP': 'NO',
+ 'OTHER_CFLAGS': [
+ '-fstrict-aliasing',
+ ],
+ 'WARNING_CFLAGS': [
+ '-Wall',
+ '-Wendif-labels',
+ '-W',
+ '-Wno-unused-parameter',
+ ],
+ },
+ 'conditions': [
+ ['target_arch=="ia32"', {
+ 'xcode_settings': {'ARCHS': ['i386']},
+ }],
+ ['target_arch=="x64"', {
+ 'xcode_settings': {'ARCHS': ['x86_64']},
+ }],
+ ],
+ 'target_conditions': [
+ ['_type!="static_library"', {
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']},
+ }],
+ ],
+ }],
+ ['OS=="solaris"', {
+ 'cflags': [ '-fno-omit-frame-pointer' ],
+ # pull in V8's postmortem metadata
+ 'ldflags': [ '-Wl,-z,allextract' ]
+ }],
+ ],
+ },
+}
diff --git a/3rdparty/libuv/configure.ac b/3rdparty/libuv/configure.ac
new file mode 100644
index 00000000000..011bee2a891
--- /dev/null
+++ b/3rdparty/libuv/configure.ac
@@ -0,0 +1,68 @@
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+AC_PREREQ(2.57)
+AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues])
+AC_CONFIG_MACRO_DIR([m4])
+m4_include([m4/libuv-extra-automake-flags.m4])
+m4_include([m4/as_case.m4])
+m4_include([m4/libuv-check-flags.m4])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
+AC_CANONICAL_HOST
+AC_ENABLE_SHARED
+AC_ENABLE_STATIC
+AC_PROG_CC
+AM_PROG_CC_C_O
+CC_CHECK_CFLAGS_APPEND([-fvisibility=hidden])
+CC_CHECK_CFLAGS_APPEND([-g])
+CC_CHECK_CFLAGS_APPEND([-std=gnu89])
+CC_CHECK_CFLAGS_APPEND([-pedantic])
+CC_CHECK_CFLAGS_APPEND([-Wall])
+CC_CHECK_CFLAGS_APPEND([-Wextra])
+CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter])
+# AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12.
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+# autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR.
+AC_PROG_LIBTOOL
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+LT_INIT
+# TODO(bnoordhuis) Check for -pthread vs. -pthreads
+AC_CHECK_LIB([dl], [dlopen])
+AC_CHECK_LIB([kstat], [kstat_lookup])
+AC_CHECK_LIB([kvm], [kvm_open])
+AC_CHECK_LIB([nsl], [gethostbyname])
+AC_CHECK_LIB([perfstat], [perfstat_cpu])
+AC_CHECK_LIB([pthread], [pthread_mutex_init])
+AC_CHECK_LIB([rt], [clock_gettime])
+AC_CHECK_LIB([sendfile], [sendfile])
+AC_CHECK_LIB([socket], [socket])
+AC_SYS_LARGEFILE
+AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])])
+AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])])
+AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])])
+AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])])
+AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[freebsd*], [true], [false])])
+AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])])
+AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])])
+AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])])
+AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
+AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
+AC_CHECK_HEADERS([sys/ahafs_evProds.h])
+AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes)
+AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"])
+AS_IF([test "x$PKG_CONFIG" != "x"], [
+ AC_CONFIG_FILES([libuv.pc])
+])
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/3rdparty/libuv/docs/Makefile b/3rdparty/libuv/docs/Makefile
new file mode 100644
index 00000000000..1e0fc8f0220
--- /dev/null
+++ b/3rdparty/libuv/docs/Makefile
@@ -0,0 +1,178 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = build
+SRCDIR = src
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR)
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR)
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libuv.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libuv.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/libuv"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libuv"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/3rdparty/libuv/docs/make.bat b/3rdparty/libuv/docs/make.bat
new file mode 100644
index 00000000000..10eb94b013b
--- /dev/null
+++ b/3rdparty/libuv/docs/make.bat
@@ -0,0 +1,243 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=build
+set SRCDIR=src
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SRCDIR%
+set I18NSPHINXOPTS=%SPHINXOPTS% %SRCDIR%
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libuv.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libuv.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %BUILDDIR%/..
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+:end
diff --git a/3rdparty/libuv/docs/src/async.rst b/3rdparty/libuv/docs/src/async.rst
new file mode 100644
index 00000000000..5c400458244
--- /dev/null
+++ b/3rdparty/libuv/docs/src/async.rst
@@ -0,0 +1,57 @@
+
+.. _async:
+
+:c:type:`uv_async_t` --- Async handle
+=====================================
+
+Async handles allow the user to "wakeup" the event loop and get a callback
+called from another thread.
+
+
+Data types
+----------
+
+.. c:type:: uv_async_t
+
+ Async handle type.
+
+.. c:type:: void (*uv_async_cb)(uv_async_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_async_init`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb)
+
+ Initialize the handle. A NULL callback is allowed.
+
+ .. note::
+ Unlike other handle initialization functions, it immediately starts the handle.
+
+.. c:function:: int uv_async_send(uv_async_t* async)
+
+ Wakeup the event loop and call the async handle's callback.
+
+ .. note::
+ It's safe to call this function from any thread. The callback will be called on the
+ loop thread.
+
+ .. warning::
+ libuv will coalesce calls to :c:func:`uv_async_send`, that is, not every call to it will
+ yield an execution of the callback. For example: if :c:func:`uv_async_send` is called 5
+ times in a row before the callback is called, the callback will only be called once. If
+ :c:func:`uv_async_send` is called again after the callback was called, it will be called
+ again.
+
+.. seealso::
+ The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/check.rst b/3rdparty/libuv/docs/src/check.rst
new file mode 100644
index 00000000000..36c93cf03d9
--- /dev/null
+++ b/3rdparty/libuv/docs/src/check.rst
@@ -0,0 +1,46 @@
+
+.. _check:
+
+:c:type:`uv_check_t` --- Check handle
+=====================================
+
+Check handles will run the given callback once per loop iteration, right
+after polling for i/o.
+
+
+Data types
+----------
+
+.. c:type:: uv_check_t
+
+ Check handle type.
+
+.. c:type:: void (*uv_check_cb)(uv_check_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_check_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_check_init(uv_loop_t* loop, uv_check_t* check)
+
+ Initialize the handle.
+
+.. c:function:: int uv_check_start(uv_check_t* check, uv_check_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_check_stop(uv_check_t* check)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/conf.py b/3rdparty/libuv/docs/src/conf.py
new file mode 100644
index 00000000000..b9eaa137432
--- /dev/null
+++ b/3rdparty/libuv/docs/src/conf.py
@@ -0,0 +1,348 @@
+# -*- coding: utf-8 -*-
+#
+# libuv API documentation documentation build configuration file, created by
+# sphinx-quickstart on Sun Jul 27 11:47:51 2014.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import os
+import re
+import sys
+
+
+def get_libuv_version():
+ with open('../../include/uv-version.h') as f:
+ data = f.read()
+ try:
+ m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE)
+ major = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE)
+ minor = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE)
+ patch = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE)
+ is_release = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_SUFFIX \"(\w*)\"$""", data, re.MULTILINE)
+ suffix = m.group(1)
+ return '%d.%d.%d%s' % (major, minor, patch, '-%s' % suffix if not is_release else '')
+ except Exception:
+ return 'unknown'
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('sphinx-plugins'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['manpage']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libuv API documentation'
+copyright = u'libuv contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = get_libuv_version()
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'nature'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = 'libuv API documentation'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = 'libuv %s API documentation' % version
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'static/logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = 'static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libuv'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ ('index', 'libuv.tex', u'libuv API documentation',
+ u'libuv contributors', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'libuv', u'libuv API documentation',
+ [u'libuv contributors'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'libuv', u'libuv API documentation',
+ u'libuv contributors', 'libuv', 'Cross-platform asynchronous I/O',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'libuv API documentation'
+epub_author = u'libuv contributors'
+epub_publisher = u'libuv contributors'
+epub_copyright = u'2014, libuv contributors'
+
+# The basename for the epub file. It defaults to the project name.
+epub_basename = u'libuv'
+
+# The HTML theme for the epub output. Since the default themes are not optimized
+# for small screen space, using the same theme for HTML and epub output is
+# usually not wise. This defaults to 'epub', a theme designed to save visual
+# space.
+#epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+#epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+#epub_tocscope = 'default'
+
+# Fix unsupported image types using the PIL.
+#epub_fix_images = False
+
+# Scale large images.
+#epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#epub_show_urls = 'inline'
+
+# If false, no index is generated.
+#epub_use_index = True
diff --git a/3rdparty/libuv/docs/src/design.rst b/3rdparty/libuv/docs/src/design.rst
new file mode 100644
index 00000000000..34c3cff68e5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/design.rst
@@ -0,0 +1,137 @@
+
+.. _design:
+
+Design overview
+===============
+
+libuv is cross-platform support library which was originally written for NodeJS. It's designed
+around the event-driven asynchronous I/O model.
+
+The library provides much more than simply abstraction over different I/O polling mechanisms:
+'handles' and 'streams' provide a high level abstraction for sockets and other entities;
+cross-platform file I/O and threading functionality is also provided, amongst other things.
+
+Here is a diagram illustrating the different parts that compose libuv and what subsystem they
+relate to:
+
+.. image:: static/architecture.png
+ :scale: 75%
+ :align: center
+
+
+Handles and requests
+^^^^^^^^^^^^^^^^^^^^
+
+libuv provides users with 2 abstractions to work with, in combination with the event loop:
+handles and requests.
+
+Handles represent long-lived objects capable of performing certain operations while active. Some
+examples: a prepare handle gets its callback called once every loop iteration when active, and
+a TCP server handle get its connection callback called every time there is a new connection.
+
+Requests represent (typically) short-lived operations. These operations can be performed over a
+handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests
+don't need a handle they run directly on the loop.
+
+
+The I/O loop
+^^^^^^^^^^^^
+
+The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O
+operations, and it's meant to be tied to a single thread. One can run multiple event loops
+as long as each runs in a different thread. The libuv event loop (or any other API involving
+the loop or handles, for that matter) **is not thread-safe** except where stated otherwise.
+
+The event loop follows the rather usual single threaded asynchronous I/O approach: all (network)
+I/O is performed on non-blocking sockets which are polled using the best mechanism available
+on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP
+on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets
+which have been added to the poller and callbacks will be fired indicating socket conditions
+(readable, writable hangup) so handles can read, write or perform the desired I/O operation.
+
+In order to better understand how the event loop operates, the following diagram illustrates all
+stages of a loop iteration:
+
+.. image:: static/loop_iteration.png
+ :scale: 75%
+ :align: center
+
+
+#. The loop concept of 'now' is updated. The event loop caches the current time at the start of
+ the event loop tick in order to reduce the number of time-related system calls.
+
+#. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So,
+ when is a loop considered to be *alive*? If a loop has active and ref'd handles, active
+ requests or closing handles it's considered to be *alive*.
+
+#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now*
+ get their callbacks called.
+
+#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the
+ most part. There are cases, however, in which calling such a callback is deferred for the next
+ loop iteration. If the previous iteration deferred any I/O callback it will be run at this point.
+
+#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every
+ loop iteration, if they are active.
+
+#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before
+ the loop will block for I/O.
+
+#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should
+ block. These are the rules when calculating the timeout:
+
+ * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0.
+ * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0.
+ * If there are no active handles or requests, the timeout is 0.
+ * If there are any idle handles active, the timeout is 0.
+ * If there are any handles pending to be closed, the timeout is 0.
+ * If none of the above cases was matched, the timeout of the closest timer is taken, or
+ if there are no active timers, infinity.
+
+#. The loop blocks for I/O. At this point the loop will block for I/O for the timeout calculated
+ on the previous step. All I/O related handles that were monitoring a given file descriptor
+ for a read or write operation get their callbacks called at this point.
+
+#. Check handle callbacks are called. Check handles get their callbacks called right after the
+ loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles.
+
+#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will
+ get the close callback called.
+
+#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress.
+ It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed
+ so there might be timers which are due, those timers get their callbacks called.
+
+#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the
+ iteration is ended and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT``
+ it will continue from the start if it's still *alive*, otherwise it will also end.
+
+
+.. important::
+ libuv uses a thread pool to make asynchronous file I/O operations possible, but
+ network I/O is **always** performed in a single thread, each loop's thread.
+
+.. note::
+ While the polling mechanism is different, libuv makes the execution model consistent
+ across Unix systems and Windows.
+
+
+File I/O
+^^^^^^^^
+
+Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on,
+so the current approach is to run blocking file I/O operations in a thread pool.
+
+For a thorough explanation of the cross-platform file I/O landscape, checkout
+`this post <http://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_.
+
+libuv currently uses a global thread pool on which all loops can queue work on. 3 types of
+operations are currently run on this pool:
+
+ * Filesystem operations
+ * DNS functions (getaddrinfo and getnameinfo)
+ * User specified code via :c:func:`uv_queue_work`
+
+.. warning::
+ See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size
+ is quite limited.
diff --git a/3rdparty/libuv/docs/src/dll.rst b/3rdparty/libuv/docs/src/dll.rst
new file mode 100644
index 00000000000..fb13f908159
--- /dev/null
+++ b/3rdparty/libuv/docs/src/dll.rst
@@ -0,0 +1,44 @@
+
+.. _dll:
+
+Shared library handling
+=======================
+
+libuv provides cross platform utilities for loading shared libraries and
+retrieving symbols from them, using the following API.
+
+
+Data types
+----------
+
+.. c:type:: uv_lib_t
+
+ Shared library data type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+
+API
+---
+
+.. c:function:: int uv_dlopen(const char* filename, uv_lib_t* lib)
+
+ Opens a shared library. The filename is in utf-8. Returns 0 on success and
+ -1 on error. Call :c:func:`uv_dlerror` to get the error message.
+
+.. c:function:: void uv_dlclose(uv_lib_t* lib)
+
+ Close the shared library.
+
+.. c:function:: int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr)
+
+ Retrieves a data pointer from a dynamic library. It is legal for a symbol
+ to map to NULL. Returns 0 on success and -1 if the symbol was not found.
+
+.. c:function:: const char* uv_dlerror(const uv_lib_t* lib)
+
+ Returns the last uv_dlopen() or uv_dlsym() error message.
diff --git a/3rdparty/libuv/docs/src/dns.rst b/3rdparty/libuv/docs/src/dns.rst
new file mode 100644
index 00000000000..1d881580966
--- /dev/null
+++ b/3rdparty/libuv/docs/src/dns.rst
@@ -0,0 +1,108 @@
+
+.. _dns:
+
+DNS utility functions
+=====================
+
+libuv provides asynchronous variants of `getaddrinfo` and `getnameinfo`.
+
+
+Data types
+----------
+
+.. c:type:: uv_getaddrinfo_t
+
+ `getaddrinfo` request type.
+
+.. c:type:: void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, int status, struct addrinfo* res)
+
+ Callback which will be called with the getaddrinfo request result once
+ complete. In case it was cancelled, `status` will have a value of
+ ``UV_ECANCELED``.
+
+.. c:type:: uv_getnameinfo_t
+
+ `getnameinfo` request type.
+
+.. c:type:: void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, int status, const char* hostname, const char* service)
+
+ Callback which will be called with the getnameinfo request result once
+ complete. In case it was cancelled, `status` will have a value of
+ ``UV_ECANCELED``.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_getaddrinfo_t.loop
+
+ Loop that started this getaddrinfo request and where completion will be
+ reported. Readonly.
+
+.. c:member:: struct addrinfo* uv_getaddrinfo_t.addrinfo
+
+ Pointer to a `struct addrinfo` containing the result. Must be freed by the user
+ with :c:func:`uv_freeaddrinfo`.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. c:member:: uv_loop_t* uv_getnameinfo_t.loop
+
+ Loop that started this getnameinfo request and where completion will be
+ reported. Readonly.
+
+.. c:member:: char[NI_MAXHOST] uv_getnameinfo_t.host
+
+ Char array containing the resulting host. It's null terminated.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. c:member:: char[NI_MAXSERV] uv_getnameinfo_t.service
+
+ Char array containing the resulting service. It's null terminated.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints)
+
+ Asynchronous :man:`getaddrinfo(3)`.
+
+ Either node or service may be NULL but not both.
+
+ `hints` is a pointer to a struct addrinfo with additional address type
+ constraints, or NULL. Consult `man -s 3 getaddrinfo` for more details.
+
+ Returns 0 on success or an error code < 0 on failure. If successful, the
+ callback will get called sometime in the future with the lookup result,
+ which is either:
+
+ * status == 0, the res argument points to a valid `struct addrinfo`, or
+ * status < 0, the res argument is NULL. See the UV_EAI_* constants.
+
+ Call :c:func:`uv_freeaddrinfo` to free the addrinfo structure.
+
+ .. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
+ in which case the request will run **synchronously**.
+
+.. c:function:: void uv_freeaddrinfo(struct addrinfo* ai)
+
+ Free the struct addrinfo. Passing NULL is allowed and is a no-op.
+
+.. c:function:: int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags)
+
+ Asynchronous :man:`getnameinfo(3)`.
+
+ Returns 0 on success or an error code < 0 on failure. If successful, the
+ callback will get called sometime in the future with the lookup result.
+ Consult `man -s 3 getnameinfo` for more details.
+
+ .. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
+ in which case the request will run **synchronously**.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/errors.rst b/3rdparty/libuv/docs/src/errors.rst
new file mode 100644
index 00000000000..cec25f5187e
--- /dev/null
+++ b/3rdparty/libuv/docs/src/errors.rst
@@ -0,0 +1,331 @@
+
+.. _errors:
+
+Error handling
+==============
+
+In libuv errors are negative numbered constants. As a rule of thumb, whenever
+there is a status parameter, or an API functions returns an integer, a negative
+number will imply an error.
+
+.. note::
+ Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on
+ Windows they are defined by libuv to arbitrary negative numbers.
+
+
+Error constants
+---------------
+
+.. c:macro:: UV_E2BIG
+
+ argument list too long
+
+.. c:macro:: UV_EACCES
+
+ permission denied
+
+.. c:macro:: UV_EADDRINUSE
+
+ address already in use
+
+.. c:macro:: UV_EADDRNOTAVAIL
+
+ address not available
+
+.. c:macro:: UV_EAFNOSUPPORT
+
+ address family not supported
+
+.. c:macro:: UV_EAGAIN
+
+ resource temporarily unavailable
+
+.. c:macro:: UV_EAI_ADDRFAMILY
+
+ address family not supported
+
+.. c:macro:: UV_EAI_AGAIN
+
+ temporary failure
+
+.. c:macro:: UV_EAI_BADFLAGS
+
+ bad ai_flags value
+
+.. c:macro:: UV_EAI_BADHINTS
+
+ invalid value for hints
+
+.. c:macro:: UV_EAI_CANCELED
+
+ request canceled
+
+.. c:macro:: UV_EAI_FAIL
+
+ permanent failure
+
+.. c:macro:: UV_EAI_FAMILY
+
+ ai_family not supported
+
+.. c:macro:: UV_EAI_MEMORY
+
+ out of memory
+
+.. c:macro:: UV_EAI_NODATA
+
+ no address
+
+.. c:macro:: UV_EAI_NONAME
+
+ unknown node or service
+
+.. c:macro:: UV_EAI_OVERFLOW
+
+ argument buffer overflow
+
+.. c:macro:: UV_EAI_PROTOCOL
+
+ resolved protocol is unknown
+
+.. c:macro:: UV_EAI_SERVICE
+
+ service not available for socket type
+
+.. c:macro:: UV_EAI_SOCKTYPE
+
+ socket type not supported
+
+.. c:macro:: UV_EALREADY
+
+ connection already in progress
+
+.. c:macro:: UV_EBADF
+
+ bad file descriptor
+
+.. c:macro:: UV_EBUSY
+
+ resource busy or locked
+
+.. c:macro:: UV_ECANCELED
+
+ operation canceled
+
+.. c:macro:: UV_ECHARSET
+
+ invalid Unicode character
+
+.. c:macro:: UV_ECONNABORTED
+
+ software caused connection abort
+
+.. c:macro:: UV_ECONNREFUSED
+
+ connection refused
+
+.. c:macro:: UV_ECONNRESET
+
+ connection reset by peer
+
+.. c:macro:: UV_EDESTADDRREQ
+
+ destination address required
+
+.. c:macro:: UV_EEXIST
+
+ file already exists
+
+.. c:macro:: UV_EFAULT
+
+ bad address in system call argument
+
+.. c:macro:: UV_EFBIG
+
+ file too large
+
+.. c:macro:: UV_EHOSTUNREACH
+
+ host is unreachable
+
+.. c:macro:: UV_EINTR
+
+ interrupted system call
+
+.. c:macro:: UV_EINVAL
+
+ invalid argument
+
+.. c:macro:: UV_EIO
+
+ i/o error
+
+.. c:macro:: UV_EISCONN
+
+ socket is already connected
+
+.. c:macro:: UV_EISDIR
+
+ illegal operation on a directory
+
+.. c:macro:: UV_ELOOP
+
+ too many symbolic links encountered
+
+.. c:macro:: UV_EMFILE
+
+ too many open files
+
+.. c:macro:: UV_EMSGSIZE
+
+ message too long
+
+.. c:macro:: UV_ENAMETOOLONG
+
+ name too long
+
+.. c:macro:: UV_ENETDOWN
+
+ network is down
+
+.. c:macro:: UV_ENETUNREACH
+
+ network is unreachable
+
+.. c:macro:: UV_ENFILE
+
+ file table overflow
+
+.. c:macro:: UV_ENOBUFS
+
+ no buffer space available
+
+.. c:macro:: UV_ENODEV
+
+ no such device
+
+.. c:macro:: UV_ENOENT
+
+ no such file or directory
+
+.. c:macro:: UV_ENOMEM
+
+ not enough memory
+
+.. c:macro:: UV_ENONET
+
+ machine is not on the network
+
+.. c:macro:: UV_ENOPROTOOPT
+
+ protocol not available
+
+.. c:macro:: UV_ENOSPC
+
+ no space left on device
+
+.. c:macro:: UV_ENOSYS
+
+ function not implemented
+
+.. c:macro:: UV_ENOTCONN
+
+ socket is not connected
+
+.. c:macro:: UV_ENOTDIR
+
+ not a directory
+
+.. c:macro:: UV_ENOTEMPTY
+
+ directory not empty
+
+.. c:macro:: UV_ENOTSOCK
+
+ socket operation on non-socket
+
+.. c:macro:: UV_ENOTSUP
+
+ operation not supported on socket
+
+.. c:macro:: UV_EPERM
+
+ operation not permitted
+
+.. c:macro:: UV_EPIPE
+
+ broken pipe
+
+.. c:macro:: UV_EPROTO
+
+ protocol error
+
+.. c:macro:: UV_EPROTONOSUPPORT
+
+ protocol not supported
+
+.. c:macro:: UV_EPROTOTYPE
+
+ protocol wrong type for socket
+
+.. c:macro:: UV_ERANGE
+
+ result too large
+
+.. c:macro:: UV_EROFS
+
+ read-only file system
+
+.. c:macro:: UV_ESHUTDOWN
+
+ cannot send after transport endpoint shutdown
+
+.. c:macro:: UV_ESPIPE
+
+ invalid seek
+
+.. c:macro:: UV_ESRCH
+
+ no such process
+
+.. c:macro:: UV_ETIMEDOUT
+
+ connection timed out
+
+.. c:macro:: UV_ETXTBSY
+
+ text file is busy
+
+.. c:macro:: UV_EXDEV
+
+ cross-device link not permitted
+
+.. c:macro:: UV_UNKNOWN
+
+ unknown error
+
+.. c:macro:: UV_EOF
+
+ end of file
+
+.. c:macro:: UV_ENXIO
+
+ no such device or address
+
+.. c:macro:: UV_EMLINK
+
+ too many links
+
+
+API
+---
+
+.. c:function:: const char* uv_strerror(int err)
+
+ Returns the error message for the given error code. Leaks a few bytes
+ of memory when you call it with an unknown error code.
+
+.. c:function:: const char* uv_err_name(int err)
+
+ Returns the error name for the given error code. Leaks a few bytes
+ of memory when you call it with an unknown error code.
diff --git a/3rdparty/libuv/docs/src/fs.rst b/3rdparty/libuv/docs/src/fs.rst
new file mode 100644
index 00000000000..69e283f4c67
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs.rst
@@ -0,0 +1,300 @@
+
+.. _fs:
+
+Filesystem operations
+=====================
+
+libuv provides a wide variety of cross-platform sync and async filesystem
+operations. All functions defined in this document take a callback, which is
+allowed to be NULL. If the callback is NULL the request is completed synchronously,
+otherwise it will be performed asynchronously.
+
+All file operations are run on the threadpool, see :ref:`threadpool` for information
+on the threadpool size.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_t
+
+ Filesystem request type.
+
+.. c:type:: uv_timespec_t
+
+ Portable equivalent of ``struct timespec``.
+
+ ::
+
+ typedef struct {
+ long tv_sec;
+ long tv_nsec;
+ } uv_timespec_t;
+
+.. c:type:: uv_stat_t
+
+ Portable equivalent of ``struct stat``.
+
+ ::
+
+ typedef struct {
+ uint64_t st_dev;
+ uint64_t st_mode;
+ uint64_t st_nlink;
+ uint64_t st_uid;
+ uint64_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_ino;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_flags;
+ uint64_t st_gen;
+ uv_timespec_t st_atim;
+ uv_timespec_t st_mtim;
+ uv_timespec_t st_ctim;
+ uv_timespec_t st_birthtim;
+ } uv_stat_t;
+
+.. c:type:: uv_fs_type
+
+ Filesystem request type.
+
+ ::
+
+ typedef enum {
+ UV_FS_UNKNOWN = -1,
+ UV_FS_CUSTOM,
+ UV_FS_OPEN,
+ UV_FS_CLOSE,
+ UV_FS_READ,
+ UV_FS_WRITE,
+ UV_FS_SENDFILE,
+ UV_FS_STAT,
+ UV_FS_LSTAT,
+ UV_FS_FSTAT,
+ UV_FS_FTRUNCATE,
+ UV_FS_UTIME,
+ UV_FS_FUTIME,
+ UV_FS_ACCESS,
+ UV_FS_CHMOD,
+ UV_FS_FCHMOD,
+ UV_FS_FSYNC,
+ UV_FS_FDATASYNC,
+ UV_FS_UNLINK,
+ UV_FS_RMDIR,
+ UV_FS_MKDIR,
+ UV_FS_MKDTEMP,
+ UV_FS_RENAME,
+ UV_FS_SCANDIR,
+ UV_FS_LINK,
+ UV_FS_SYMLINK,
+ UV_FS_READLINK,
+ UV_FS_CHOWN,
+ UV_FS_FCHOWN
+ } uv_fs_type;
+
+.. c:type:: uv_dirent_t
+
+ Cross platform (reduced) equivalent of ``struct dirent``.
+ Used in :c:func:`uv_fs_scandir_next`.
+
+ ::
+
+ typedef enum {
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK
+ } uv_dirent_type_t;
+
+ typedef struct uv_dirent_s {
+ const char* name;
+ uv_dirent_type_t type;
+ } uv_dirent_t;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_fs_t.loop
+
+ Loop that started this request and where completion will be reported.
+ Readonly.
+
+.. c:member:: uv_fs_type uv_fs_t.fs_type
+
+ FS request type.
+
+.. c:member:: const char* uv_fs_t.path
+
+ Path affecting the request.
+
+.. c:member:: ssize_t uv_fs_t.result
+
+ Result of the request. < 0 means error, success otherwise. On requests such
+ as :c:func:`uv_fs_read` or :c:func:`uv_fs_write` it indicates the amount of
+ data that was read or written, respectively.
+
+.. c:member:: uv_stat_t uv_fs_t.statbuf
+
+ Stores the result of :c:func:`uv_fs_stat` and other stat requests.
+
+.. c:member:: void* uv_fs_t.ptr
+
+ Stores the result of :c:func:`uv_fs_readlink` and serves as an alias to
+ `statbuf`.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: void uv_fs_req_cleanup(uv_fs_t* req)
+
+ Cleanup request. Must be called after a request is finished to deallocate
+ any memory libuv might have allocated.
+
+.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`close(2)`.
+
+.. c:function:: int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`open(2)`.
+
+ .. note::
+ On Windows libuv uses `CreateFileW` and thus the file is always opened
+ in binary mode. Because of this the O_BINARY and O_TEXT flags are not
+ supported.
+
+.. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`preadv(2)`.
+
+.. c:function:: int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`unlink(2)`.
+
+.. c:function:: int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`pwritev(2)`.
+
+.. c:function:: int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`mkdir(2)`.
+
+ .. note::
+ `mode` is currently not implemented on Windows.
+
+.. c:function:: int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb)
+
+ Equivalent to :man:`mkdtemp(3)`.
+
+ .. note::
+ The result can be found as a null terminated string at `req->path`.
+
+.. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`rmdir(2)`.
+
+.. c:function:: int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb)
+.. c:function:: int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent)
+
+ Equivalent to :man:`scandir(3)`, with a slightly different API. Once the callback
+ for the request is called, the user can use :c:func:`uv_fs_scandir_next` to
+ get `ent` populated with the next directory entry data. When there are no
+ more entries ``UV_EOF`` will be returned.
+
+ .. note::
+ Unlike `scandir(3)`, this function does not return the "." and ".." entries.
+
+ .. note::
+ On Linux, getting the type of an entry is only supported by some filesystems (btrfs, ext2,
+ ext3 and ext4 at the time of this writing), check the :man:`getdents(2)` man page.
+
+.. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+.. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+.. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively.
+
+.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
+
+ Equivalent to :man:`rename(2)`.
+
+.. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`fsync(2)`.
+
+.. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`fdatasync(2)`.
+
+.. c:function:: int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`ftruncate(2)`.
+
+.. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb)
+
+ Limited equivalent to :man:`sendfile(2)`.
+
+.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`access(2)` on Unix. Windows uses ``GetFileAttributesW()``.
+
+.. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+.. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`chmod(2)` and :man:`fchmod(2)` respectively.
+
+.. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb)
+.. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb)
+
+ Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively.
+
+.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
+
+ Equivalent to :man:`link(2)`.
+
+.. c:function:: int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb)
+
+ Equivalent to :man:`symlink(2)`.
+
+ .. note::
+ On Windows the `flags` parameter can be specified to control how the symlink will
+ be created:
+
+ * ``UV_FS_SYMLINK_DIR``: indicates that `path` points to a directory.
+
+ * ``UV_FS_SYMLINK_JUNCTION``: request that the symlink is created
+ using junction points.
+
+.. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`readlink(2)`.
+
+.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``.
+
+ .. note::
+ This function is not implemented on Windows XP and Windows Server 2003.
+ On these systems, UV_ENOSYS is returned.
+
+ .. versionadded:: 1.8.0
+
+.. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
+.. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
+
+ Equivalent to :man:`chown(2)` and :man:`fchown(2)` respectively.
+
+ .. note::
+ These functions are not implemented on Windows.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/fs_event.rst b/3rdparty/libuv/docs/src/fs_event.rst
new file mode 100644
index 00000000000..c2d7f520236
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs_event.rst
@@ -0,0 +1,108 @@
+
+.. _fs_event:
+
+:c:type:`uv_fs_event_t` --- FS Event handle
+===========================================
+
+FS Event handles allow the user to monitor a given path for changes, for example,
+if the file was renamed or there was a generic change in it. This handle uses
+the best backend for the job on each platform.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_event_t
+
+ FS Event handle type.
+
+.. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status)
+
+ Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly
+ after the handle is started. If the handle was started with a directory the
+ `filename` parameter will be a relative path to a file contained in the directory.
+ The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements.
+
+.. c:type:: uv_fs_event
+
+ Event types that :c:type:`uv_fs_event_t` handles monitor.
+
+ ::
+
+ enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+ };
+
+.. c:type:: uv_fs_event_flags
+
+ Flags that can be passed to :c:func:`uv_fs_event_start` to control its
+ behavior.
+
+ ::
+
+ enum uv_fs_event_flags {
+ /*
+ * By default, if the fs event watcher is given a directory name, we will
+ * watch for all events in that directory. This flags overrides this behavior
+ * and makes fs_event report only changes to the directory entry itself. This
+ * flag does not affect individual files watched.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_WATCH_ENTRY = 1,
+ /*
+ * By default uv_fs_event will try to use a kernel interface such as inotify
+ * or kqueue to detect events. This may not work on remote filesystems such
+ * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
+ * regular interval.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_STAT = 2,
+ /*
+ * By default, event watcher, when watching directory, is not registering
+ * (is ignoring) changes in it's subdirectories.
+ * This flag will override this behaviour on platforms that support it.
+ */
+ UV_FS_EVENT_RECURSIVE = 4
+ };
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags)
+
+ Start the handle with the given callback, which will watch the specified
+ `path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`.
+
+ .. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and
+ only on OSX and Windows.
+
+.. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. c:function:: int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size)
+
+ Get the path being monitored by the handle. The buffer must be preallocated
+ by the user. Returns 0 on success or an error code < 0 in case of failure.
+ On success, `buffer` will contain the path and `size` its length. If the buffer
+ is not big enough UV_ENOBUFS will be returned and len will be set to the
+ required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/fs_poll.rst b/3rdparty/libuv/docs/src/fs_poll.rst
new file mode 100644
index 00000000000..4efb2440e0b
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs_poll.rst
@@ -0,0 +1,72 @@
+
+.. _fs_poll:
+
+:c:type:`uv_fs_poll_t` --- FS Poll handle
+=========================================
+
+FS Poll handles allow the user to monitor a given path for changes. Unlike
+:c:type:`uv_fs_event_t`, fs poll handles use `stat` to detect when a file has
+changed so they can work on file systems where fs event handles can't.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_poll_t
+
+ FS Poll handle type.
+
+.. c:type:: void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr)
+
+ Callback passed to :c:func:`uv_fs_poll_start` which will be called repeatedly
+ after the handle is started, when any change happens to the monitored path.
+
+ The callback is invoked with `status < 0` if `path` does not exist
+ or is inaccessible. The watcher is *not* stopped but your callback is
+ not called again until something changes (e.g. when the file is created
+ or the error reason changes).
+
+ When `status == 0`, the callback receives pointers to the old and new
+ :c:type:`uv_stat_t` structs. They are valid for the duration of the
+ callback only.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_fs_poll_start(uv_fs_poll_t* handle, uv_fs_poll_cb poll_cb, const char* path, unsigned int interval)
+
+ Check the file at `path` for changes every `interval` milliseconds.
+
+ .. note::
+ For maximum portability, use multi-second intervals. Sub-second intervals will not detect
+ all changes on many file systems.
+
+.. c:function:: int uv_fs_poll_stop(uv_fs_poll_t* handle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. c:function:: int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size)
+
+ Get the path being monitored by the handle. The buffer must be preallocated
+ by the user. Returns 0 on success or an error code < 0 in case of failure.
+ On success, `buffer` will contain the path and `size` its length. If the buffer
+ is not big enough UV_ENOBUFS will be returned and len will be set to the
+ required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/handle.rst b/3rdparty/libuv/docs/src/handle.rst
new file mode 100644
index 00000000000..6ba597a21ab
--- /dev/null
+++ b/3rdparty/libuv/docs/src/handle.rst
@@ -0,0 +1,181 @@
+
+.. _handle:
+
+:c:type:`uv_handle_t` --- Base handle
+=====================================
+
+`uv_handle_t` is the base type for all libuv handle types.
+
+Structures are aligned so that any libuv handle can be cast to `uv_handle_t`.
+All API functions defined here work with any handle type.
+
+
+Data types
+----------
+
+.. c:type:: uv_handle_t
+
+ The base libuv handle type.
+
+.. c:type:: uv_any_handle
+
+ Union of all handle types.
+
+.. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
+
+ Type definition for callback passed to :c:func:`uv_read_start` and
+ :c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t`
+ structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment)
+ is provided, but it doesn't need to be honored. Setting the buffer's length to 0
+ will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or
+ :c:type:`uv_read_cb` callback.
+
+.. c:type:: void (*uv_close_cb)(uv_handle_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_close`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_handle_t.loop
+
+ Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly.
+
+.. c:member:: void* uv_handle_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field.
+
+
+API
+---
+
+.. c:function:: int uv_is_active(const uv_handle_t* handle)
+
+ Returns non-zero if the handle is active, zero if it's inactive. What
+ "active" means depends on the type of handle:
+
+ - A uv_async_t handle is always active and cannot be deactivated, except
+ by closing it with uv_close().
+
+ - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that
+ deals with i/o - is active when it is doing something that involves i/o,
+ like reading, writing, connecting, accepting new connections, etc.
+
+ - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has
+ been started with a call to uv_check_start(), uv_idle_start(), etc.
+
+ Rule of thumb: if a handle of type `uv_foo_t` has a `uv_foo_start()`
+ function, then it's active from the moment that function is called.
+ Likewise, `uv_foo_stop()` deactivates the handle again.
+
+.. c:function:: int uv_is_closing(const uv_handle_t* handle)
+
+ Returns non-zero if the handle is closing or closed, zero otherwise.
+
+ .. note::
+ This function should only be used between the initialization of the handle and the
+ arrival of the close callback.
+
+.. c:function:: void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
+
+ Request handle to be closed. `close_cb` will be called asynchronously after
+ this call. This MUST be called on each handle before memory is released.
+
+ Handles that wrap file descriptors are closed immediately but
+ `close_cb` will still be deferred to the next iteration of the event loop.
+ It gives you a chance to free up any resources associated with the handle.
+
+ In-progress requests, like uv_connect_t or uv_write_t, are cancelled and
+ have their callbacks called asynchronously with status=UV_ECANCELED.
+
+.. c:function:: void uv_ref(uv_handle_t* handle)
+
+ Reference the given handle. References are idempotent, that is, if a handle
+ is already referenced calling this function again will have no effect.
+
+ See :ref:`refcount`.
+
+.. c:function:: void uv_unref(uv_handle_t* handle)
+
+ Un-reference the given handle. References are idempotent, that is, if a handle
+ is not referenced calling this function again will have no effect.
+
+ See :ref:`refcount`.
+
+.. c:function:: int uv_has_ref(const uv_handle_t* handle)
+
+ Returns non-zero if the handle referenced, zero otherwise.
+
+ See :ref:`refcount`.
+
+.. c:function:: size_t uv_handle_size(uv_handle_type type)
+
+ Returns the size of the given handle type. Useful for FFI binding writers
+ who don't want to know the structure layout.
+
+
+Miscellaneous API functions
+---------------------------
+
+The following API functions take a :c:type:`uv_handle_t` argument but they work
+just for some handle types.
+
+.. c:function:: int uv_send_buffer_size(uv_handle_t* handle, int* value)
+
+ Gets or sets the size of the send buffer that the operating
+ system uses for the socket.
+
+ If `*value` == 0, it will return the current send buffer size,
+ otherwise it will use `*value` to set the new send buffer size.
+
+ This function works for TCP, pipe and UDP handles on Unix and for TCP and
+ UDP handles on Windows.
+
+ .. note::
+ Linux will set double the size and return double the size of the original set value.
+
+.. c:function:: int uv_recv_buffer_size(uv_handle_t* handle, int* value)
+
+ Gets or sets the size of the receive buffer that the operating
+ system uses for the socket.
+
+ If `*value` == 0, it will return the current receive buffer size,
+ otherwise it will use `*value` to set the new receive buffer size.
+
+ This function works for TCP, pipe and UDP handles on Unix and for TCP and
+ UDP handles on Windows.
+
+ .. note::
+ Linux will set double the size and return double the size of the original set value.
+
+.. c:function:: int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd)
+
+ Gets the platform dependent file descriptor equivalent.
+
+ The following handles are supported: TCP, pipes, TTY, UDP and poll. Passing
+ any other handle type will fail with `UV_EINVAL`.
+
+ If a handle doesn't have an attached file descriptor yet or the handle
+ itself has been closed, this function will return `UV_EBADF`.
+
+ .. warning::
+ Be very careful when using this function. libuv assumes it's in control of the file
+ descriptor so any change to it may lead to malfunction.
+
+
+.. _refcount:
+
+Reference counting
+------------------
+
+The libuv event loop (if run in the default mode) will run until there are no
+active `and` referenced handles left. The user can force the loop to exit early
+by unreferencing handles which are active, for example by calling :c:func:`uv_unref`
+after calling :c:func:`uv_timer_start`.
+
+A handle can be referenced or unreferenced, the refcounting scheme doesn't use
+a counter, so both operations are idempotent.
+
+All handles are referenced when active by default, see :c:func:`uv_is_active`
+for a more detailed explanation on what being `active` involves.
diff --git a/3rdparty/libuv/docs/src/idle.rst b/3rdparty/libuv/docs/src/idle.rst
new file mode 100644
index 00000000000..1f51c4a19e4
--- /dev/null
+++ b/3rdparty/libuv/docs/src/idle.rst
@@ -0,0 +1,54 @@
+
+.. _idle:
+
+:c:type:`uv_idle_t` --- Idle handle
+===================================
+
+Idle handles will run the given callback once per loop iteration, right
+before the :c:type:`uv_prepare_t` handles.
+
+.. note::
+ The notable difference with prepare handles is that when there are active idle handles,
+ the loop will perform a zero timeout poll instead of blocking for i/o.
+
+.. warning::
+ Despite the name, idle handles will get their callbacks called on every loop iteration,
+ not when the loop is actually "idle".
+
+
+Data types
+----------
+
+.. c:type:: uv_idle_t
+
+ Idle handle type.
+
+.. c:type:: void (*uv_idle_cb)(uv_idle_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_idle_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_idle_stop(uv_idle_t* idle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/index.rst b/3rdparty/libuv/docs/src/index.rst
new file mode 100644
index 00000000000..fa89c4bffe5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/index.rst
@@ -0,0 +1,95 @@
+
+Welcome to the libuv API documentation
+======================================
+
+Overview
+--------
+
+libuv is a multi-platform support library with a focus on asynchronous I/O. It
+was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_,
+`Julia`_, `pyuv`_, and `others`_.
+
+.. note::
+ In case you find errors in this documentation you can help by sending
+ `pull requests <https://github.com/libuv/libuv>`_!
+
+.. _Node.js: http://nodejs.org
+.. _Luvit: http://luvit.io
+.. _Julia: http://julialang.org
+.. _pyuv: https://github.com/saghul/pyuv
+.. _others: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv
+
+
+Features
+--------
+
+* Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
+* Asynchronous TCP and UDP sockets
+* Asynchronous DNS resolution
+* Asynchronous file and file system operations
+* File system events
+* ANSI escape code controlled TTY
+* IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
+* Child processes
+* Thread pool
+* Signal handling
+* High resolution clock
+* Threading and synchronization primitives
+
+
+Downloads
+---------
+
+libuv can be downloaded from `here <http://dist.libuv.org/dist/>`_.
+
+
+Installation
+------------
+
+Installation instructions can be found on `the README <https://github.com/libuv/libuv/blob/master/README.md>`_.
+
+
+Upgrading
+---------
+
+Migration guides for different libuv versions, starting with 1.0.
+
+.. toctree::
+ :maxdepth: 1
+
+ migration_010_100
+
+
+Documentation
+-------------
+
+.. toctree::
+ :maxdepth: 1
+
+ design
+ errors
+ version
+ loop
+ handle
+ request
+ timer
+ prepare
+ check
+ idle
+ async
+ poll
+ signal
+ process
+ stream
+ tcp
+ pipe
+ tty
+ udp
+ fs_event
+ fs_poll
+ fs
+ threadpool
+ dns
+ dll
+ threading
+ misc
diff --git a/3rdparty/libuv/docs/src/loop.rst b/3rdparty/libuv/docs/src/loop.rst
new file mode 100644
index 00000000000..2a01d796375
--- /dev/null
+++ b/3rdparty/libuv/docs/src/loop.rst
@@ -0,0 +1,166 @@
+
+.. _loop:
+
+:c:type:`uv_loop_t` --- Event loop
+==================================
+
+The event loop is the central part of libuv's functionality. It takes care
+of polling for i/o and scheduling callbacks to be run based on different sources
+of events.
+
+
+Data types
+----------
+
+.. c:type:: uv_loop_t
+
+ Loop data type.
+
+.. c:type:: uv_run_mode
+
+ Mode used to run the loop with :c:func:`uv_run`.
+
+ ::
+
+ typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+ } uv_run_mode;
+
+.. c:type:: void (*uv_walk_cb)(uv_handle_t* handle, void* arg)
+
+ Type definition for callback passed to :c:func:`uv_walk`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: void* uv_loop_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field. libuv does, however,
+ initialize it to NULL in :c:func:`uv_loop_init`, and it poisons the value (on debug builds)
+ on :c:func:`uv_loop_close`.
+
+
+API
+---
+
+.. c:function:: int uv_loop_init(uv_loop_t* loop)
+
+ Initializes the given `uv_loop_t` structure.
+
+.. c:function:: int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...)
+
+ .. versionadded:: 1.0.2
+
+ Set additional loop options. You should normally call this before the
+ first call to :c:func:`uv_run` unless mentioned otherwise.
+
+ Returns 0 on success or a UV_E* error code on failure. Be prepared to
+ handle UV_ENOSYS; it means the loop option is not supported by the platform.
+
+ Supported options:
+
+ - UV_LOOP_BLOCK_SIGNAL: Block a signal when polling for new events. The
+ second argument to :c:func:`uv_loop_configure` is the signal number.
+
+ This operation is currently only implemented for SIGPROF signals,
+ to suppress unnecessary wakeups when using a sampling profiler.
+ Requesting other signals will fail with UV_EINVAL.
+
+.. c:function:: int uv_loop_close(uv_loop_t* loop)
+
+ Closes all internal loop resources. This function must only be called once
+ the loop has finished its execution or it will return UV_EBUSY. After this
+ function returns the user shall free the memory allocated for the loop.
+
+.. c:function:: uv_loop_t* uv_default_loop(void)
+
+ Returns the initialized default loop. It may return NULL in case of
+ allocation failure.
+
+ This function is just a convenient way for having a global loop throughout
+ an application, the default loop is in no way different than the ones
+ initialized with :c:func:`uv_loop_init`. As such, the default loop can (and
+ should) be closed with :c:func:`uv_loop_close` so the resources associated
+ with it are freed.
+
+.. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode)
+
+ This function runs the event loop. It will act differently depending on the
+ specified mode:
+
+ - UV_RUN_DEFAULT: Runs the event loop until there are no more active and
+ referenced handles or requests. Returns non-zero if :c:func:`uv_stop`
+ was called and there are still active handles or requests. Returns
+ zero in all other cases.
+ - UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if
+ there are no pending callbacks. Returns zero when done (no active handles
+ or requests left), or non-zero if more callbacks are expected (meaning
+ you should run the event loop again sometime in the future).
+ - UV_RUN_NOWAIT: Poll for i/o once but don't block if there are no
+ pending callbacks. Returns zero if done (no active handles
+ or requests left), or non-zero if more callbacks are expected (meaning
+ you should run the event loop again sometime in the future).
+
+.. c:function:: int uv_loop_alive(const uv_loop_t* loop)
+
+ Returns non-zero if there are active handles or request in the loop.
+
+.. c:function:: void uv_stop(uv_loop_t* loop)
+
+ Stop the event loop, causing :c:func:`uv_run` to end as soon as
+ possible. This will happen not sooner than the next loop iteration.
+ If this function was called before blocking for i/o, the loop won't block
+ for i/o on this iteration.
+
+.. c:function:: size_t uv_loop_size(void)
+
+ Returns the size of the `uv_loop_t` structure. Useful for FFI binding
+ writers who don't want to know the structure layout.
+
+.. c:function:: int uv_backend_fd(const uv_loop_t* loop)
+
+ Get backend file descriptor. Only kqueue, epoll and event ports are
+ supported.
+
+ This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to
+ poll in one thread and run the event loop's callbacks in another see
+ test/test-embed.c for an example.
+
+ .. note::
+ Embedding a kqueue fd in another kqueue pollset doesn't work on all platforms. It's not
+ an error to add the fd but it never generates events.
+
+.. c:function:: int uv_backend_timeout(const uv_loop_t* loop)
+
+ Get the poll timeout. The return value is in milliseconds, or -1 for no
+ timeout.
+
+.. c:function:: uint64_t uv_now(const uv_loop_t* loop)
+
+ Return the current timestamp in milliseconds. The timestamp is cached at
+ the start of the event loop tick, see :c:func:`uv_update_time` for details
+ and rationale.
+
+ The timestamp increases monotonically from some arbitrary point in time.
+ Don't make assumptions about the starting point, you will only get
+ disappointed.
+
+ .. note::
+ Use :c:func:`uv_hrtime` if you need sub-millisecond granularity.
+
+.. c:function:: void uv_update_time(uv_loop_t* loop)
+
+ Update the event loop's concept of "now". Libuv caches the current time
+ at the start of the event loop tick in order to reduce the number of
+ time-related system calls.
+
+ You won't normally need to call this function unless you have callbacks
+ that block the event loop for longer periods of time, where "longer" is
+ somewhat subjective but probably on the order of a millisecond or more.
+
+.. c:function:: void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg)
+
+ Walk the list of handles: `walk_cb` will be executed with the given `arg`.
diff --git a/3rdparty/libuv/docs/src/migration_010_100.rst b/3rdparty/libuv/docs/src/migration_010_100.rst
new file mode 100644
index 00000000000..bb6ac1a8092
--- /dev/null
+++ b/3rdparty/libuv/docs/src/migration_010_100.rst
@@ -0,0 +1,244 @@
+
+.. _migration_010_100:
+
+libuv 0.10 -> 1.0.0 migration guide
+===================================
+
+Some APIs changed quite a bit throughout the 1.0.0 development process. Here
+is a migration guide for the most significant changes that happened after 0.10
+was released.
+
+
+Loop initialization and closing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 (and previous versions), loops were created with `uv_loop_new`, which
+allocated memory for a new loop and initialized it; and destroyed with `uv_loop_delete`,
+which destroyed the loop and freed the memory. Starting with 1.0, those are deprecated
+and the user is responsible for allocating the memory and then initializing the loop.
+
+libuv 0.10
+
+::
+
+ uv_loop_t* loop = uv_loop_new();
+ ...
+ uv_loop_delete(loop);
+
+libuv 1.0
+
+::
+
+ uv_loop_t* loop = malloc(sizeof *loop);
+ uv_loop_init(loop);
+ ...
+ uv_loop_close(loop);
+ free(loop);
+
+.. note::
+ Error handling was omitted for brevity. Check the documentation for :c:func:`uv_loop_init`
+ and :c:func:`uv_loop_close`.
+
+
+Error handling
+~~~~~~~~~~~~~~
+
+Error handling had a major overhaul in libuv 1.0. In general, functions and status parameters
+would get 0 for success and -1 for failure on libuv 0.10, and the user had to use `uv_last_error`
+to fetch the error code, which was a positive number.
+
+In 1.0, functions and status parameters contain the actual error code, which is 0 for success, or
+a negative number in case of error.
+
+libuv 0.10
+
+::
+
+ ... assume 'server' is a TCP server which is already listening
+ r = uv_listen((uv_stream_t*) server, 511, NULL);
+ if (r == -1) {
+ uv_err_t err = uv_last_error(uv_default_loop());
+ /* err.code contains UV_EADDRINUSE */
+ }
+
+libuv 1.0
+
+::
+
+ ... assume 'server' is a TCP server which is already listening
+ r = uv_listen((uv_stream_t*) server, 511, NULL);
+ if (r < 0) {
+ /* r contains UV_EADDRINUSE */
+ }
+
+
+Threadpool changes
+~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 Unix used a threadpool which defaulted to 4 threads, while Windows used the
+`QueueUserWorkItem` API, which uses a Windows internal threadpool, which defaults to 512
+threads per process.
+
+In 1.0, we unified both implementations, so Windows now uses the same implementation Unix
+does. The threadpool size can be set by exporting the ``UV_THREADPOOL_SIZE`` environment
+variable. See :c:ref:`threadpool`.
+
+
+Allocation callback API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 the callback had to return a filled :c:type:`uv_buf_t` by value:
+
+::
+
+ uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
+ return uv_buf_init(malloc(size), size);
+ }
+
+In libuv 1.0 a pointer to a buffer is passed to the callback, which the user
+needs to fill:
+
+::
+
+ void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+ }
+
+
+Unification of IPv4 / IPv6 APIs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+libuv 1.0 unified the IPv4 and IPv6 APIS. There is no longer a `uv_tcp_bind` and `uv_tcp_bind6`
+duality, there is only :c:func:`uv_tcp_bind` now.
+
+IPv4 functions took ``struct sockaddr_in`` structures by value, and IPv6 functions took
+``struct sockaddr_in6``. Now functions take a ``struct sockaddr*`` (note it's a pointer).
+It can be stack allocated.
+
+libuv 0.10
+
+::
+
+ struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", 1234);
+ ...
+ uv_tcp_bind(&server, addr)
+
+libuv 1.0
+
+::
+
+ struct sockaddr_in addr;
+ uv_ip4_addr("0.0.0.0", 1234, &addr)
+ ...
+ uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+
+The IPv4 and IPv6 struct creating functions (:c:func:`uv_ip4_addr` and :c:func:`uv_ip6_addr`)
+have also changed, make sure you check the documentation.
+
+..note::
+ This change applies to all functions that made a distinction between IPv4 and IPv6
+ addresses.
+
+
+Streams / UDP data receive callback API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The streams and UDP data receive callbacks now get a pointer to a :c:type:`uv_buf_t` buffer,
+not a structure by value.
+
+libuv 0.10
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ uv_buf_t buf) {
+ ...
+ }
+
+ void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ uv_buf_t buf,
+ struct sockaddr* addr,
+ unsigned flags) {
+ ...
+ }
+
+libuv 1.0
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ...
+ }
+
+ void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ...
+ }
+
+
+Receiving handles over pipes API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 (and earlier versions) the `uv_read2_start` function was used to start reading
+data on a pipe, which could also result in the reception of handles over it. The callback
+for such function looked like this:
+
+::
+
+ void on_read(uv_pipe_t* pipe,
+ ssize_t nread,
+ uv_buf_t buf,
+ uv_handle_type pending) {
+ ...
+ }
+
+In libuv 1.0, `uv_read2_start` was removed, and the user needs to check if there are pending
+handles using :c:func:`uv_pipe_pending_count` and :c:func:`uv_pipe_pending_type` while in
+the read callback:
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ...
+ while (uv_pipe_pending_count((uv_pipe_t*) handle) != 0) {
+ pending = uv_pipe_pending_type((uv_pipe_t*) handle);
+ ...
+ }
+ ...
+ }
+
+
+Extracting the file descriptor out of a handle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+While it wasn't supported by the API, users often accessed the libuv internals in
+order to get access to the file descriptor of a TCP handle, for example.
+
+::
+
+ fd = handle->io_watcher.fd;
+
+This is now properly exposed through the :c:func:`uv_fileno` function.
+
+
+uv_fs_readdir rename and API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`uv_fs_readdir` returned a list of strings in the `req->ptr` field upon completion in
+libuv 0.10. In 1.0, this function got renamed to :c:func:`uv_fs_scandir`, since it's
+actually implemented using ``scandir(3)``.
+
+In addition, instead of allocating a full list strings, the user is able to get one
+result at a time by using the :c:func:`uv_fs_scandir_next` function. This function
+does not need to make a roundtrip to the threadpool, because libuv will keep the
+list of *dents* returned by ``scandir(3)`` around.
diff --git a/3rdparty/libuv/docs/src/misc.rst b/3rdparty/libuv/docs/src/misc.rst
new file mode 100644
index 00000000000..2ce0887db0c
--- /dev/null
+++ b/3rdparty/libuv/docs/src/misc.rst
@@ -0,0 +1,328 @@
+
+.. _misc:
+
+Miscellaneous utilities
+=======================
+
+This section contains miscellaneous functions that don't really belong in any
+other section.
+
+
+Data types
+----------
+
+.. c:type:: uv_buf_t
+
+ Buffer data type.
+
+ .. c:member:: char* uv_buf_t.base
+
+ Pointer to the base of the buffer. Readonly.
+
+ .. c:member:: size_t uv_buf_t.len
+
+ Total bytes in the buffer. Readonly.
+
+ .. note::
+ On Windows this field is ULONG.
+
+.. c:type:: void* (*uv_malloc_func)(size_t size)
+
+ Replacement function for :man:`malloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void* (*uv_realloc_func)(void* ptr, size_t size)
+
+ Replacement function for :man:`realloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void* (*uv_calloc_func)(size_t count, size_t size)
+
+ Replacement function for :man:`calloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void (*uv_free_func)(void* ptr)
+
+ Replacement function for :man:`free(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: uv_file
+
+ Cross platform representation of a file handle.
+
+.. c:type:: uv_os_sock_t
+
+ Cross platform representation of a socket handle.
+
+.. c:type:: uv_os_fd_t
+
+ Abstract representation of a file descriptor. On Unix systems this is a
+ `typedef` of `int` and on Windows a `HANDLE`.
+
+.. c:type:: uv_rusage_t
+
+ Data type for resource usage results.
+
+ ::
+
+ typedef struct {
+ uv_timeval_t ru_utime; /* user CPU time used */
+ uv_timeval_t ru_stime; /* system CPU time used */
+ uint64_t ru_maxrss; /* maximum resident set size */
+ uint64_t ru_ixrss; /* integral shared memory size */
+ uint64_t ru_idrss; /* integral unshared data size */
+ uint64_t ru_isrss; /* integral unshared stack size */
+ uint64_t ru_minflt; /* page reclaims (soft page faults) */
+ uint64_t ru_majflt; /* page faults (hard page faults) */
+ uint64_t ru_nswap; /* swaps */
+ uint64_t ru_inblock; /* block input operations */
+ uint64_t ru_oublock; /* block output operations */
+ uint64_t ru_msgsnd; /* IPC messages sent */
+ uint64_t ru_msgrcv; /* IPC messages received */
+ uint64_t ru_nsignals; /* signals received */
+ uint64_t ru_nvcsw; /* voluntary context switches */
+ uint64_t ru_nivcsw; /* involuntary context switches */
+ } uv_rusage_t;
+
+.. c:type:: uv_cpu_info_t
+
+ Data type for CPU information.
+
+ ::
+
+ typedef struct uv_cpu_info_s {
+ char* model;
+ int speed;
+ struct uv_cpu_times_s {
+ uint64_t user;
+ uint64_t nice;
+ uint64_t sys;
+ uint64_t idle;
+ uint64_t irq;
+ } cpu_times;
+ } uv_cpu_info_t;
+
+.. c:type:: uv_interface_address_t
+
+ Data type for interface addresses.
+
+ ::
+
+ typedef struct uv_interface_address_s {
+ char* name;
+ char phys_addr[6];
+ int is_internal;
+ union {
+ struct sockaddr_in address4;
+ struct sockaddr_in6 address6;
+ } address;
+ union {
+ struct sockaddr_in netmask4;
+ struct sockaddr_in6 netmask6;
+ } netmask;
+ } uv_interface_address_t;
+
+
+API
+---
+
+.. c:function:: uv_handle_type uv_guess_handle(uv_file file)
+
+ Used to detect what type of stream should be used with a given file
+ descriptor. Usually this will be used during initialization to guess the
+ type of the stdio streams.
+
+ For :man:`isatty(3)` equivalent functionality use this function and test
+ for ``UV_TTY``.
+
+.. c:function:: int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, uv_free_func free_func)
+
+ .. versionadded:: 1.6.0
+
+ Override the use of the standard library's :man:`malloc(3)`,
+ :man:`calloc(3)`, :man:`realloc(3)`, :man:`free(3)`, memory allocation
+ functions.
+
+ This function must be called before any other libuv function is called or
+ after all resources have been freed and thus libuv doesn't reference
+ any allocated memory chunk.
+
+ On success, it returns 0, if any of the function pointers is NULL it
+ returns UV_EINVAL.
+
+ .. warning:: There is no protection against changing the allocator multiple
+ times. If the user changes it they are responsible for making
+ sure the allocator is changed while no memory was allocated with
+ the previous allocator, or that they are compatible.
+
+.. c:function:: uv_buf_t uv_buf_init(char* base, unsigned int len)
+
+ Constructor for :c:type:`uv_buf_t`.
+
+ Due to platform differences the user cannot rely on the ordering of the
+ `base` and `len` members of the uv_buf_t struct. The user is responsible for
+ freeing `base` after the uv_buf_t is done. Return struct passed by value.
+
+.. c:function:: char** uv_setup_args(int argc, char** argv)
+
+ Store the program arguments. Required for getting / setting the process title.
+
+.. c:function:: int uv_get_process_title(char* buffer, size_t size)
+
+ Gets the title of the current process.
+
+.. c:function:: int uv_set_process_title(const char* title)
+
+ Sets the current process title.
+
+.. c:function:: int uv_resident_set_memory(size_t* rss)
+
+ Gets the resident set size (RSS) for the current process.
+
+.. c:function:: int uv_uptime(double* uptime)
+
+ Gets the current system uptime.
+
+.. c:function:: int uv_getrusage(uv_rusage_t* rusage)
+
+ Gets the resource usage measures for the current process.
+
+ .. note::
+ On Windows not all fields are set, the unsupported fields are filled with zeroes.
+
+.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count)
+
+ Gets information about the CPUs on the system. The `cpu_infos` array will
+ have `count` elements and needs to be freed with :c:func:`uv_free_cpu_info`.
+
+.. c:function:: void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count)
+
+ Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`.
+
+.. c:function:: int uv_interface_addresses(uv_interface_address_t** addresses, int* count)
+
+ Gets address information about the network interfaces on the system. An
+ array of `count` elements is allocated and returned in `addresses`. It must
+ be freed by the user, calling :c:func:`uv_free_interface_addresses`.
+
+.. c:function:: void uv_free_interface_addresses(uv_interface_address_t* addresses, int count)
+
+ Free an array of :c:type:`uv_interface_address_t` which was returned by
+ :c:func:`uv_interface_addresses`.
+
+.. c:function:: void uv_loadavg(double avg[3])
+
+ Gets the load average. See: `<http://en.wikipedia.org/wiki/Load_(computing)>`_
+
+ .. note::
+ Returns [0,0,0] on Windows (i.e., it's not implemented).
+
+.. c:function:: int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr)
+
+ Convert a string containing an IPv4 addresses to a binary structure.
+
+.. c:function:: int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr)
+
+ Convert a string containing an IPv6 addresses to a binary structure.
+
+.. c:function:: int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size)
+
+ Convert a binary structure containing an IPv4 address to a string.
+
+.. c:function:: int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size)
+
+ Convert a binary structure containing an IPv6 address to a string.
+
+.. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size)
+.. c:function:: int uv_inet_pton(int af, const char* src, void* dst)
+
+ Cross-platform IPv6-capable implementation of :man:`inet_ntop(3)`
+ and :man:`inet_pton(3)`. On success they return 0. In case of error
+ the target `dst` pointer is unmodified.
+
+.. c:function:: int uv_exepath(char* buffer, size_t* size)
+
+ Gets the executable path.
+
+.. c:function:: int uv_cwd(char* buffer, size_t* size)
+
+ Gets the current working directory.
+
+ .. versionchanged:: 1.1.0
+
+ On Unix the path no longer ends in a slash.
+
+.. c:function:: int uv_chdir(const char* dir)
+
+ Changes the current working directory.
+
+.. c:function:: int uv_os_homedir(char* buffer, size_t* size)
+
+ Gets the current user's home directory. On Windows, `uv_os_homedir()` first
+ checks the `USERPROFILE` environment variable using
+ `GetEnvironmentVariableW()`. If `USERPROFILE` is not set,
+ `GetUserProfileDirectoryW()` is called. On all other operating systems,
+ `uv_os_homedir()` first checks the `HOME` environment variable using
+ :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The
+ user's home directory is stored in `buffer`. When `uv_os_homedir()` is
+ called, `size` indicates the maximum size of `buffer`. On success or
+ `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`.
+
+ .. warning::
+ `uv_os_homedir()` is not thread safe.
+
+ .. versionadded:: 1.6.0
+
+.. uint64_t uv_get_free_memory(void)
+.. c:function:: uint64_t uv_get_total_memory(void)
+
+ Gets memory information (in bytes).
+
+.. c:function:: uint64_t uv_hrtime(void)
+
+ Returns the current high-resolution real time. This is expressed in
+ nanoseconds. It is relative to an arbitrary time in the past. It is not
+ related to the time of day and therefore not subject to clock drift. The
+ primary use is for measuring performance between intervals.
+
+ .. note::
+ Not every platform can support nanosecond resolution; however, this value will always
+ be in nanoseconds.
+
+.. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream)
+
+ Prints all handles associated with the given `loop` to the given `stream`.
+
+ Example:
+
+ ::
+
+ uv_print_all_handles(uv_default_loop(), stderr);
+ /*
+ [--I] signal 0x1a25ea8
+ [-AI] async 0x1a25cf0
+ [R--] idle 0x1a7a8c8
+ */
+
+ The format is `[flags] handle-type handle-address`. For `flags`:
+
+ - `R` is printed for a handle that is referenced
+ - `A` is printed for a handle that is active
+ - `I` is printed for a handle that is internal
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
+
+.. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream)
+
+ This is the same as :c:func:`uv_print_all_handles` except only active handles
+ are printed.
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
diff --git a/3rdparty/libuv/docs/src/pipe.rst b/3rdparty/libuv/docs/src/pipe.rst
new file mode 100644
index 00000000000..d33b0f2b977
--- /dev/null
+++ b/3rdparty/libuv/docs/src/pipe.rst
@@ -0,0 +1,104 @@
+
+.. _pipe:
+
+:c:type:`uv_pipe_t` --- Pipe handle
+===================================
+
+Pipe handles provide an abstraction over local domain sockets on Unix and named
+pipes on Windows.
+
+:c:type:`uv_pipe_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_pipe_t
+
+ Pipe handle type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)
+
+ Initialize a pipe handle. The `ipc` argument is a boolean to indicate if
+ this pipe will be used for handle passing between processes.
+
+.. c:function:: int uv_pipe_open(uv_pipe_t* handle, uv_file file)
+
+ Open an existing file descriptor or HANDLE as a pipe.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or HANDLE is not checked for its type, but
+ it's required that it represents a valid pipe.
+
+.. c:function:: int uv_pipe_bind(uv_pipe_t* handle, const char* name)
+
+ Bind the pipe to a file path (Unix) or a name (Windows).
+
+ .. note::
+ Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
+ 92 and 108 bytes.
+
+.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
+
+ Connect to the Unix domain socket or the named pipe.
+
+ .. note::
+ Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
+ 92 and 108 bytes.
+
+.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)
+
+ Get the name of the Unix domain socket or the named pipe.
+
+ A preallocated buffer must be provided. The size parameter holds the length
+ of the buffer and it's set to the number of bytes written to the buffer on
+ output. If the buffer is not big enough ``UV_ENOBUFS`` will be returned and
+ len will contain the required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. c:function:: int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size)
+
+ Get the name of the Unix domain socket or the named pipe to which the handle
+ is connected.
+
+ A preallocated buffer must be provided. The size parameter holds the length
+ of the buffer and it's set to the number of bytes written to the buffer on
+ output. If the buffer is not big enough ``UV_ENOBUFS`` will be returned and
+ len will contain the required size.
+
+ .. versionadded:: 1.3.0
+
+.. c:function:: void uv_pipe_pending_instances(uv_pipe_t* handle, int count)
+
+ Set the number of pending pipe instance handles when the pipe server is
+ waiting for connections.
+
+ .. note::
+ This setting applies to Windows only.
+
+.. c:function:: int uv_pipe_pending_count(uv_pipe_t* handle)
+.. c:function:: uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle)
+
+ Used to receive handles over IPC pipes.
+
+ First - call :c:func:`uv_pipe_pending_count`, if it's > 0 then initialize
+ a handle of the given `type`, returned by :c:func:`uv_pipe_pending_type`
+ and call ``uv_accept(pipe, handle)``.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/poll.rst b/3rdparty/libuv/docs/src/poll.rst
new file mode 100644
index 00000000000..6dc41839ac1
--- /dev/null
+++ b/3rdparty/libuv/docs/src/poll.rst
@@ -0,0 +1,103 @@
+
+.. _poll:
+
+:c:type:`uv_poll_t` --- Poll handle
+===================================
+
+Poll handles are used to watch file descriptors for readability and
+writability, similar to the purpose of :man:`poll(2)`.
+
+The purpose of poll handles is to enable integrating external libraries that
+rely on the event loop to signal it about the socket status changes, like
+c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended;
+:c:type:`uv_tcp_t`, :c:type:`uv_udp_t`, etc. provide an implementation that is faster and
+more scalable than what can be achieved with :c:type:`uv_poll_t`, especially on
+Windows.
+
+It is possible that poll handles occasionally signal that a file descriptor is
+readable or writable even when it isn't. The user should therefore always
+be prepared to handle EAGAIN or equivalent when it attempts to read from or
+write to the fd.
+
+It is not okay to have multiple active poll handles for the same socket, this
+can cause libuv to busyloop or otherwise malfunction.
+
+The user should not close a file descriptor while it is being polled by an
+active poll handle. This can cause the handle to report an error,
+but it might also start polling another socket. However the fd can be safely
+closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`.
+
+.. note::
+ On windows only sockets can be polled with poll handles. On Unix any file
+ descriptor that would be accepted by :man:`poll(2)` can be used.
+
+
+Data types
+----------
+
+.. c:type:: uv_poll_t
+
+ Poll handle type.
+
+.. c:type:: void (*uv_poll_cb)(uv_poll_t* handle, int status, int events)
+
+ Type definition for callback passed to :c:func:`uv_poll_start`.
+
+.. c:type:: uv_poll_event
+
+ Poll event types
+
+ ::
+
+ enum uv_poll_event {
+ UV_READABLE = 1,
+ UV_WRITABLE = 2
+ };
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd)
+
+ Initialize the handle using a file descriptor.
+
+ .. versionchanged:: 1.2.2 the file descriptor is set to non-blocking mode.
+
+.. c:function:: int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket)
+
+ Initialize the handle using a socket descriptor. On Unix this is identical
+ to :c:func:`uv_poll_init`. On windows it takes a SOCKET handle.
+
+ .. versionchanged:: 1.2.2 the socket is set to non-blocking mode.
+
+.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
+
+ Starts polling the file descriptor. `events` is a bitmask consisting made up
+ of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback
+ will be called with `status` set to 0, and the detected events set on the
+ `events` field.
+
+ If an error happens while polling, `status` will be < 0 and corresponds
+ with one of the UV_E* error codes (see :ref:`errors`). The user should
+ not close the socket while the handle is active. If the user does that
+ anyway, the callback *may* be called reporting an error status, but this
+ is **not** guaranteed.
+
+ .. note::
+ Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so
+ will update the events mask that is being watched for.
+
+.. c:function:: int uv_poll_stop(uv_poll_t* poll)
+
+ Stop polling the file descriptor, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/prepare.rst b/3rdparty/libuv/docs/src/prepare.rst
new file mode 100644
index 00000000000..aca58155809
--- /dev/null
+++ b/3rdparty/libuv/docs/src/prepare.rst
@@ -0,0 +1,46 @@
+
+.. _prepare:
+
+:c:type:`uv_prepare_t` --- Prepare handle
+=========================================
+
+Prepare handles will run the given callback once per loop iteration, right
+before polling for i/o.
+
+
+Data types
+----------
+
+.. c:type:: uv_prepare_t
+
+ Prepare handle type.
+
+.. c:type:: void (*uv_prepare_cb)(uv_prepare_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_prepare_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare)
+
+ Initialize the handle.
+
+.. c:function:: int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_prepare_stop(uv_prepare_t* prepare)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/process.rst b/3rdparty/libuv/docs/src/process.rst
new file mode 100644
index 00000000000..b0380ddfb72
--- /dev/null
+++ b/3rdparty/libuv/docs/src/process.rst
@@ -0,0 +1,225 @@
+
+.. _process:
+
+:c:type:`uv_process_t` --- Process handle
+=========================================
+
+Process handles will spawn a new process and allow the user to control it and
+establish communication channels with it using streams.
+
+
+Data types
+----------
+
+.. c:type:: uv_process_t
+
+ Process handle type.
+
+.. c:type:: uv_process_options_t
+
+ Options for spawning the process (passed to :c:func:`uv_spawn`.
+
+ ::
+
+ typedef struct uv_process_options_s {
+ uv_exit_cb exit_cb;
+ const char* file;
+ char** args;
+ char** env;
+ const char* cwd;
+ unsigned int flags;
+ int stdio_count;
+ uv_stdio_container_t* stdio;
+ uv_uid_t uid;
+ uv_gid_t gid;
+ } uv_process_options_t;
+
+.. c:type:: void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal)
+
+ Type definition for callback passed in :c:type:`uv_process_options_t` which
+ will indicate the exit status and the signal that caused the process to
+ terminate, if any.
+
+.. c:type:: uv_process_flags
+
+ Flags to be set on the flags field of :c:type:`uv_process_options_t`.
+
+ ::
+
+ enum uv_process_flags {
+ /*
+ * Set the child process' user id.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On Unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
+ /*
+ * Spawn the child process in a detached state - this will make it a process
+ * group leader, and will effectively enable the child to keep running after
+ * the parent exits. Note that the child process will still keep the
+ * parent's event loop alive unless the parent process calls uv_unref() on
+ * the child's process handle.
+ */
+ UV_PROCESS_DETACHED = (1 << 3),
+ /*
+ * Hide the subprocess console window that would normally be created. This
+ * option is only meaningful on Windows systems. On Unix it is silently
+ * ignored.
+ */
+ UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+ };
+
+.. c:type:: uv_stdio_container_t
+
+ Container for each stdio handle or fd passed to a child process.
+
+ ::
+
+ typedef struct uv_stdio_container_s {
+ uv_stdio_flags flags;
+ union {
+ uv_stream_t* stream;
+ int fd;
+ } data;
+ } uv_stdio_container_t;
+
+.. c:type:: uv_stdio_flags
+
+ Flags specifying how a stdio should be transmitted to the child process.
+
+ ::
+
+ typedef enum {
+ UV_IGNORE = 0x00,
+ UV_CREATE_PIPE = 0x01,
+ UV_INHERIT_FD = 0x02,
+ UV_INHERIT_STREAM = 0x04,
+ /*
+ * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
+ * determine the direction of flow, from the child process' perspective. Both
+ * flags may be specified to create a duplex data stream.
+ */
+ UV_READABLE_PIPE = 0x10,
+ UV_WRITABLE_PIPE = 0x20
+ } uv_stdio_flags;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_process_t.pid
+
+ The PID of the spawned process. It's set after calling :c:func:`uv_spawn`.
+
+.. note::
+ The :c:type:`uv_handle_t` members also apply.
+
+.. c:member:: uv_process_options_t.exit_cb
+
+ Callback called after the process exits.
+
+.. c:member:: uv_process_options_t.file
+
+ Path pointing to the program to be executed.
+
+.. c:member:: uv_process_options_t.args
+
+ Command line arguments. args[0] should be the path to the program. On
+ Windows this uses `CreateProcess` which concatenates the arguments into a
+ string this can cause some strange errors. See the
+ ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`.
+
+.. c:member:: uv_process_options_t.env
+
+ Environment for the new process. If NULL the parents environment is used.
+
+.. c:member:: uv_process_options_t.cwd
+
+ Current working directory for the subprocess.
+
+.. c:member:: uv_process_options_t.flags
+
+ Various flags that control how :c:func:`uv_spawn` behaves. See
+ :c:type:`uv_process_flags`.
+
+.. c:member:: uv_process_options_t.stdio_count
+.. c:member:: uv_process_options_t.stdio
+
+ The `stdio` field points to an array of :c:type:`uv_stdio_container_t`
+ structs that describe the file descriptors that will be made available to
+ the child process. The convention is that stdio[0] points to stdin,
+ fd 1 is used for stdout, and fd 2 is stderr.
+
+ .. note::
+ On Windows file descriptors greater than 2 are available to the child process only if
+ the child processes uses the MSVCRT runtime.
+
+.. c:member:: uv_process_options_t.uid
+.. c:member:: uv_process_options_t.gid
+
+ Libuv can change the child process' user/group id. This happens only when
+ the appropriate bits are set in the flags fields.
+
+ .. note::
+ This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error
+ to ``UV_ENOTSUP``.
+
+.. c:member:: uv_stdio_container_t.flags
+
+ Flags specifying how the stdio container should be passed to the child. See
+ :c:type:`uv_stdio_flags`.
+
+.. c:member:: uv_stdio_container_t.data
+
+ Union containing either the stream or fd to be passed on to the child
+ process.
+
+
+API
+---
+
+.. c:function:: void uv_disable_stdio_inheritance(void)
+
+ Disables inheritance for file descriptors / handles that this process
+ inherited from its parent. The effect is that child processes spawned by
+ this process don't accidentally inherit these handles.
+
+ It is recommended to call this function as early in your program as possible,
+ before the inherited file descriptors can be closed or duplicated.
+
+ .. note::
+ This function works on a best-effort basis: there is no guarantee that libuv can discover
+ all file descriptors that were inherited. In general it does a better job on Windows than
+ it does on Unix.
+
+.. c:function:: int uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options)
+
+ Initializes the process handle and starts the process. If the process is
+ successfully spawned, this function will return 0. Otherwise, the
+ negative error code corresponding to the reason it couldn't spawn is
+ returned.
+
+ Possible reasons for failing to spawn would include (but not be limited to)
+ the file to execute not existing, not having permissions to use the setuid or
+ setgid specified, or not having enough memory to allocate for the new
+ process.
+
+.. c:function:: int uv_process_kill(uv_process_t* handle, int signum)
+
+ Sends the specified signal to the given process handle. Check the documentation
+ on :c:ref:`signal` for signal support, specially on Windows.
+
+.. c:function:: int uv_kill(int pid, int signum)
+
+ Sends the specified signal to the given PID. Check the documentation
+ on :c:ref:`signal` for signal support, specially on Windows.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/request.rst b/3rdparty/libuv/docs/src/request.rst
new file mode 100644
index 00000000000..660b80ae957
--- /dev/null
+++ b/3rdparty/libuv/docs/src/request.rst
@@ -0,0 +1,82 @@
+
+.. _request:
+
+:c:type:`uv_req_t` --- Base request
+===================================
+
+`uv_req_t` is the base type for all libuv request types.
+
+Structures are aligned so that any libuv request can be cast to `uv_req_t`.
+All API functions defined here work with any request type.
+
+
+Data types
+----------
+
+.. c:type:: uv_req_t
+
+ The base libuv request structure.
+
+.. c:type:: uv_any_req
+
+ Union of all request types.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: void* uv_req_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field.
+
+.. c:member:: uv_req_type uv_req_t.type
+
+ Indicated the type of request. Readonly.
+
+ ::
+
+ typedef enum {
+ UV_UNKNOWN_REQ = 0,
+ UV_REQ,
+ UV_CONNECT,
+ UV_WRITE,
+ UV_SHUTDOWN,
+ UV_UDP_SEND,
+ UV_FS,
+ UV_WORK,
+ UV_GETADDRINFO,
+ UV_GETNAMEINFO,
+ UV_REQ_TYPE_PRIVATE,
+ UV_REQ_TYPE_MAX,
+ } uv_req_type;
+
+
+API
+---
+
+.. c:function:: int uv_cancel(uv_req_t* req)
+
+ Cancel a pending request. Fails if the request is executing or has finished
+ executing.
+
+ Returns 0 on success, or an error code < 0 on failure.
+
+ Only cancellation of :c:type:`uv_fs_t`, :c:type:`uv_getaddrinfo_t`,
+ :c:type:`uv_getnameinfo_t` and :c:type:`uv_work_t` requests is
+ currently supported.
+
+ Cancelled requests have their callbacks invoked some time in the future.
+ It's **not** safe to free the memory associated with the request until the
+ callback is called.
+
+ Here is how cancellation is reported to the callback:
+
+ * A :c:type:`uv_fs_t` request has its req->result field set to `UV_ECANCELED`.
+
+ * A :c:type:`uv_work_t`, :c:type:`uv_getaddrinfo_t` or c:type:`uv_getnameinfo_t`
+ request has its callback invoked with status == `UV_ECANCELED`.
+
+.. c:function:: size_t uv_req_size(uv_req_type type)
+
+ Returns the size of the given request type. Useful for FFI binding writers
+ who don't want to know the structure layout.
diff --git a/3rdparty/libuv/docs/src/signal.rst b/3rdparty/libuv/docs/src/signal.rst
new file mode 100644
index 00000000000..dc1223b90ac
--- /dev/null
+++ b/3rdparty/libuv/docs/src/signal.rst
@@ -0,0 +1,77 @@
+
+.. _signal:
+
+:c:type:`uv_signal_t` --- Signal handle
+=======================================
+
+Signal handles implement Unix style signal handling on a per-event loop bases.
+
+Reception of some signals is emulated on Windows:
+
+* SIGINT is normally delivered when the user presses CTRL+C. However, like
+ on Unix, it is not generated when terminal raw mode is enabled.
+
+* SIGBREAK is delivered when the user pressed CTRL + BREAK.
+
+* SIGHUP is generated when the user closes the console window. On SIGHUP the
+ program is given approximately 10 seconds to perform cleanup. After that
+ Windows will unconditionally terminate it.
+
+* SIGWINCH is raised whenever libuv detects that the console has been
+ resized. SIGWINCH is emulated by libuv when the program uses a :c:type:`uv_tty_t`
+ handle to write to the console. SIGWINCH may not always be delivered in a
+ timely manner; libuv will only detect size changes when the cursor is
+ being moved. When a readable :c:type:`uv_tty_t` handle is used in raw mode,
+ resizing the console buffer will also trigger a SIGWINCH signal.
+
+Watchers for other signals can be successfully created, but these signals
+are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`,
+`SIGTERM` and `SIGKILL.`
+
+Calls to raise() or abort() to programmatically raise a signal are
+not detected by libuv; these will not trigger a signal watcher.
+
+.. note::
+ On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to
+ manage threads. Installing watchers for those signals will lead to unpredictable behavior
+ and is strongly discouraged. Future versions of libuv may simply reject them.
+
+
+Data types
+----------
+
+.. c:type:: uv_signal_t
+
+ Signal handle type.
+
+.. c:type:: void (*uv_signal_cb)(uv_signal_t* handle, int signum)
+
+ Type definition for callback passed to :c:func:`uv_signal_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: int uv_signal_t.signum
+
+ Signal being monitored by this handle. Readonly.
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_signal_init(uv_loop_t* loop, uv_signal_t* signal)
+
+ Initialize the handle.
+
+.. c:function:: int uv_signal_start(uv_signal_t* signal, uv_signal_cb cb, int signum)
+
+ Start the handle with the given callback, watching for the given signal.
+
+.. c:function:: int uv_signal_stop(uv_signal_t* signal)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py b/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py
new file mode 100644
index 00000000000..1d1dc379f41
--- /dev/null
+++ b/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py
@@ -0,0 +1,46 @@
+# encoding: utf-8
+
+#
+# Copyright (c) 2013 Dariusz Dwornikowski. All rights reserved.
+#
+# Adapted from https://github.com/tdi/sphinxcontrib-manpage
+# License: Apache 2
+#
+
+
+import re
+
+from docutils import nodes, utils
+from docutils.parsers.rst.roles import set_classes
+from string import Template
+
+
+def make_link_node(rawtext, app, name, manpage_num, options):
+ ref = app.config.man_url_regex
+ if not ref:
+ ref = "http://linux.die.net/man/%s/%s" % (manpage_num, name)
+ else:
+ s = Template(ref)
+ ref = s.substitute(num=manpage_num, topic=name)
+ set_classes(options)
+ node = nodes.reference(rawtext, "%s(%s)" % (name, manpage_num), refuri=ref, **options)
+ return node
+
+
+def man_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ app = inliner.document.settings.env.app
+ p = re.compile("([a-zA-Z0-9_\.-_]+)\((\d)\)")
+ m = p.match(text)
+
+ manpage_num = m.group(2)
+ name = m.group(1)
+ node = make_link_node(rawtext, app, name, manpage_num, options)
+ return [node], []
+
+
+def setup(app):
+ app.info('Initializing manpage plugin')
+ app.add_role('man', man_role)
+ app.add_config_value('man_url_regex', None, 'env')
+ return
+
diff --git a/3rdparty/libuv/docs/src/static/architecture.png b/3rdparty/libuv/docs/src/static/architecture.png
new file mode 100644
index 00000000000..81e8749f249
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/architecture.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg
new file mode 100644
index 00000000000..439f5810936
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg
new file mode 100644
index 00000000000..ffb21ff2245
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip b/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip
new file mode 100644
index 00000000000..17aedace14f
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist
new file mode 100644
index 00000000000..39dd4fe62fb
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <string>Template: White (2014-02-28 09:41)</string>
+ <string>M6.2.2-1878-1</string>
+</array>
+</plist>
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier
new file mode 100644
index 00000000000..ddb18f01f99
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier
@@ -0,0 +1 @@
+F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA \ No newline at end of file
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist
new file mode 100644
index 00000000000..74bc69317de
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg
new file mode 100644
index 00000000000..dd8decd6303
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg
new file mode 100644
index 00000000000..aadd401f1f0
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg
new file mode 100644
index 00000000000..fc80025a4be
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/favicon.ico b/3rdparty/libuv/docs/src/static/favicon.ico
new file mode 100644
index 00000000000..2c40694cd28
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/favicon.ico
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/logo.png b/3rdparty/libuv/docs/src/static/logo.png
new file mode 100644
index 00000000000..eaf1eee577b
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/logo.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/loop_iteration.png b/3rdparty/libuv/docs/src/static/loop_iteration.png
new file mode 100644
index 00000000000..e769cf338b4
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/loop_iteration.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/stream.rst b/3rdparty/libuv/docs/src/stream.rst
new file mode 100644
index 00000000000..9f0aacd1643
--- /dev/null
+++ b/3rdparty/libuv/docs/src/stream.rst
@@ -0,0 +1,219 @@
+
+.. _stream:
+
+:c:type:`uv_stream_t` --- Stream handle
+=======================================
+
+Stream handles provide an abstraction of a duplex communication channel.
+:c:type:`uv_stream_t` is an abstract type, libuv provides 3 stream implementations
+in the for of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_stream_t
+
+ Stream handle type.
+
+.. c:type:: uv_connect_t
+
+ Connect request type.
+
+.. c:type:: uv_shutdown_t
+
+ Shutdown request type.
+
+.. c:type:: uv_write_t
+
+ Write request type.
+
+.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
+
+ Callback called when data was read on a stream.
+
+ `nread` is > 0 if there is data available or < 0 on error. When we've
+ reached EOF, `nread` will be set to ``UV_EOF``. When `nread` < 0,
+ the `buf` parameter might not point to a valid buffer; in that case
+ `buf.len` and `buf.base` are both set to 0.
+
+ .. note::
+ `nread` might be 0, which does *not* indicate an error or EOF. This
+ is equivalent to ``EAGAIN`` or ``EWOULDBLOCK`` under ``read(2)``.
+
+ The callee is responsible for stopping closing the stream when an error happens
+ by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read
+ from the stream again is undefined.
+
+ The callee is responsible for freeing the buffer, libuv does not reuse it.
+ The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on
+ error.
+
+.. c:type:: void (*uv_write_cb)(uv_write_t* req, int status)
+
+ Callback called after data was written on a stream. `status` will be 0 in
+ case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_connect_cb)(uv_connect_t* req, int status)
+
+ Callback called after a connection started by :c:func:`uv_connect` is done.
+ `status` will be 0 in case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
+
+ Callback called after s shutdown request has been completed. `status` will
+ be 0 in case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
+
+ Callback called when a stream server has received an incoming connection.
+ The user can accept the connection by calling :c:func:`uv_accept`.
+ `status` will be 0 in case of success, < 0 otherwise.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: size_t uv_stream_t.write_queue_size
+
+ Contains the amount of queued bytes waiting to be sent. Readonly.
+
+.. c:member:: uv_stream_t* uv_connect_t.handle
+
+ Pointer to the stream where this connection request is running.
+
+.. c:member:: uv_stream_t* uv_shutdown_t.handle
+
+ Pointer to the stream where this shutdown request is running.
+
+.. c:member:: uv_stream_t* uv_write_t.handle
+
+ Pointer to the stream where this write request is running.
+
+.. c:member:: uv_stream_t* uv_write_t.send_handle
+
+ Pointer to the stream being sent using this write request..
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb)
+
+ Shutdown the outgoing (write) side of a duplex stream. It waits for pending
+ write requests to complete. The `handle` should refer to a initialized stream.
+ `req` should be an uninitialized shutdown request struct. The `cb` is called
+ after shutdown is complete.
+
+.. c:function:: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
+
+ Start listening for incoming connections. `backlog` indicates the number of
+ connections the kernel might queue, same as :man:`listen(2)`. When a new
+ incoming connection is received the :c:type:`uv_connection_cb` callback is
+ called.
+
+.. c:function:: int uv_accept(uv_stream_t* server, uv_stream_t* client)
+
+ This call is used in conjunction with :c:func:`uv_listen` to accept incoming
+ connections. Call this function after receiving a :c:type:`uv_connection_cb`
+ to accept the connection. Before calling this function the client handle must
+ be initialized. < 0 return value indicates an error.
+
+ When the :c:type:`uv_connection_cb` callback is called it is guaranteed that
+ this function will complete successfully the first time. If you attempt to use
+ it more than once, it may fail. It is suggested to only call this function once
+ per :c:type:`uv_connection_cb` call.
+
+ .. note::
+ `server` and `client` must be handles running on the same loop.
+
+.. c:function:: int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
+
+ Read data from an incoming stream. The :c:type:`uv_read_cb` callback will
+ be made several times until there is no more data to read or
+ :c:func:`uv_read_stop` is called.
+
+.. c:function:: int uv_read_stop(uv_stream_t*)
+
+ Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
+ no longer be called.
+
+ This function is idempotent and may be safely called on a stopped stream.
+
+.. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
+
+ Write data to stream. Buffers are written in order. Example:
+
+ ::
+
+ uv_buf_t a[] = {
+ { .base = "1", .len = 1 },
+ { .base = "2", .len = 1 }
+ };
+
+ uv_buf_t b[] = {
+ { .base = "3", .len = 1 },
+ { .base = "4", .len = 1 }
+ };
+
+ uv_write_t req1;
+ uv_write_t req2;
+
+ /* writes "1234" */
+ uv_write(&req1, stream, a, 2);
+ uv_write(&req2, stream, b, 2);
+
+.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
+
+ Extended write function for sending handles over a pipe. The pipe must be
+ initialized with `ipc` == 1.
+
+ .. note::
+ `send_handle` must be a TCP socket or pipe, which is a server or a connection (listening
+ or connected state). Bound sockets or pipes will be assumed to be servers.
+
+.. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)
+
+ Same as :c:func:`uv_write`, but won't queue a write request if it can't be
+ completed immediately.
+
+ Will return either:
+
+ * > 0: number of bytes written (can be less than the supplied buffer size).
+ * < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent
+ immediately).
+
+.. c:function:: int uv_is_readable(const uv_stream_t* handle)
+
+ Returns 1 if the stream is readable, 0 otherwise.
+
+.. c:function:: int uv_is_writable(const uv_stream_t* handle)
+
+ Returns 1 if the stream is writable, 0 otherwise.
+
+.. c:function:: int uv_stream_set_blocking(uv_stream_t* handle, int blocking)
+
+ Enable or disable blocking mode for a stream.
+
+ When blocking mode is enabled all writes complete synchronously. The
+ interface remains unchanged otherwise, e.g. completion or failure of the
+ operation will still be reported through a callback which is made
+ asynchronously.
+
+ .. warning::
+ Relying too much on this API is not recommended. It is likely to change
+ significantly in the future.
+
+ Currently only works on Windows for :c:type:`uv_pipe_t` handles.
+ On UNIX platforms, all :c:type:`uv_stream_t` handles are supported.
+
+ Also libuv currently makes no ordering guarantee when the blocking mode
+ is changed after write requests have already been submitted. Therefore it is
+ recommended to set the blocking mode immediately after opening or creating
+ the stream.
+
+ .. versionchanged:: 1.4.0 UNIX implementation added.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/tcp.rst b/3rdparty/libuv/docs/src/tcp.rst
new file mode 100644
index 00000000000..ca0c9b4ac5a
--- /dev/null
+++ b/3rdparty/libuv/docs/src/tcp.rst
@@ -0,0 +1,108 @@
+
+.. _tcp:
+
+:c:type:`uv_tcp_t` --- TCP handle
+=================================
+
+TCP handles are used to represent both TCP streams and servers.
+
+:c:type:`uv_tcp_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_tcp_t
+
+ TCP handle type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle)
+
+ Initialize the handle. No socket is created as of yet.
+
+.. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags)
+
+ Initialize the handle with the specified flags. At the moment only the lower 8 bits
+ of the `flags` parameter are used as the socket domain. A socket will be created
+ for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
+ just like :c:func:`uv_tcp_init`.
+
+ .. versionadded:: 1.7.0
+
+.. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
+
+ Open an existing file descriptor or SOCKET as a TCP handle.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or SOCKET is not checked for its type, but
+ it's required that it represents a valid stream socket.
+
+.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
+
+ Enable / disable Nagle's algorithm.
+
+.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
+
+ Enable / disable TCP keep-alive. `delay` is the initial delay in seconds,
+ ignored when `enable` is zero.
+
+.. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable)
+
+ Enable / disable simultaneous asynchronous accept requests that are
+ queued by the operating system when listening for new TCP connections.
+
+ This setting is used to tune a TCP server for the desired performance.
+ Having simultaneous accepts can significantly improve the rate of accepting
+ connections (which is why it is enabled by default) but may lead to uneven
+ load distribution in multi-process setups.
+
+.. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags)
+
+ Bind the handle to an address and port. `addr` should point to an
+ initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
+
+ When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
+ error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or
+ :c:func:`uv_tcp_connect`. That is, a successful call to this function does
+ not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect`
+ will succeed as well.
+
+ `flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
+ is disabled and only IPv6 is used.
+
+.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the current address to which the handle is bound. `addr` must point to
+ a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
+ recommended for IPv4 and IPv6 support.
+
+.. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the address of the peer connected to the handle. `addr` must point to
+ a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
+ recommended for IPv4 and IPv6 support.
+
+.. c:function:: int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, uv_connect_cb cb)
+
+ Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle
+ and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an
+ initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
+
+ The callback is made when the connection has been established or when a
+ connection error happened.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/threading.rst b/3rdparty/libuv/docs/src/threading.rst
new file mode 100644
index 00000000000..e876dde1256
--- /dev/null
+++ b/3rdparty/libuv/docs/src/threading.rst
@@ -0,0 +1,160 @@
+
+.. _threading:
+
+Threading and synchronization utilities
+=======================================
+
+libuv provides cross-platform implementations for multiple threading and
+synchronization primitives. The API largely follows the pthreads API.
+
+
+Data types
+----------
+
+.. c:type:: uv_thread_t
+
+ Thread data type.
+
+.. c:type:: void (*uv_thread_cb)(void* arg)
+
+ Callback that is invoked to initialize thread execution. `arg` is the same
+ value that was passed to :c:func:`uv_thread_create`.
+
+.. c:type:: uv_key_t
+
+ Thread-local key data type.
+
+.. c:type:: uv_once_t
+
+ Once-only initializer data type.
+
+.. c:type:: uv_mutex_t
+
+ Mutex data type.
+
+.. c:type:: uv_rwlock_t
+
+ Read-write lock data type.
+
+.. c:type:: uv_sem_t
+
+ Semaphore data type.
+
+.. c:type:: uv_cond_t
+
+ Condition data type.
+
+.. c:type:: uv_barrier_t
+
+ Barrier data type.
+
+
+API
+---
+
+Threads
+^^^^^^^
+
+.. c:function:: int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg)
+
+ .. versionchanged:: 1.4.1 returns a UV_E* error code on failure
+
+.. c:function:: uv_thread_t uv_thread_self(void)
+.. c:function:: int uv_thread_join(uv_thread_t *tid)
+.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2)
+
+Thread-local storage
+^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+ The total thread-local storage size may be limited. That is, it may not be possible to
+ create many TLS keys.
+
+.. c:function:: int uv_key_create(uv_key_t* key)
+.. c:function:: void uv_key_delete(uv_key_t* key)
+.. c:function:: void* uv_key_get(uv_key_t* key)
+.. c:function:: void uv_key_set(uv_key_t* key, void* value)
+
+Once-only initialization
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Runs a function once and only once. Concurrent calls to :c:func:`uv_once` with the
+same guard will block all callers except one (it's unspecified which one).
+The guard should be initialized statically with the UV_ONCE_INIT macro.
+
+.. c:function:: void uv_once(uv_once_t* guard, void (*callback)(void))
+
+Mutex locks
+^^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_mutex_init(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_lock(uv_mutex_t* handle)
+.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_unlock(uv_mutex_t* handle)
+
+Read-write locks
+^^^^^^^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_rwlock_init(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_destroy(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_rdlock(uv_rwlock_t* rwlock)
+.. c:function:: int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_rdunlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_wrlock(uv_rwlock_t* rwlock)
+.. c:function:: int uv_rwlock_trywrlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_wrunlock(uv_rwlock_t* rwlock)
+
+Semaphores
+^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_sem_init(uv_sem_t* sem, unsigned int value)
+.. c:function:: void uv_sem_destroy(uv_sem_t* sem)
+.. c:function:: void uv_sem_post(uv_sem_t* sem)
+.. c:function:: void uv_sem_wait(uv_sem_t* sem)
+.. c:function:: int uv_sem_trywait(uv_sem_t* sem)
+
+Conditions
+^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. note::
+ Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` and
+ :c:func:`uv_cond_timedwait`.
+
+.. c:function:: int uv_cond_init(uv_cond_t* cond)
+.. c:function:: void uv_cond_destroy(uv_cond_t* cond)
+.. c:function:: void uv_cond_signal(uv_cond_t* cond)
+.. c:function:: void uv_cond_broadcast(uv_cond_t* cond)
+.. c:function:: void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex)
+.. c:function:: int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout)
+
+Barriers
+^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. note::
+ :c:func:`uv_barrier_wait` returns a value > 0 to an arbitrarily chosen "serializer" thread
+ to facilitate cleanup, i.e.
+
+ ::
+
+ if (uv_barrier_wait(&barrier) > 0)
+ uv_barrier_destroy(&barrier);
+
+.. c:function:: int uv_barrier_init(uv_barrier_t* barrier, unsigned int count)
+.. c:function:: void uv_barrier_destroy(uv_barrier_t* barrier)
+.. c:function:: int uv_barrier_wait(uv_barrier_t* barrier)
diff --git a/3rdparty/libuv/docs/src/threadpool.rst b/3rdparty/libuv/docs/src/threadpool.rst
new file mode 100644
index 00000000000..18949507e75
--- /dev/null
+++ b/3rdparty/libuv/docs/src/threadpool.rst
@@ -0,0 +1,67 @@
+
+.. _threadpool:
+
+Thread pool work scheduling
+===========================
+
+libuv provides a threadpool which can be used to run user code and get notified
+in the loop thread. This thread pool is internally used to run all filesystem
+operations, as well as getaddrinfo and getnameinfo requests.
+
+Its default size is 4, but it can be changed at startup time by setting the
+``UV_THREADPOOL_SIZE`` environment variable to any value (the absolute maximum
+is 128).
+
+The threadpool is global and shared across all event loops. When a particular
+function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`)
+libuv preallocates and initializes the maximum number of threads allowed by
+``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead
+(~1MB for 128 threads) but increases the performance of threading at runtime.
+
+.. note::
+ Note that even though a global thread pool which is shared across all events
+ loops is used, the functions are not thread safe.
+
+
+Data types
+----------
+
+.. c:type:: uv_work_t
+
+ Work request type.
+
+.. c:type:: void (*uv_work_cb)(uv_work_t* req)
+
+ Callback passed to :c:func:`uv_queue_work` which will be run on the thread
+ pool.
+
+.. c:type:: void (*uv_after_work_cb)(uv_work_t* req, int status)
+
+ Callback passed to :c:func:`uv_queue_work` which will be called on the loop
+ thread after the work on the threadpool has been completed. If the work
+ was cancelled using :c:func:`uv_cancel` `status` will be ``UV_ECANCELED``.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_work_t.loop
+
+ Loop that started this request and where completion will be reported.
+ Readonly.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb)
+
+ Initializes a work request which will run the given `work_cb` in a thread
+ from the threadpool. Once `work_cb` is completed, `after_work_cb` will be
+ called on the loop thread.
+
+ This request can be cancelled with :c:func:`uv_cancel`.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/timer.rst b/3rdparty/libuv/docs/src/timer.rst
new file mode 100644
index 00000000000..31d733efc39
--- /dev/null
+++ b/3rdparty/libuv/docs/src/timer.rst
@@ -0,0 +1,76 @@
+
+.. _timer:
+
+:c:type:`uv_timer_t` --- Timer handle
+=====================================
+
+Timer handles are used to schedule callbacks to be called in the future.
+
+
+Data types
+----------
+
+.. c:type:: uv_timer_t
+
+ Timer handle type.
+
+.. c:type:: void (*uv_timer_cb)(uv_timer_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_timer_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
+
+ Start the timer. `timeout` and `repeat` are in milliseconds.
+
+ If `timeout` is zero, the callback fires on the next event loop iteration.
+ If `repeat` is non-zero, the callback fires first after `timeout`
+ milliseconds and then repeatedly after `repeat` milliseconds.
+
+.. c:function:: int uv_timer_stop(uv_timer_t* handle)
+
+ Stop the timer, the callback will not be called anymore.
+
+.. c:function:: int uv_timer_again(uv_timer_t* handle)
+
+ Stop the timer, and if it is repeating restart it using the repeat value
+ as the timeout. If the timer has never been started before it returns
+ UV_EINVAL.
+
+.. c:function:: void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat)
+
+ Set the repeat interval value in milliseconds. The timer will be scheduled
+ to run on the given interval, regardless of the callback execution
+ duration, and will follow normal timer semantics in the case of a
+ time-slice overrun.
+
+ For example, if a 50ms repeating timer first runs for 17ms, it will be
+ scheduled to run again 33ms later. If other tasks consume more than the
+ 33ms following the first timer callback, then the callback will run as soon
+ as possible.
+
+ .. note::
+ If the repeat value is set from a timer callback it does not immediately take effect.
+ If the timer was non-repeating before, it will have been stopped. If it was repeating,
+ then the old repeat value will have been used to schedule the next timeout.
+
+.. c:function:: uint64_t uv_timer_get_repeat(const uv_timer_t* handle)
+
+ Get the timer repeat value.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/tty.rst b/3rdparty/libuv/docs/src/tty.rst
new file mode 100644
index 00000000000..655dca9ca20
--- /dev/null
+++ b/3rdparty/libuv/docs/src/tty.rst
@@ -0,0 +1,93 @@
+
+.. _tty:
+
+:c:type:`uv_tty_t` --- TTY handle
+=================================
+
+TTY handles represent a stream for the console.
+
+:c:type:`uv_tty_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_tty_t
+
+ TTY handle type.
+
+.. c:type:: uv_tty_mode_t
+
+ .. versionadded:: 1.2.0
+
+ TTY mode type:
+
+ ::
+
+ typedef enum {
+ /* Initial/normal terminal mode */
+ UV_TTY_MODE_NORMAL,
+ /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+ UV_TTY_MODE_RAW,
+ /* Binary-safe I/O mode for IPC (Unix-only) */
+ UV_TTY_MODE_IO
+ } uv_tty_mode_t;
+
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int readable)
+
+ Initialize a new TTY stream with the given file descriptor. Usually the
+ file descriptor will be:
+
+ * 0 = stdin
+ * 1 = stdout
+ * 2 = stderr
+
+ `readable`, specifies if you plan on calling :c:func:`uv_read_start` with
+ this stream. stdin is readable, stdout is not.
+
+ On Unix this function will try to open ``/dev/tty`` and use it if the passed
+ file descriptor refers to a TTY. This lets libuv put the tty in non-blocking
+ mode without affecting other processes that share the tty.
+
+ .. note::
+ If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
+ non-readable TTY streams.
+
+ .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
+ descriptor that refers to a file returns `UV_EINVAL`
+ on UNIX.
+
+.. c:function:: int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode)
+
+ .. versionchanged:: 1.2.0: the mode is specified as a
+ :c:type:`uv_tty_mode_t` value.
+
+ Set the TTY using the specified terminal mode.
+
+.. c:function:: int uv_tty_reset_mode(void)
+
+ To be called when the program exits. Resets TTY settings to default
+ values for the next process to take over.
+
+ This function is async signal-safe on Unix platforms but can fail with error
+ code ``UV_EBUSY`` if you call it when execution is inside
+ :c:func:`uv_tty_set_mode`.
+
+.. c:function:: int uv_tty_get_winsize(uv_tty_t* handle, int* width, int* height)
+
+ Gets the current Window size. On success it returns 0.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/udp.rst b/3rdparty/libuv/docs/src/udp.rst
new file mode 100644
index 00000000000..dd46603394e
--- /dev/null
+++ b/3rdparty/libuv/docs/src/udp.rst
@@ -0,0 +1,295 @@
+
+.. _udp:
+
+:c:type:`uv_udp_t` --- UDP handle
+=================================
+
+UDP handles encapsulate UDP communication for both clients and servers.
+
+
+Data types
+----------
+
+.. c:type:: uv_udp_t
+
+ UDP handle type.
+
+.. c:type:: uv_udp_send_t
+
+ UDP send request type.
+
+.. c:type:: uv_udp_flags
+
+ Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`..
+
+ ::
+
+ enum uv_udp_flags {
+ /* Disables dual stack mode. */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2,
+ /*
+ * Indicates if SO_REUSEADDR will be set when binding the handle in
+ * uv_udp_bind.
+ * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
+ * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
+ * multiple threads or processes can bind to the same address without error
+ * (provided they all set the flag) but only the last one to bind will receive
+ * any traffic, in effect "stealing" the port from the previous listener.
+ */
+ UV_UDP_REUSEADDR = 4
+ };
+
+.. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
+
+ Type definition for callback passed to :c:func:`uv_udp_send`, which is
+ called after the data was sent.
+
+.. c:type:: void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
+
+ Type definition for callback passed to :c:func:`uv_udp_recv_start`, which
+ is called when the endpoint receives data.
+
+ * `handle`: UDP handle
+ * `nread`: Number of bytes that have been received.
+ 0 if there is no more data to read. You may discard or repurpose
+ the read buffer. Note that 0 may also mean that an empty datagram
+ was received (in this case `addr` is not NULL). < 0 if a transmission
+ error was detected.
+ * `buf`: :c:type:`uv_buf_t` with the received data.
+ * `addr`: ``struct sockaddr*`` containing the address of the sender.
+ Can be NULL. Valid for the duration of the callback only.
+ * `flags`: One or more or'ed UV_UDP_* constants. Right now only
+ ``UV_UDP_PARTIAL`` is used.
+
+ .. note::
+ The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
+ nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is
+ received.
+
+.. c:type:: uv_membership
+
+ Membership type for a multicast address.
+
+ ::
+
+ typedef enum {
+ UV_LEAVE_GROUP = 0,
+ UV_JOIN_GROUP
+ } uv_membership;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: size_t uv_udp_t.send_queue_size
+
+ Number of bytes queued for sending. This field strictly shows how much
+ information is currently queued.
+
+.. c:member:: size_t uv_udp_t.send_queue_count
+
+ Number of send requests currently in the queue awaiting to be processed.
+
+.. c:member:: uv_udp_t* uv_udp_send_t.handle
+
+ UDP handle where this send request is taking place.
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle)
+
+ Initialize a new UDP handle. The actual socket is created lazily.
+ Returns 0 on success.
+
+.. c:function:: int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
+
+ Initialize the handle with the specified flags. At the moment the lower 8 bits
+ of the `flags` parameter are used as the socket domain. A socket will be created
+ for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
+ just like :c:func:`uv_udp_init`.
+
+ .. versionadded:: 1.7.0
+
+.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
+
+ Opens an existing file descriptor or Windows SOCKET as a UDP handle.
+
+ Unix only:
+ The only requirement of the `sock` argument is that it follows the datagram
+ contract (works in unconnected mode, supports sendmsg()/recvmsg(), etc).
+ In other words, other datagram-type sockets like raw sockets or netlink
+ sockets can also be passed to this function.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or SOCKET is not checked for its type, but
+ it's required that it represents a valid datagram socket.
+
+.. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags)
+
+ Bind the UDP handle to an IP address and port.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param addr: `struct sockaddr_in` or `struct sockaddr_in6`
+ with the address and port to bind to.
+
+ :param flags: Indicate how the socket will be bound,
+ ``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the local IP and port of the UDP handle.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init` and bound.
+
+ :param name: Pointer to the structure to be filled with the address data.
+ In order to support IPv4 and IPv6 `struct sockaddr_storage` should be
+ used.
+
+ :param namelen: On input it indicates the data of the `name` field. On
+ output it indicates how much of it was filled.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership)
+
+ Set membership for a multicast address
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param multicast_addr: Multicast address to set membership for.
+
+ :param interface_addr: Interface address.
+
+ :param membership: Should be ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_loop(uv_udp_t* handle, int on)
+
+ Set IP multicast loop flag. Makes multicast packets loop back to
+ local sockets.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param on: 1 for on, 0 for off.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl)
+
+ Set the multicast ttl.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param ttl: 1 through 255.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
+
+ Set the multicast interface to send or receive data on.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param interface_addr: interface address.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_broadcast(uv_udp_t* handle, int on)
+
+ Set broadcast on or off.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param on: 1 for on, 0 for off.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_ttl(uv_udp_t* handle, int ttl)
+
+ Set the time to live.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param ttl: 1 through 255.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb)
+
+ Send data over the UDP socket. If the socket has not previously been bound
+ with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0
+ (the "all interfaces" IPv4 address) and a random port number.
+
+ :param req: UDP request handle. Need not be initialized.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param bufs: List of buffers to send.
+
+ :param nbufs: Number of buffers in `bufs`.
+
+ :param addr: `struct sockaddr_in` or `struct sockaddr_in6` with the
+ address and port of the remote peer.
+
+ :param send_cb: Callback to invoke when the data has been sent out.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr)
+
+ Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't
+ be completed immediately.
+
+ :returns: >= 0: number of bytes sent (it matches the given buffer size).
+ < 0: negative error code (``UV_EAGAIN`` is returned when the message
+ can't be sent immediately).
+
+.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
+
+ Prepare for receiving data. If the socket has not previously been bound
+ with :c:func:`uv_udp_bind` it is bound to 0.0.0.0 (the "all interfaces"
+ IPv4 address) and a random port number.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param alloc_cb: Callback to invoke when temporary storage is needed.
+
+ :param recv_cb: Callback to invoke with received data.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
+
+ Stop listening for incoming datagrams.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/version.rst b/3rdparty/libuv/docs/src/version.rst
new file mode 100644
index 00000000000..e1715b2d3c5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/version.rst
@@ -0,0 +1,60 @@
+
+.. _version:
+
+Version-checking macros and functions
+=====================================
+
+Starting with version 1.0.0 libuv follows the `semantic versioning`_
+scheme. This means that new APIs can be introduced throughout the lifetime of
+a major release. In this section you'll find all macros and functions that
+will allow you to write or compile code conditionally, in order to work with
+multiple libuv versions.
+
+.. _semantic versioning: http://semver.org
+
+
+Macros
+------
+
+.. c:macro:: UV_VERSION_MAJOR
+
+ libuv version's major number.
+
+.. c:macro:: UV_VERSION_MINOR
+
+ libuv version's minor number.
+
+.. c:macro:: UV_VERSION_PATCH
+
+ libuv version's patch number.
+
+.. c:macro:: UV_VERSION_IS_RELEASE
+
+ Set to 1 to indicate a release version of libuv, 0 for a development
+ snapshot.
+
+.. c:macro:: UV_VERSION_SUFFIX
+
+ libuv version suffix. Certain development releases such as Release Candidates
+ might have a suffix such as "rc".
+
+.. c:macro:: UV_VERSION_HEX
+
+ Returns the libuv version packed into a single integer. 8 bits are used for
+ each component, with the patch number stored in the 8 least significant
+ bits. E.g. for libuv 1.2.3 this would be 0x010203.
+
+ .. versionadded:: 1.7.0
+
+
+Functions
+---------
+
+.. c:function:: unsigned int uv_version(void)
+
+ Returns :c:macro:`UV_VERSION_HEX`.
+
+.. c:function:: const char* uv_version_string(void)
+
+ Returns the libuv version number as a string. For non-release versions the
+ version suffix is included.
diff --git a/3rdparty/libuv/gyp_uv.py b/3rdparty/libuv/gyp_uv.py
new file mode 100644
index 00000000000..39933f624d5
--- /dev/null
+++ b/3rdparty/libuv/gyp_uv.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+import os
+import platform
+import sys
+
+try:
+ import multiprocessing.synchronize
+ gyp_parallel_support = True
+except ImportError:
+ gyp_parallel_support = False
+
+
+CC = os.environ.get('CC', 'cc')
+script_dir = os.path.dirname(__file__)
+uv_root = os.path.normpath(script_dir)
+output_dir = os.path.join(os.path.abspath(uv_root), 'out')
+
+sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib'))
+try:
+ import gyp
+except ImportError:
+ print('You need to install gyp in build/gyp first. See the README.')
+ sys.exit(42)
+
+
+def host_arch():
+ machine = platform.machine()
+ if machine == 'i386': return 'ia32'
+ if machine == 'x86_64': return 'x64'
+ if machine.startswith('arm'): return 'arm'
+ if machine.startswith('mips'): return 'mips'
+ return machine # Return as-is and hope for the best.
+
+
+def run_gyp(args):
+ rc = gyp.main(args)
+ if rc != 0:
+ print 'Error running GYP'
+ sys.exit(rc)
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+
+ # GYP bug.
+ # On msvs it will crash if it gets an absolute path.
+ # On Mac/make it will crash if it doesn't get an absolute path.
+ if sys.platform == 'win32':
+ args.append(os.path.join(uv_root, 'uv.gyp'))
+ common_fn = os.path.join(uv_root, 'common.gypi')
+ options_fn = os.path.join(uv_root, 'options.gypi')
+ # we force vs 2010 over 2008 which would otherwise be the default for gyp
+ if not os.environ.get('GYP_MSVS_VERSION'):
+ os.environ['GYP_MSVS_VERSION'] = '2010'
+ else:
+ args.append(os.path.join(os.path.abspath(uv_root), 'uv.gyp'))
+ common_fn = os.path.join(os.path.abspath(uv_root), 'common.gypi')
+ options_fn = os.path.join(os.path.abspath(uv_root), 'options.gypi')
+
+ if os.path.exists(common_fn):
+ args.extend(['-I', common_fn])
+
+ if os.path.exists(options_fn):
+ args.extend(['-I', options_fn])
+
+ args.append('--depth=' + uv_root)
+
+ # There's a bug with windows which doesn't allow this feature.
+ if sys.platform != 'win32':
+ if '-f' not in args:
+ args.extend('-f make'.split())
+ if 'eclipse' not in args and 'ninja' not in args:
+ args.extend(['-Goutput_dir=' + output_dir])
+ args.extend(['--generator-output', output_dir])
+
+ if not any(a.startswith('-Dhost_arch=') for a in args):
+ args.append('-Dhost_arch=%s' % host_arch())
+
+ if not any(a.startswith('-Dtarget_arch=') for a in args):
+ args.append('-Dtarget_arch=%s' % host_arch())
+
+ if not any(a.startswith('-Duv_library=') for a in args):
+ args.append('-Duv_library=static_library')
+
+ # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize
+ # so gyp must be run with --no-parallel
+ if not gyp_parallel_support:
+ args.append('--no-parallel')
+
+ gyp_args = list(args)
+ print gyp_args
+ run_gyp(gyp_args)
diff --git a/3rdparty/libuv/img/banner.png b/3rdparty/libuv/img/banner.png
new file mode 100644
index 00000000000..7187daa2e57
--- /dev/null
+++ b/3rdparty/libuv/img/banner.png
Binary files differ
diff --git a/3rdparty/libuv/img/logos.svg b/3rdparty/libuv/img/logos.svg
new file mode 100644
index 00000000000..d6185f8b191
--- /dev/null
+++ b/3rdparty/libuv/img/logos.svg
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="792pt"
+ height="612pt"
+ id="svg3069"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="New document 3">
+ <defs
+ id="defs3071">
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath70">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z"
+ id="path72" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath70-6">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z"
+ id="path72-5" />
+ </clipPath>
+ </defs>
+ <sodipodi:namedview
+ inkscape:document-units="in"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.43415836"
+ inkscape:cx="508.42646"
+ inkscape:cy="359.27024"
+ inkscape:current-layer="layer1"
+ id="namedview3073"
+ showgrid="false"
+ inkscape:window-width="1010"
+ inkscape:window-height="702"
+ inkscape:window-x="441"
+ inkscape:window-y="267"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata3075">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(0.2288071,0,0,-0.2288071,130.84779,1169.4436)"
+ id="g66">
+ <g
+ id="g68"
+ clip-path="url(#clipPath70)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 3274.33,2372.2 c -42.27,-8.61 -87.28,-37.29 -122.12,-43.75 -77.01,-14.25 -122.4,-0.53 -81.76,16.27 59.03,24.45 253.75,30.55 274.1,175.05 20.36,144.5 6.1,209.66 -4.07,246.29 -4.87,17.57 -15.81,43.49 -25.9,65.76 -2.85,15.73 -6.59,29.07 -9.86,38.57 -1.82,4.29 -3.65,9.81 -5.46,16.78 0,0 -2.54,17.81 5.6,35.1 7.2,15.34 31.95,48.62 33.62,80.79 0.03,1.95 0.11,3.9 0.08,5.85 -0.1,2.18 -0.28,4.33 -0.63,6.48 l -0.18,1.9 c -3.17,18.05 -13.53,30.62 -27.6,39.98 -9.06,6.02 -21.4,7.92 -28.17,16.51 5.4,17.01 22.63,23.06 29.82,36.95 4.48,12.34 0.82,25.3 -5.99,37.08 -13.13,14.72 -38.92,27.49 -62.07,36.15 -28.97,10.87 -58.44,19.45 -78.35,35.06 -21.03,11.19 -35.17,32.83 -22.26,61.45 3.35,7.44 4.85,14.93 4.75,22.04 l -0.09,2.09 c -0.03,1.45 -0.23,2.76 -0.41,4.1 -0.15,1.04 -0.32,2.06 -0.55,3.08 l -0.47,1.77 -0.56,2.02 c -5.3,17.86 -33.44,22.88 -43.47,23.78 -22.72,2.04 -37.4,8.2 -49.46,12.01 9.7,-5.04 19.46,-11.78 31.9,-16.79 7.87,-3.21 19.17,-5.12 28.68,-8.29 l 0.09,0.02 c 0,0 17.55,-3.56 22.38,-15.78 4.84,-12.2 2.03,-22.9 0,-29.75 l -0.74,-1.99 c -1.75,-5.35 -3.72,-10.51 -4.13,-15.84 -1.65,-21.04 11.26,-32 18.12,-49.6 12.35,-11.73 29.93,-23.88 54.32,-34.88 21.92,-9.9 48.15,-15.89 64.4,-25.7 9.41,-5.68 26.55,-19.41 26.16,-29.4 -0.3,-7.65 -14.43,-18.09 -20.12,-25.7 -4.07,-5.42 -6.09,-12.62 -9.73,-17.74 -3.17,-5 -7.24,-8.22 -11.92,-8.22 -6.1,0 -20.01,-2.36 -10.86,-3.04 9.16,-0.68 32.91,-11.87 32.91,-11.87 l -0.02,-0.03 c 32.1,-13.28 53.67,-37.88 41.87,-72.96 -9.88,-29.39 -32.61,-53.97 -34.2,-86.3 -1.7,-34.4 14.07,-62.72 16.09,-90 3.41,-45.9 -3.18,-77.51 -12.06,-112.01 -4.17,-16.14 -6.39,-32.04 -10.06,-47.74 -15.68,-66.87 -56.09,-95.84 -110.68,-126.73 -23.67,-13.39 -49.07,-38.07 -74.45,-45.9 -4.09,-1.26 -10.39,0.66 -14.11,0 -23.38,-4.22 -44.42,-15.81 -68.41,-20.19 -22.59,-4.17 -46.27,-2.17 -73.08,-8.96 -13.6,-4.85 -31.03,-12.11 -41.21,-16.43 -15.74,-7.17 -31.16,-14.63 -46.55,-22.15 l -51.11,-29.2 c 0,0 -28.48,-16.49 3.06,-4.28 25.38,9.83 112.62,53.25 76.08,27.75 -25.2,-12.66 -38.87,-30.64 -61.16,-45.98 0,0 -74.99,-37.19 -86.24,-47.57 -12.37,-11.42 -27.49,-5.1 -37.41,-16.3 -11.65,-13.13 -25.94,-21.01 -36.13,-24.41 -10.17,-3.42 -21.7,-25.78 -37.31,-37.31 -15.61,-11.54 -49.52,-8.15 -79.38,-21.04 -29.85,-12.89 -60.79,-13.06 -60.79,-13.06 -2.96,-0.28 -5.83,-0.46 -8.58,-0.53 -1.18,-0.03 -2.27,-0.02 -3.4,-0.02 -17.46,-0.09 -30.81,3.32 -41.04,7.08 -12.47,4.58 -17.05,2.28 -14.25,0.76 2.8,-1.51 10.92,-9.11 10.92,-9.11 -34.83,0.04 -44.33,23.18 -60.37,40.37 7.29,1.04 28.08,-4.04 17.52,2.08 -20.85,9.97 -61.01,10.69 -61.8,34.67 -0.6,18.81 8.06,14.69 8.06,14.69 14.61,-25.44 59.69,-27.93 92.57,-27.57 61.24,0.74 102.68,34.32 142.82,53.32 13.01,7.82 28.21,18.1 28.21,18.1 l -0.08,-0.3 c 12.67,8.25 25.48,16.25 36.31,26.22 18.9,17.37 31.67,40.04 48.31,59.27 1.93,3.27 5.99,7.26 10.81,11.28 4.69,4.4 9.73,8.5 15.34,12.09 l 0.21,-0.45 2.18,1.46 -0.39,0.82 c 40.39,22.9 78.03,48.25 109.79,79.02 l 0.21,0.36 c 4.56,4.13 28.46,30.81 40,43.76 13.61,18.15 23.42,41.08 29.11,64.18 2.05,8.36 0.75,18.51 4.01,27.56 5.07,14.03 17.81,26.51 26.17,40.39 8.65,14.43 14.37,30.14 20.12,45.9 25.17,69.17 54.28,124.25 108.66,161.6 26.2,18.01 58.02,29.63 76.46,56.95 -13.39,-13.59 -30.82,-23.5 -51.87,-30.09 -59.79,-19.7 -98.68,-70.15 -118.23,-102.2 -15.01,-26.98 -26.61,-57.04 -35.14,-89.93 -2.83,40.54 -12.84,72.15 -26.17,102.84 -11.85,27.29 -22.33,56.15 -44.27,73.46 0,0 -0.84,-0.06 -4.25,1.99 -3.39,2.02 56.57,3.53 56.57,3.53 10.49,-0.38 21.17,-1.89 31.99,-3.29 2.03,0.22 4.51,0.1 7.56,-0.43 32.96,-5.82 67.21,6.45 88.55,21.98 11.08,8.06 30.34,14.52 46.32,18.89 0.26,0.69 1.82,1.47 5.81,2.23 0,0 24.42,7.63 50.37,14.76 17.58,4.81 30.38,8.5 39.27,12.89 5.15,3.28 10.05,7.22 13.85,11.91 7.61,9.39 7.76,20.66 14.1,36.73 6.31,16.03 15.96,28.49 16.1,42.24 0.45,45.08 -42.25,80.98 -88.54,56.95 45.58,11.75 77.9,-10.49 72.44,-53.28 -6.74,-52.87 -86.39,-92.05 -134.83,-112.01 -19.2,-7.91 -41.68,-17.9 -64.38,-20.19 -32.74,-3.32 -62.41,3.67 -90.56,1.84 -36.1,-2.38 -60.11,-21.47 -90.55,-23.89 -26.16,-2.07 -22.61,15.61 -45.31,17.62 -4.7,2.68 -18.98,0 -33.18,0.74 -39.25,-10.37 -64.5,7.57 -96.58,22.04 -23.14,10.45 -47.82,19.96 -72.44,22.04 -61.81,5.24 -99.39,-3.35 -149.91,2.01 -14.25,1.51 -43.81,3.31 -57.85,8.57 -43.71,16.35 -77.17,10.42 -124.65,11.1 -34.54,0.5 -66.59,2.31 -88.15,-1.47 -5.88,-1.06 -11.84,-2.57 -18.12,-3.67 -46.27,-8.09 -116.76,-12.28 -114.69,-53.26 3.44,2.35 2.48,8.74 8.04,9.18 -0.2,-7.53 -0.39,-15.05 2.01,-20.21 -26.91,0.7 -42.78,19.28 -42.25,40.41 0.9,35.93 58.71,50.95 98.59,60.61 39.98,9.64 81.5,20.94 110.69,25.7 -69.91,-10.27 -143.86,-16.88 -197.22,-42.25 -0.75,2.76 -1.23,5.42 -1.55,7.98 -4.22,19.4 -13.43,49.15 -19.91,78.07 -7.46,33.24 4.06,91.59 4.06,91.59 l 0.29,-0.34 c 4.81,29.66 10.94,42.88 16.88,60.61 12.65,37.82 53.52,49.69 82.13,53.28 -24.12,-17.04 -39.54,-38.17 -49.29,-66.46 -1.2,-10.04 -2.14,-19.46 -2.84,-27.77 21.65,67.41 82.07,92.64 82.07,92.64 l 19.34,20.86 -0.25,-0.95 c 33.36,32.26 77.42,57.26 133.43,58.83 28.22,0.79 62.32,-6.64 62.23,-34.32 -0.04,-15.65 -12.28,-28.93 -28.97,-36.27 4.91,-0.97 9.4,-0.29 13.47,1.39 l 17.34,19.41 c 5.74,14.18 5.23,32.1 -4.44,42.9 25.52,21.82 65.26,-2.65 62.36,-31.6 7.47,6.3 12.03,18.2 6.89,27.64 34.34,20.18 53.56,-28.74 88.11,-17.31 -3.25,9.79 -19.89,7.81 -24.95,15.97 45.17,6.46 84.78,-9.42 130.08,-5.82 2.84,-2.47 5.91,-4.93 9.19,-7.36 -84.73,-9.38 -15.9,-9.33 -15.9,-9.33 10.85,0.99 36.92,2.81 47.06,1.01 16.58,-3 27.29,1.04 41.95,6.77 0.35,-0.64 1.82,-0.58 2.71,1.08 7.6,3 16.35,6.31 27.47,9.31 4.31,0.61 8.64,1.72 12.84,3.09 l 1.81,0.37 0.26,0.29 c 5.8,2.02 11.27,4.44 15.96,6.71 42.69,20.52 78.1,68.84 114.56,94.19 60.42,41.99 117.63,-9.88 159.69,-43.54 l -0.27,-0.39 c 10.55,-7.2 24.46,-16.08 39.61,-25.35 39.58,-17.23 91.79,-32.28 119.67,-59.84 22.31,-22.04 29.9,-50.42 39.49,-79.88 8.96,-27.47 26.34,-51.77 36.12,-82.6 1.88,1.58 2.99,3.96 3.63,6.8 -0.27,2.63 -0.7,5.41 0.08,7.13 l 0.53,-0.48 c -0.11,5.38 -1.3,11.69 -3.14,18.33 -8.29,16.88 -22.78,36.11 -21,51.15 0,0 51.42,-26.57 109.76,-52.96 20.09,-9.09 38.48,-24.08 54.53,-41.21 l 4.69,0.1 c -0.55,-1.2 -0.5,-2.93 -0.33,-4.76 28.36,-31.78 48.46,-69.63 55.45,-91.51 1.44,-4.49 3.07,-9.04 4.83,-13.57 l 0.01,-0.05 c 2.2,-5.71 4.57,-11.35 7.02,-16.78 l 0.05,0.08 c 1.03,-1.85 1.68,-3.66 2.37,-5.49 8.42,-18.22 16.69,-33.01 18.99,-37.06 7.41,-9.21 13.39,-21.04 19.78,-31.05 2.22,-24.89 3.41,-50.09 3.41,-75.56 0,-199.46 -69.36,-382.69 -185.2,-527 -6.7,-0.78 -15.83,-2.33 -27.9,-4.8 z m -52.92,-82.53 c -40.52,-13.23 -81.83,-38.11 -108.21,-40.61 -79.4,-7.5 -93.63,27.79 -30.19,33.61 23.94,2.2 59.29,4.91 87.52,18.29 41.64,19.78 84.29,38.98 112.76,53.23 -19.47,-22.6 -40.15,-44.11 -61.88,-64.52 z m -865.53,-3.85 c -6.73,-2.26 -6.73,1.07 -6.73,1.07 0,0 -12.2,17.42 -14.09,33.64 -1.91,16.07 2.23,30.38 6.26,32.5 4.07,2.2 4.95,-7.16 8.26,-18.88 3.33,-11.84 19.78,-36.13 19.78,-36.13 2.34,-5 -6.65,-9.95 -13.48,-12.2 z m 42.43,-7.43 c -7.73,-2.57 -7.72,1.26 -7.72,1.26 0,0 -13.94,19.78 -16.06,38.24 -2.14,18.26 2.66,34.52 7.3,36.95 4.67,2.51 5.67,-8.16 9.42,-21.52 3.76,-13.43 22.6,-41.09 22.6,-41.09 2.67,-5.68 -7.71,-11.25 -15.54,-13.84 z m 14.34,51.42 c -2.66,23.12 3.53,43.78 9.47,46.91 5.98,3.19 7.21,-10.35 11.96,-27.27 4.76,-17.04 28.77,-52.08 28.77,-52.08 3.4,-7.18 -9.92,-14.29 -19.94,-17.55 -9.92,-3.24 -9.89,1.54 -9.89,1.54 0,0 -17.72,25.08 -20.37,48.45 z m 344.3,264.59 c 4.16,3.72 8.54,-4.1 16.65,-12.97 8.18,-8.98 36.92,-23.11 36.92,-23.11 4.63,-3.42 -4.59,-11.97 -12.08,-17.13 -7.47,-5.16 -8.66,-2.13 -8.66,-2.13 0,0 -21.16,9.99 -29.17,23.65 -7.97,13.46 -7.84,27.91 -3.66,31.69 z m -68.15,-36.32 c 5.11,4.79 10.57,-5.35 20.77,-16.86 10.31,-11.78 46.52,-30.52 46.52,-30.52 5.9,-4.44 -5.63,-15.55 -14.96,-22.21 -9.36,-6.66 -10.92,-2.72 -10.92,-2.72 0,0 -26.46,13.4 -36.55,31.17 -9.99,17.53 -10,36.37 -4.86,41.14 z m -60.8,-81.74 c -9,18.83 -8.22,38.34 -3.02,43.06 5.25,4.73 10.2,-6.14 19.69,-18.82 9.63,-12.88 44.35,-34.41 44.35,-34.41 5.56,-5 -6.19,-15.86 -15.65,-22.26 -9.41,-6.35 -10.8,-2.21 -10.8,-2.21 0,0 -25.38,15.51 -34.57,34.64 z m -55.66,-46.52 c -7.53,19.87 -5.51,39.81 -0.21,44.23 5.4,4.43 9.44,-7.08 17.74,-20.66 8.43,-13.86 40.51,-38.43 40.51,-38.43 5.09,-5.51 -6.92,-15.77 -16.52,-21.57 -9.48,-5.72 -10.46,-1.32 -10.46,-1.32 0,0 -23.45,17.66 -31.06,37.75 z m -75.01,-121.98 c -9.98,-3.02 -9.89,1.61 -9.89,1.61 0,0 -16.92,24.38 -18.9,46.94 -1.96,22.39 4.85,42.34 10.86,45.31 6.07,3.02 6.94,-10.05 11.14,-26.43 4.3,-16.56 27.21,-50.59 27.21,-50.59 3.18,-6.96 -10.3,-13.73 -20.42,-16.84 z m 20.3,78.13 c -4.88,22.44 -0.13,43.46 5.88,47.35 6.06,3.95 8.61,-9.17 15.12,-25.14 6.57,-16.04 35.41,-47.57 35.41,-47.57 4.31,-6.67 -9.23,-15.5 -19.66,-20.14 -10.27,-4.55 -10.72,0.28 -10.72,0.28 0,0 -21.1,22.52 -26.03,45.22 z m 271.98,527.71 c 0,0 5.87,-0.99 3.22,-9.29 -2.64,-8.28 -3.15,-33.94 4.88,-45 8.07,-11.09 -5.53,-6.88 -16.15,4.32 -10.63,11.15 -18.15,31.7 -15.86,45.66 0,0 -0.61,5.87 23.91,4.31 z m -37.52,-67.96 c 12.88,-14.37 -6.84,-10.53 -23.34,3.63 -16.48,14.11 -29.99,41.66 -28.75,61.54 0,0 -1.69,8.15 32.94,9.54 0,0 8.42,-0.53 5.81,-12.53 -2.47,-11.98 0.45,-47.93 13.34,-62.18 z m -87.89,-74.93 c 75.07,-4.92 128.89,21.11 167.01,47.73 10.04,7 23.31,24.05 40.27,12.85 -7.23,-14.98 -26.39,-24.85 -42.26,-33.04 -27.81,-14.37 -52.47,-26.94 -84.52,-34.9 54.02,8.26 92.4,30.76 132.81,51.42 4.95,-10.38 10.51,-31.21 14.16,-48.84 l 0.52,0.05 c 0,0 3.67,-9.88 2.58,-19.53 0.15,-4.6 -0.78,-8.56 -4.07,-10.74 -1.11,-1.42 -2.44,-2.73 -4.11,-3.82 -14.75,-9.67 -58.52,-31.04 -93.63,-33.58 -1.16,-0.07 -2.27,-0.22 -3.42,-0.33 l -2.59,-0.73 -0.07,0.48 c -31.84,-3.69 -52.44,-16.81 -11.72,-10.12 40.74,6.72 128,21.57 96.21,9.62 l 0.11,0.02 c -39.69,-15.51 -91.77,-30.69 -142.89,-25.71 -33.03,3.2 -67.2,19.4 -96.58,34.89 -29.34,15.45 -57.18,35.77 -88.54,42.22 -23.87,4.94 -43.59,-1.94 -64.39,-5.5 -13.85,-2.34 -33.15,-7.95 -41.54,0.7 -3.54,4.19 -0.72,8.49 -0.72,8.49 7.94,19.62 31.07,31.19 50.3,36.72 60.36,17.37 118.83,-14.55 177.08,-18.35 z m 17.01,65.76 c 12.62,-18.31 -9.29,-10.98 -26.04,7.72 -16.76,18.69 -28.07,52.35 -23.77,75.03 0,0 -0.73,9.53 38.96,5.89 0,0 9.52,-1.89 4.9,-15.19 -4.73,-13.42 -6.64,-55.1 5.95,-73.45 z m -79.92,8.72 c 12.44,-20.82 -10.82,-11.69 -27.75,9.78 -16.94,21.37 -27.09,59.1 -20.93,83.8 0,0 -0.14,10.62 42.73,4.68 0,0 10.14,-2.56 4.23,-17.09 -5.93,-14.48 -10.72,-60.33 1.72,-81.17 z m -82.62,11.5 c 12.72,-21.08 -10.85,-12.08 -28.06,9.58 -17.23,21.59 -27.69,59.9 -21.58,85.21 0,0 -0.23,10.74 43.13,5.29 0,0 10.28,-2.5 4.37,-17.35 -5.89,-14.84 -10.51,-61.7 2.14,-82.73 z m -75.72,-23.8 c 15.61,-27.27 -11.73,-15.72 -32.57,12.24 -20.82,27.97 -34.79,77.68 -29.28,110.62 0,0 -0.8,14.07 48.83,7.3 0,0 11.92,-3.09 6.02,-22.58 -5.92,-19.36 -8.62,-80.28 7,-107.58 z m -80.38,20.29 c 15.56,-23.8 -11.82,-14.71 -32.58,9.48 -20.74,24.17 -34.4,68.31 -28.65,98.18 0,0 -0.78,12.63 49.05,8.82 0,0 11.91,-2.29 5.83,-19.98 -6.03,-17.69 -9.15,-72.64 6.35,-96.5 z m -85.14,27.74 c 10.98,-20.46 -10.36,-11.36 -25.48,9.78 -15.12,21.03 -23.44,58.05 -17.05,82.25 0,0 0.14,10.39 39.73,4.3 0,0 9.4,-2.58 3.46,-16.71 -5.88,-14.2 -11.63,-59.14 -0.66,-79.62 z m -64.93,17.69 c 10.31,-16.32 -8.4,-9.23 -22.34,7.51 -13.92,16.76 -22.72,46.32 -18.28,65.79 0,0 -0.36,8.33 33.87,3.93 0,0 8.22,-1.94 3.71,-13.4 -4.32,-11.4 -7.32,-47.51 3.04,-63.83 z m -68.19,-11.78 c 12.6,-18.31 -9.3,-10.98 -26.05,7.74 -16.75,18.69 -28.06,52.34 -23.76,75.03 0,0 -0.74,9.51 38.95,5.89 0,0 9.52,-1.89 4.9,-15.21 -4.74,-13.41 -6.63,-55.07 5.96,-73.45 z m -55.02,4.85 c 12.88,-14.35 -6.83,-10.55 -23.32,3.6 -16.5,14.13 -30.01,41.69 -28.77,61.56 0,0 -1.68,8.15 32.94,9.54 0,0 8.42,-0.53 5.83,-12.55 -2.48,-11.98 0.43,-47.93 13.32,-62.15 z m 755.27,-755.37 c -38.14,-13.18 -105.91,-46.26 -160.35,-73.94 -13.01,-0.6 -26.11,-0.94 -39.29,-0.94 -465.3,0 -842.48,377.19 -842.48,842.49 0,360.48 226.45,668 544.82,788.29 1.61,-1.49 3.31,-2.93 5.11,-4.33 3.61,-2.81 9.58,-4.3 12.67,-8 4.11,-4.94 2.4,-14.97 4.19,-21.16 5.55,-19.11 17.35,-36.65 37,-50.99 2.87,-2.12 8.35,-3.14 10.85,-5.95 5.47,-6.21 3.88,-16.65 8.01,-23.83 4.35,-7.55 11.76,-16.67 20.9,-23.69 5.01,-3.86 12.5,-5.92 17.18,-10.52 3.79,-3.71 4.84,-10.39 7.55,-15.95 7.34,-15.01 26.73,-32.41 36.04,-48.12 1.23,-2.07 2.19,-4.27 3,-6.51 3.88,-7.99 13.26,-24.92 26.05,-32.75 0,0 1.33,-23.51 24.78,-50.31 -47.5,2.56 -93.32,29.42 -128.56,2.74 -10.17,11.1 -42.79,19.8 -56.75,4.23 -10.31,17.92 -64.99,29.36 -75.62,1.04 -77.73,34.87 -171.54,-14.85 -201.69,-64.76 -5.6,-2.67 -10.83,-5.48 -15.77,-8.37 -21.28,6.4 -50.1,8.67 -81.29,-13.82 -30.74,-22.18 -62.88,-121.66 -57.35,-190.53 0.6,-7.38 14.59,-24.8 19.62,-59.7 5,-34.62 8.81,-45.99 8.81,-45.99 -6.84,-11.93 -15,-17.26 -16.11,-31.22 -2.41,-30.21 23.42,-46.63 47.62,-62.1 8.61,-4.01 18.36,-6.89 28.94,-7.27 6.39,-10.12 31.01,-44.33 71.72,-44.33 1,0 2.03,0.07 3.03,0.13 15.54,-13.07 31.75,-16.58 20.56,-0.47 -0.92,1.33 -1.71,2.82 -2.45,4.35 7.48,-4.43 16.54,-8.77 24.61,-9.56 0.16,-0.01 3.96,-0.97 7.13,-0.97 1.12,0 4.46,0 5.64,2.57 1.17,2.58 -1.21,5.35 -1.99,6.23 -3.26,3.76 -6.93,13.54 -9.69,22.65 2.98,-5.46 6.23,-10.66 9.87,-15.13 19.37,-23.78 46.47,-35.02 31.34,-11.36 -4.86,7.58 -7.63,17.91 -8.98,28.88 7.5,-9.25 20.42,-19.99 41.43,-24.29 17.36,-16.51 38.94,-23.26 26.01,-5.71 -3.3,4.49 -5.46,10.27 -6.75,16.59 10.47,-12.55 28.17,-28.68 49.88,-28.68 l 1.58,0.04 0.44,0.02 c 14.89,-10.07 27.36,-11.75 16.22,2.77 -4.83,6.32 -7.46,15.08 -8.64,24.34 9.84,-20.08 28.82,-47.69 61.49,-56.57 0.24,-0.09 5.87,-1.65 10.52,-1.65 3.63,0 5.91,0.93 7,2.92 1.58,2.85 -0.5,6.17 -1.18,7.26 -2.11,3.38 -4.07,7.59 -5.77,11.74 14.67,-8.6 25.51,-9.33 14.1,4.68 -5.9,7.22 -9.05,17.42 -10.34,27.95 7.97,-21.31 24.22,-51.23 56.3,-70.83 0.24,-0.11 6.01,-2.84 12.42,-2.84 3.09,0 5.84,0.65 8.23,1.85 2.04,1.05 3.38,2.77 3.93,4.98 1.67,6.68 -4.67,16.16 -5.24,16.93 -2.64,5.2 -7.48,16.18 -9.86,25.78 l 0.24,-0.19 c 23.19,-18.71 53.29,-27.37 34.72,-8.72 -11.27,11.35 -15.62,30.79 -16,46.67 6.77,-19.01 23.24,-51.94 57.35,-58.45 0.23,-0.02 5.52,-1.04 9.42,-1.04 2.17,0 4.78,0.25 5.69,2.33 0.4,0.88 0.56,2.3 -0.99,4.04 -2.55,2.86 -6.18,11.52 -8.1,18.52 1.62,-1.24 3.19,-2.55 4.89,-3.63 16.54,-10.85 36.06,-16.54 38.61,-13.02 5.29,-4.34 13.57,-10.03 24.82,-14.99 1.05,-2.39 2.09,-4.82 2.93,-7.24 0,0 5.25,-14.59 7.27,-22.48 -26.76,6.93 -72.56,20.35 -106.65,12.83 -26.92,-5.92 -97.1,-44.72 -80.12,-71.99 1.13,-1.82 2.58,-3.09 4.24,-4.11 l 1.05,-0.4 c 6.7,-3.57 18.52,-5.67 30.95,-5.57 l 4.52,0.13 c 7.22,0.39 26.15,3.12 32.56,5.2 18.77,6.1 35.53,2.43 35.53,2.43 l -0.24,-0.17 c 13.34,-1.55 27.41,-6.24 41.94,-13.66 15.61,-7.94 36.85,-21.06 42.26,-27.53 9.76,-11.73 -5.19,-39.21 -10.76,-56.13 -0.27,-1 -0.61,-2.04 -0.93,-3.08 l -0.4,-1.4 -0.05,0.03 c -0.79,-2.37 -1.76,-4.86 -2.8,-7.4 -0.95,1.19 -1.79,2.34 -2.43,3.42 -5.34,8.98 -8.21,16.84 -10.97,13.23 -2.76,-3.62 -2.89,-17.96 2.36,-31.49 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.05,-11.06 -13.38,-22.64 -21.11,-33.75 -6.02,5.7 -12.11,12.11 -15.05,17.23 -6.87,11.76 -10.53,22.09 -14.04,17.35 -3.54,-4.72 -3.64,-23.77 3.09,-41.67 2.2,-5.83 5.55,-11.11 9.07,-15.73 -5.34,-6.74 -10.55,-12.95 -15.3,-18.23 -2.13,-2.34 -4.65,-4.99 -7.32,-7.74 -7.34,7.56 -16.63,17.94 -20.38,25.45 -6.54,13.12 -9.91,24.3 -13.63,19.54 -3.71,-4.8 -4.43,-24.95 1.75,-44.43 2.55,-7.98 6.93,-15.27 11.27,-21.19 -7.96,-7.58 -16.6,-15.59 -25.47,-23.67 -5.38,7.14 -10.69,14.98 -13.12,20.98 -5.83,14.19 -8.6,26.23 -12.54,21.61 -3.88,-4.63 -5.58,-25.57 -0.35,-46.44 1.29,-5.15 3.26,-10.09 5.5,-14.67 -8.79,-7.86 -17.3,-15.38 -25.11,-22.19 -2.29,4.97 -4.2,9.69 -5.26,13.58 -4.58,16.9 -6.3,30.85 -10.81,26.57 -4.51,-4.18 -8.35,-26.68 -5.05,-50.59 0.31,-2.3 0.76,-4.57 1.27,-6.85 l -2.2,-1.89 c -5.11,-4.41 -10.66,-9.72 -16.39,-15.56 -1.43,4.49 -2.54,8.7 -3.12,12.19 -2.91,17.61 -3.35,31.7 -7.98,28.33 -4.6,-3.31 -10.11,-25.03 -9,-49.33 0.17,-3.82 0.63,-7.68 1.27,-11.45 -6.74,-7.6 -13.41,-15.44 -19.69,-23.09 -3.64,9.35 -6.93,19.01 -8.2,26 -3.33,18.42 -4.03,33.23 -8.74,29.6 -4.31,-3.29 -9.05,-23.01 -8.53,-45.96 -4.7,-3.44 -10.79,-19.44 -10.99,-37.57 -0.09,-6.17 1.01,-12.49 2.51,-18.2 -3.05,-4.3 -8.38,-7.28 -12.11,-12.52 -19.24,-26.91 -11.39,-58.98 30.18,-66.11 12.74,-39.25 45.04,-58.31 94.58,-58.76 6.65,-0.06 13.6,2.26 20.12,1.85 7.36,-0.49 13.42,-3.48 20.13,-3.69 36.11,-1.1 55.04,10.39 82.49,18.39 20.47,5.94 41.6,7.84 54.34,12.84 19.51,7.65 28.78,28.62 44.26,38.56 5.77,3.7 16.64,5.44 26.17,11.01 8.04,4.73 15,13.32 22.13,16.53 6.23,2.82 16.6,2.26 24.14,5.51 12.64,5.48 26.6,17.31 42.27,25.73 32.81,17.55 59.51,30.53 94.57,45.89 16.75,7.34 34.47,24.6 44.27,25.71 11.62,1.34 25.15,-8.36 34.21,-7.34 18.46,-21.95 24.89,-52.62 24.12,-92.06 1.09,-0.11 0.29,-9.78 0.29,-9.78 0,0 6.45,-84.66 -125.77,-130.38 z M 2319.1,3773.92 c 13.83,-3.85 29.29,-11.71 14.56,-35.21 -9.06,9.68 -12.13,22.44 -14.56,35.21 z m 26.38,-30.96 c 4.42,7.74 0.02,11.68 2.36,16.37 39.74,-5.12 43.17,-33.03 26,-72.62 -26.49,8.95 -33.54,26.66 -38.58,44.64 4.25,4.61 7.55,6.9 10.22,11.61 z m 43.39,-7.87 c 36.99,-16.3 42.8,-57.19 17.22,-110.53 -8.74,5.74 -15.55,12.62 -20.46,20.22 -3.89,6.03 -9.35,15.9 -8.18,24.01 0.82,5.58 5.24,13.07 7.5,19.31 6.47,17.93 8.99,34.11 3.92,46.99 z m 177.23,-155.25 c -0.64,1.95 0.67,1.89 2.28,3.33 55.29,-11.22 59.69,-65.17 35.95,-105.83 -11.26,-19.25 -22.27,-29.38 -39.55,-24.01 -14.3,4.46 -16.25,15.95 -23.14,23.85 28.17,41.04 27.62,71.27 24.46,102.66 z m -63.91,40.61 c -0.24,5.01 -1.15,10.58 0.87,15.52 4.77,-0.4 13.12,-1.61 19.95,-5.23 31.05,-16.4 43.9,-75.07 25.85,-109.56 -7.75,-14.78 -15.59,-21.96 -30.09,-17.81 -23.4,6.72 -30.19,33.21 -39.62,44.17 25.51,27.2 24.04,51.08 23.04,72.91 z m -74.76,73.65 1.52,0.74 c 60.84,-21.44 95.74,-61.97 40.45,-136.4 -21.08,10.57 -32.94,24.68 -38.43,40.68 -3.23,9.38 -5.72,10.51 -3.53,22.15 4.69,25.14 6.27,52.87 -0.01,72.83 z m 236.11,-312.56 c -2.27,-1.01 -3.87,-1.76 -3.87,-1.76 -7.39,-3.78 -15.16,-6.03 -22.54,-7.31 -45.74,9.82 -59.56,61.95 -59.56,61.95 42.74,18.79 66.89,72.89 51.68,102.65 0.43,1.11 1.42,0.93 2.42,0.7 19.37,-8.54 39.75,-22.88 49.66,-38.41 18.83,-29.45 24.41,-73.75 8.73,-109.34 -6.98,-1.61 -11.46,-3.21 -17.08,-5.19 -0.95,-0.25 -1.94,-0.54 -2.92,-0.88 l -5.22,-1.92 -0.53,-0.21 -0.82,-0.27 0.05,-0.01 z m 73.78,36.96 c -3.13,-2.66 -6.21,-5.27 -9.06,-7.69 -2.62,-5.02 -10.66,-11.66 -20.93,-16.01 8.15,24.72 9.13,50.99 9.7,70.45 16.84,-8.75 28.08,-20.77 34.57,-34.43 -2.08,-1.8 -4.21,-3.66 -6.4,-5.55 -2.88,5.37 -6.87,10.23 -12.09,14.35 2.36,-6.86 3.71,-13.9 4.21,-21.12 z m -92.4,328 c 412.7,0 756.05,-296.74 828.41,-688.48 -7.89,5.56 -16.59,10.5 -26.45,14.61 -20.63,92.05 -65.01,150.17 -156.18,183.4 -30.56,11.13 -59.51,24.02 -89.66,37.15 1.74,97.97 -112.11,95.91 -183.06,146.34 -30.86,21.99 -65.84,62.56 -101.14,70.06 -68.27,14.52 -110.27,-33.06 -150.59,-66.3 -9.89,10.8 -24.72,21.35 -46.23,30.94 0,0 -38.48,54.88 -56.43,65.21 -1.19,0.68 -1.98,1.3 -2.5,1.92 -9.92,4.65 -22.34,7.27 -31.12,13.07 -8.67,5.7 -10.31,19.19 -18.99,25.7 -4.25,3.19 -10.84,6.65 -16.6,8.96 -6.96,2.79 -18.88,2.27 -25.88,6.1 -8.63,4.73 -9.32,20.11 -15.57,27.74 -6.89,8.43 -15.75,15.32 -30.08,20.14 -5.81,1.93 -14.59,2.06 -19.84,4.87 -5.86,3.17 -7.29,13.09 -11.83,19.17 -10.55,14.18 -28.36,25.18 -48.68,32.36 -4.37,1.54 -10.25,1.54 -13.45,3.69 -3.77,2.51 -4.21,8.78 -6.49,13.58 70.85,19.35 145.38,29.77 222.36,29.77 z m 836.59,-742.56 c -8.56,14.67 -16.48,28.78 -19.38,41.21 5.81,-3.84 10.91,-8.12 15.58,-12.68 1.44,-9.45 2.67,-18.97 3.8,-28.53 z m -836.59,785.09 c -91.12,0 -179,-13.85 -261.73,-39.43 -0.93,1.64 -1.92,3.24 -3.23,4.52 -7.64,7.44 -16.71,13.1 -35.56,8.27 -6.68,8.65 -15.49,15.6 -29.86,18.55 l -0.45,-0.77 c 1.82,-17.15 4.28,-34.48 17.33,-46.35 l -0.19,-2.08 C 1997.3,3605.11 1759.91,3282.33 1759.91,2904 c 0,-488.79 396.23,-885.02 885.01,-885.02 488.78,0 885.04,396.23 885.04,885.02 0,488.81 -396.26,885.03 -885.04,885.03 z M 2195.1,3323.54 c 0,0 -34.81,-7.93 -44.29,-69.48 0,0 -1.65,-31.07 8.08,-24.19 -8.2,37.31 27.27,54.21 35.41,58.01 11.45,5.09 20.91,3.38 21.63,-6.34 0.78,-10.49 -11.21,-15.13 -14.8,-25.94 12.73,7.18 41.2,24 38.24,45.9 -2.18,16.1 -17.34,30.4 -44.27,22.04 z m 457.68,-37.78 c -59.82,35.02 -214.44,28.94 -250.75,31.75 -35.74,2.72 -53.6,-42.72 -53.6,-42.72 -0.47,-9.62 7.4,1.41 7.4,1.41 23.35,42.08 43.88,34.38 43.88,34.38 73.99,-21.61 87.17,-130.29 90.25,-155.48 3.06,-25 9.38,-8.72 9.38,-8.72 7.19,62.54 -38.41,138.76 -48,148.55 -9.58,9.73 -0.43,15.23 30.13,6.68 92.03,-25.84 100.65,-173.22 106.2,-191.09 5.54,-17.8 9,-0.68 9,-0.68 -12.45,135.51 -63.96,168.92 -77.69,187.56 -5.7,7.73 40.82,8.9 61.31,-4.43 115.64,-74.71 102.66,-217.79 113.07,-197.37 10.55,20.85 -29.1,150.34 -84.81,194.41 -11.15,8.79 38.66,-6.58 57.02,-23.49 87,-80.41 97.7,-167.53 104.39,-192.7 6.57,-25 9.78,-16.53 9.78,-16.53 1.21,85.15 -66.26,193.01 -126.96,228.47 z m 167.67,59.29 c 12.83,6.96 27.96,52.1 59.04,33.35 23.1,-13.93 34.1,-17.46 34.1,-17.46 0,0 -16.13,-4.53 -23.47,-16.63 -7.34,-12.1 -16.14,-21.41 -41.81,-17.62 -26.95,4.02 -31.88,-0.21 -45.46,-2.42 0,0 4.76,13.79 17.6,20.78 z m -49.59,-36.2 c 19.79,-4.3 38.04,-11.99 56.34,-23.86 20.27,-13.17 42.21,-37.36 72.44,-34.91 9.64,0.77 27.16,10.1 34.21,14.7 8.82,5.75 29.74,19.45 24.15,40.39 -2.48,9.3 -13.54,10.78 -20.13,18.37 -9.13,10.56 -8.78,20.93 -16.09,33.05 15.93,-3.2 25.06,-12.64 42.24,-14.7 -27.07,24.28 -58.26,44.78 -96.58,58.78 2.88,1.63 4.71,8.31 14.09,11.01 8.45,2.44 35.7,-1.72 18.11,1.85 -17.66,4.94 -28.62,-0.09 -40.23,-7.36 -26.68,-16.67 -48.41,-54.95 -76.48,-71.6 -12.18,-7.27 -24.09,-5.6 -34.22,-18.39 6.56,-13.1 13.21,-5.39 22.15,-7.33 z m 209.28,23.88 c -6.66,-3.87 4.19,-7.38 6.03,-9.19 7.67,-7.55 24.8,-21.4 30.18,-33.05 11,-23.83 7.62,-60.3 -12.08,-73.48 -13.27,-8.86 -78.22,-33.08 -106.63,-33.05 -79.93,0.11 -88.04,87.86 -136.84,117.54 0.87,-8.4 7,-25.99 13.98,-35.11 27.44,-35.83 53.66,-109.66 130.81,-97.33 27.26,4.36 78.26,23.19 98.72,35.98 22.22,13.85 38.72,67.03 16.08,96.46 -10.14,13.18 -34.41,29.88 -40.25,31.23"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path76" />
+ </g>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ d="m 376.40655,56.024215 0,23.8525 24.42625,0 0,-23.8525 -24.42625,0 z m 0.09,131.692505 24.24875,0 0,-96.436255 -24.24875,0 0,96.436255 z m 305.7425,-96.436255 -35.3525,96.436255 -18.88,0 -35.5375,-96.436255 25.3575,0 19.61875,59.602505 19.43625,-59.602505 25.3575,0 z m -97.74375,96.436255 -23.5075,0 0,-8.885 c -6.29375,6.66375 -14.31625,9.995 -24.06125,9.995 -9.505,0 -17.09375,-2.83625 -22.76875,-8.51375 -6.54125,-6.53875 -9.80875,-15.67 -9.80875,-27.39375 l 0,-61.638755 24.2475,0 0,58.306255 c 0,6.04875 1.70625,10.61625 5.12125,13.6975 2.80625,2.5925 6.34375,3.8875 10.61125,3.8875 4.39,0 7.99,-1.295 10.79625,-3.8875 3.4125,-3.08125 5.12125,-7.64875 5.12125,-13.6975 l 0,-58.306255 24.24875,0 0,96.436255 z m -114.8675,-48.31 c 0,-8.51375 -0.67125,-14.6225 -2.0125,-18.32375 -2.44125,-6.17 -7.1375,-9.255 -14.09,-9.255 -6.95625,0 -11.6525,3.085 -14.09125,9.255 -1.34125,3.70125 -2.0125,9.81 -2.0125,18.32375 0,8.515 0.67125,14.62375 2.0125,18.32375 2.43875,6.295 7.135,9.44125 14.09125,9.44125 6.9525,0 11.64875,-3.14625 14.09,-9.44125 1.34125,-3.7 2.0125,-9.80875 2.0125,-18.32375 z m 24.24875,0 c 0,9.8725 -0.43375,17.2775 -1.29625,22.2125 -1.35875,8.02125 -4.1975,14.19125 -8.51375,18.5075 -5.80375,5.805 -13.63625,8.7 -23.50875,8.7 -9.8725,0 -17.8925,-3.3925 -24.06125,-10.18 l 0,9.07 -23.3225,0 0,-131.788755 24.2475,0 0,43.86875 c 5.77875,-6.415 13.53,-9.625 23.24625,-9.625 9.83875,0 17.64875,2.9 23.42875,8.7 4.305,4.318755 7.1325,10.488755 8.48625,18.508755 0.8625,4.93625 1.29375,12.28 1.29375,22.02625 z m -130.04375,48.31 -13.69625,0 c -9.255,0 -16.4125,-2.8975 -21.47125,-8.69875 -4.4425,-5.05875 -6.6625,-11.35125 -6.6625,-18.88 l 0,-104.210005 24.2475,0 0,102.730005 c 0,5.80125 2.8075,8.69875 8.42375,8.69875 l 9.15875,0 0,20.36"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path74" />
+ <g
+ transform="matrix(0.23169071,0,0,-0.23371708,-280.79355,1099.9435)"
+ id="g66-4">
+ <g
+ id="g68-1"
+ clip-path="url(#clipPath70-6)">
+ <g
+ id="g3197"
+ transform="translate(-350.10267,-350.10267)">
+ <path
+ id="path76-6"
+ style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 3504.81,2908.41 c 0,-483.58 -391.32,-875.6 -874.02,-875.6 -482.71,0 -874,392.02 -874,875.6 0,483.61 391.29,875.63 874,875.63 482.7,0 874.02,-392.02 874.02,-875.63"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path78"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 3482.08,2908.41 c 0,-471 -381.13,-852.83 -851.29,-852.83 -470.16,0 -851.27,381.83 -851.27,852.83 0,471.02 381.11,852.85 851.27,852.85 470.16,0 851.29,-381.83 851.29,-852.85"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path80"
+ style="fill:#adda1a;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3473.33,3029.95 c -6.42,7.53 -13.81,14.41 -22.76,20.33 3.77,-16.2 15.99,-35.21 27.12,-54.62 -1.18,11.52 -2.73,22.91 -4.36,34.29 z M 3070.25,2284 c -63.63,-5.85 -49.36,-41.32 30.29,-33.77 29.21,2.77 76.64,33.01 121.13,44.56 22.41,21.66 43.74,44.44 63.68,68.43 -27,-14.62 -77.9,-37.33 -127.3,-60.84 -28.31,-13.46 -63.77,-16.17 -87.8,-18.38 z m 409,691.11 c -9.21,11.12 -16.63,28.08 -26.56,40.46 -2.32,4.07 -10.61,18.92 -19.05,37.24 -0.7,1.84 -1.35,3.66 -2.39,5.51 l -0.05,-0.07 c -2.45,5.45 -4.83,11.12 -7.04,16.85 l -0.01,0.06 c -1.76,4.55 -3.39,9.12 -4.84,13.64 -7.01,21.99 -27.18,60.03 -55.62,91.97 -0.17,1.83 -0.23,3.57 0.33,4.78 l -4.7,-0.11 c -16.1,17.22 -34.56,32.28 -54.71,41.42 -58.53,26.53 -110.11,53.23 -110.11,53.23 -1.79,-15.12 12.75,-34.44 21.07,-51.41 1.85,-6.68 3.04,-13.01 3.15,-18.42 l -0.53,0.48 c -0.79,-1.72 -0.36,-4.51 -0.09,-7.16 -0.63,-2.86 -1.75,-5.25 -3.64,-6.83 -9.8,30.98 -27.24,55.39 -36.22,83.01 -9.63,29.6 -17.24,58.12 -39.62,80.27 -27.97,27.69 -80.34,42.83 -120.05,60.13 -15.2,9.33 -29.15,18.25 -39.73,25.48 l 0.27,0.4 c -42.2,33.83 -99.59,85.95 -160.2,43.76 -36.58,-25.48 -72.09,-74.05 -114.92,-94.66 -4.7,-2.29 -10.18,-4.72 -16.01,-6.75 l -0.25,-0.29 -1.82,-0.38 c -4.22,-1.37 -8.56,-2.48 -12.88,-3.09 -11.15,-3.02 -19.94,-6.36 -27.56,-9.36 -0.89,-1.67 -2.36,-1.72 -2.72,-1.08 -14.7,-5.76 -25.44,-9.82 -42.09,-6.82 -10.16,1.82 -36.31,-0.01 -47.19,-1.01 0,0 -69.05,-0.05 15.93,9.37 -3.27,2.46 -6.36,4.92 -9.21,7.4 -45.43,-3.61 -85.18,12.35 -130.49,5.85 5.09,-8.21 21.77,-6.21 25.04,-16.05 -34.67,-11.48 -53.95,37.68 -88.39,17.4 5.15,-9.48 0.58,-21.45 -6.91,-27.78 2.9,29.09 -36.96,53.69 -62.56,31.76 9.7,-10.86 10.2,-28.86 4.46,-43.12 l -17.4,-19.5 c -4.08,-1.69 -8.59,-2.37 -13.51,-1.4 16.74,7.37 29.01,20.73 29.06,36.46 0.09,27.81 -34.12,35.28 -62.43,34.49 -56.18,-1.59 -100.39,-26.71 -133.84,-59.13 l 0.24,0.95 -19.4,-20.96 c 0,0 -60.6,-25.35 -82.33,-93.09 0.7,8.35 1.64,17.81 2.85,27.9 9.79,28.43 25.25,49.66 49.44,66.79 -28.7,-3.61 -69.69,-15.54 -82.38,-53.55 -5.96,-17.81 -12.11,-31.1 -16.94,-60.9 l -0.29,0.34 c 0,0 -11.55,-58.65 -4.07,-92.05 6.5,-29.06 15.74,-58.97 19.98,-78.46 0.31,-2.57 0.8,-5.25 1.55,-8.02 53.53,25.5 127.71,32.14 197.84,42.47 -29.28,-4.79 -70.93,-16.14 -111.03,-25.84 -40.01,-9.7 -98.01,-24.8 -98.91,-60.92 -0.53,-21.23 15.39,-39.9 42.38,-40.6 -2.4,5.18 -2.21,12.74 -2.01,20.32 -5.57,-0.46 -4.61,-6.86 -8.07,-9.23 -2.07,41.18 68.63,45.39 115.05,53.52 6.31,1.1 12.28,2.63 18.18,3.7 21.63,3.79 53.78,1.97 88.43,1.46 47.63,-0.67 81.2,5.28 125.04,-11.15 14.08,-5.29 43.74,-7.09 58.03,-8.62 50.68,-5.38 88.38,3.26 150.38,-2.01 24.7,-2.09 49.47,-11.64 72.68,-22.15 32.18,-14.54 57.5,-32.58 96.88,-22.16 14.24,-0.73 28.56,1.95 33.28,-0.73 22.77,-2.03 19.21,-19.81 45.45,-17.71 30.54,2.43 54.62,21.61 90.84,24.01 28.24,1.84 57.99,-5.19 90.84,-1.86 22.77,2.31 45.33,12.35 64.59,20.29 48.59,20.07 128.49,59.45 135.25,112.57 5.48,43.01 -26.95,65.35 -72.67,53.55 46.44,24.15 89.27,-11.93 88.81,-57.23 -0.13,-13.82 -9.81,-26.35 -16.14,-42.45 -6.37,-16.16 -6.51,-27.48 -14.14,-36.9 -3.81,-4.74 -8.73,-8.7 -13.9,-11.99 -8.91,-4.41 -21.76,-8.11 -39.39,-12.95 -26.03,-7.17 -50.53,-14.82 -50.53,-14.82 -4,-0.78 -5.56,-1.56 -5.83,-2.26 -16.03,-4.39 -35.35,-10.88 -46.46,-18.98 -21.4,-15.61 -55.77,-27.94 -88.83,-22.1 -3.06,0.55 -5.56,0.66 -7.59,0.44 -10.86,1.42 -21.56,2.92 -32.09,3.3 0,0 -60.14,-1.51 -56.74,-3.53 3.41,-2.07 4.26,-2.02 4.26,-2.02 22.01,-17.39 32.52,-46.38 44.41,-73.8 13.37,-30.85 23.4,-62.63 26.25,-103.36 8.55,33.04 20.19,63.26 35.25,90.38 19.61,32.19 58.62,82.91 118.6,102.69 21.12,6.63 38.61,16.58 52.03,30.26 -18.49,-27.47 -50.41,-39.13 -76.7,-57.24 -54.55,-37.54 -83.75,-92.88 -109,-162.4 -5.76,-15.84 -11.5,-31.64 -20.18,-46.15 -8.38,-13.93 -21.17,-26.48 -26.25,-40.58 -3.28,-9.09 -1.97,-19.3 -4.03,-27.7 -5.7,-23.21 -15.54,-46.26 -29.19,-64.5 -11.59,-13.02 -35.57,-39.82 -40.13,-43.98 l -0.22,-0.36 c -31.85,-30.92 -69.62,-56.39 -110.13,-79.41 l 0.39,-0.82 -2.18,-1.47 -0.22,0.45 c -5.62,-3.61 -10.68,-7.72 -15.38,-12.15 -4.84,-4.03 -8.91,-8.05 -10.85,-11.33 -16.68,-19.34 -29.5,-42.11 -48.46,-59.56 -10.87,-10.02 -23.71,-18.07 -36.43,-26.37 l 0.09,0.31 c 0,0 -15.25,-10.33 -28.3,-18.19 -40.26,-19.09 -81.84,-52.85 -143.27,-53.58 -32.98,-0.36 -78.22,2.15 -92.87,27.71 0,0 -8.68,4.13 -8.07,-14.77 0.78,-24.11 41.07,-24.82 61.99,-34.85 10.59,-6.14 -10.26,-1.04 -17.57,-2.08 16.08,-17.27 25.62,-40.53 60.55,-40.57 0,0 -8.15,7.62 -10.95,9.16 -2.81,1.52 1.78,3.83 14.29,-0.78 10.26,-3.78 23.65,-7.19 41.17,-7.09 1.13,0 2.23,-0.02 3.41,0 2.76,0.08 5.63,0.26 8.61,0.54 0,0 31.03,0.17 60.97,13.12 29.96,12.96 63.98,9.55 79.64,21.14 15.66,11.58 27.23,34.07 37.43,37.5 10.22,3.42 24.55,11.33 36.24,24.55 9.96,11.24 25.12,4.89 37.52,16.37 11.29,10.44 86.52,47.81 86.52,47.81 22.36,15.41 36.07,33.48 61.35,46.2 36.66,25.62 -50.85,-18.01 -76.31,-27.89 -31.65,-12.26 -3.07,4.31 -3.07,4.31 l 51.26,29.33 c 15.44,7.57 30.91,15.07 46.7,22.26 10.21,4.35 27.69,11.65 41.34,16.53 26.89,6.81 50.65,4.82 73.31,8.99 24.06,4.41 45.17,16.05 68.63,20.3 3.73,0.66 10.05,-1.26 14.14,0 25.47,7.85 50.95,32.67 74.69,46.13 54.76,31.04 95.31,60.15 111.03,127.36 3.69,15.78 5.91,31.75 10.09,47.96 8.91,34.68 15.52,66.46 12.1,112.58 -2.02,27.41 -17.84,55.88 -16.14,90.44 1.6,32.49 24.4,57.21 34.31,86.74 11.84,35.26 -9.8,59.99 -42,73.32 l 0.02,0.03 c 0,0 -23.83,11.25 -33.01,11.93 -9.19,0.69 4.77,3.06 10.89,3.06 4.7,0 8.77,3.24 11.96,8.26 3.64,5.15 5.68,12.38 9.75,17.83 5.72,7.65 19.89,18.14 20.19,25.82 0.39,10.04 -16.8,23.84 -26.25,29.55 -16.3,9.86 -42.61,15.88 -64.59,25.84 -24.47,11.05 -42.11,23.26 -54.5,35.05 -6.87,17.68 -19.82,28.7 -18.17,49.84 0.41,5.36 2.38,10.54 4.14,15.93 l 0.74,1.99 c 2.04,6.89 4.85,17.63 0,29.9 -4.84,12.28 -22.46,15.85 -22.46,15.85 l -0.07,-0.01 c -9.55,3.18 -20.88,5.11 -28.78,8.33 -12.47,5.03 -22.27,11.8 -32.01,16.88 12.11,-3.84 26.84,-10.03 49.63,-12.08 10.06,-0.89 38.28,-5.95 43.6,-23.9 l 0.56,-2.02 0.47,-1.79 c 0.23,-1.02 0.4,-2.05 0.56,-3.09 0.18,-1.35 0.38,-2.66 0.41,-4.12 l 0.09,-2.09 c 0.1,-7.16 -1.4,-14.68 -4.77,-22.16 -12.95,-28.75 1.23,-50.51 22.34,-61.76 19.97,-15.69 49.52,-24.31 78.59,-35.23 23.22,-8.71 49.09,-21.54 62.26,-36.33 6.84,-11.84 10.51,-24.87 6.01,-37.26 -7.2,-13.97 -24.49,-20.05 -29.91,-37.14 6.8,-8.64 19.17,-10.55 28.26,-16.59 14.11,-9.41 24.5,-22.04 27.69,-40.18 l 0.18,-1.91 c 0.34,-2.16 0.53,-4.32 0.63,-6.51 0.03,-1.96 -0.05,-3.92 -0.08,-5.88 -1.68,-32.34 -26.5,-65.77 -33.73,-81.2 -8.16,-17.37 -5.61,-35.28 -5.61,-35.28 1.81,-7 3.64,-12.54 5.48,-16.85 3.27,-9.56 7.03,-22.96 9.88,-38.76 10.13,-22.39 21.09,-48.44 25.98,-66.09 10.22,-36.81 24.51,-102.3 4.09,-247.53 -20.41,-145.21 -215.75,-151.34 -274.96,-175.91 -40.77,-16.9 4.76,-30.67 82.01,-16.35 34.95,6.5 80.11,35.32 122.51,43.97 17.97,3.67 29.54,5.36 36.09,5.44 114.98,145.4 183.81,329.08 183.81,528.99 0,22.48 -1.13,44.67 -2.83,66.7"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path82"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2527.18,3484.46 c 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 -14.35,4.48 -16.31,16.03 -23.22,23.97 z m -22.94,26.32 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m 160.36,-21.48 c 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 z m 88.05,-72.17 c 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 z m -311.91,160.11 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path84"
+ style="fill:#f6836c;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2529.01,2752.37 c -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path86"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2326.23,2354.71 c 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 z m 40.64,1.81 c 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 z m 40.42,22 c 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 z m 57.45,25.09 c 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 z m 44.26,31.78 c 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 z m 48.77,40.94 c 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 z m 185.39,120.94 c 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 z m -83.83,-151.23 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m 15.48,114.75 c 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 z m 101.12,357.36 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m -37.63,-68.3 c 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 z m -71.11,-9.21 c 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 z m -108.01,18.58 c -16.99,21.48 -27.18,59.39 -21,84.23 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 z m -83.19,11.35 c -17.28,21.7 -27.77,60.21 -21.65,85.66 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 z m -80.49,-21.24 c -20.89,28.13 -34.89,78.07 -29.36,111.18 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 z m -80.64,17.63 c -20.8,24.29 -34.51,68.64 -28.73,98.66 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 z m -78.28,28.17 c -15.16,21.15 -23.52,58.34 -17.11,82.67 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 z m -61.99,15.5 c -13.96,16.84 -22.79,46.55 -18.34,66.13 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 z m -72.12,-11.61 c -16.8,18.79 -28.15,52.6 -23.84,75.42 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 z m -52.45,0.72 c -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path88"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2806.87,3351.66 c 12.87,7 28.05,52.37 59.22,33.53 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path90"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 2731.38,3432.29 c -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 z m -55.32,-35.43 c -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 z m -125.66,63.63 c -14.35,4.48 -16.31,16.03 -23.22,23.97 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 z m -46.16,50.29 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m -400.52,-594.93 c 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63 -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 z m 24.44,3.25 c 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 -16.8,18.79 -28.15,52.6 -23.84,75.42 z m 77.62,2.32 c 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 -13.96,16.84 -22.79,46.55 -18.34,66.13 z m 63.22,1.04 c 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 -15.16,21.15 -23.52,58.34 -17.11,82.67 z m 66.66,-12.18 c 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 -20.8,24.29 -34.51,68.64 -28.73,98.66 z m 80.01,-5.11 c 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 -20.89,28.13 -34.89,78.07 -29.36,111.18 z m 88.2,-4.28 c 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 -17.28,21.7 -27.77,60.21 -21.65,85.66 z m 83.84,-12.78 c 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 -16.99,21.48 -27.18,59.39 -21,84.23 z m 79.05,-19.65 c 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 z m 101.86,1.14 c 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 z m 98.58,-102.42 c 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42 -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 z m -41.74,95.63 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m 8.86,-374.35 c -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 z m -57.5,-52.94 c -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 z m -67.96,-44.82 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m -59.7,-50.77 c -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 z m -59.67,-53.19 c -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 z m -57.23,-32.78 c -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 z m -54.59,-28.17 c -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 z m -44.74,-1.44 c -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 z m -42.56,7.47 c -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 z m 50.37,1345.42 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37 z m 1173.75,-787.01 c -11.13,19.41 -23.35,38.42 -27.12,54.62 8.95,-5.92 16.34,-12.8 22.76,-20.33 -1.34,9.41 -2.92,18.74 -4.57,28.06 -9.71,7.73 -20.63,14.52 -33.49,19.89 -20.69,92.5 -65.21,150.91 -156.67,184.3 -30.66,11.19 -59.7,24.15 -89.94,37.34 1.75,98.46 -112.47,96.39 -183.64,147.07 -30.95,22.1 -66.05,62.87 -101.46,70.41 -68.48,14.6 -110.62,-33.23 -151.06,-66.63 -9.93,10.85 -24.8,21.45 -46.38,31.1 0,0 -38.6,55.15 -56.6,65.52 -1.19,0.69 -2,1.32 -2.52,1.93 -9.94,4.68 -22.41,7.31 -31.21,13.14 -8.7,5.73 -10.35,19.28 -19.05,25.84 -4.26,3.2 -10.87,6.67 -16.65,8.99 -6.98,2.81 -18.94,2.29 -25.97,6.14 -8.65,4.75 -9.34,20.2 -15.61,27.87 -6.91,8.47 -15.8,15.4 -30.18,20.24 -5.83,1.94 -14.63,2.07 -19.9,4.9 -5.88,3.18 -7.32,13.15 -11.87,19.26 -10.58,14.26 -28.45,25.31 -48.83,32.52 -4.39,1.55 -10.28,1.55 -13.49,3.71 -4.03,2.7 -4.19,9.73 -6.94,14.64 -4.25,7.58 -9.92,15.28 -19.06,19.99 -3.91,2.04 -9.92,1.85 -13.75,4.03 -4.5,2.58 -5.71,8.88 -9.5,12.57 -7.66,7.48 -16.76,13.16 -35.67,8.31 -6.7,8.69 -15.55,15.67 -29.96,18.64 l -0.44,-0.77 c 1.82,-17.24 4.29,-34.66 17.38,-46.59 -3.32,-19.81 5.98,-34.36 21.01,-46.08 3.62,-2.83 9.62,-4.32 12.72,-8.05 4.11,-4.96 2.41,-15.04 4.2,-21.26 5.56,-19.2 17.41,-36.84 37.11,-51.25 2.88,-2.12 8.38,-3.14 10.88,-5.97 5.5,-6.25 3.9,-16.74 8.05,-23.95 4.36,-7.59 11.79,-16.75 20.96,-23.81 5.03,-3.88 12.53,-5.95 17.23,-10.57 3.81,-3.73 4.86,-10.44 7.58,-16.02 7.35,-15.1 26.81,-32.59 36.15,-48.37 1.23,-2.08 2.2,-4.3 3.01,-6.54 3.89,-8.03 13.3,-25.05 26.13,-32.91 0,0 1.34,-23.63 24.86,-50.57 -47.65,2.58 -93.62,29.56 -128.96,2.76 -10.2,11.15 -42.93,19.9 -56.94,4.25 -10.33,18.01 -65.18,29.5 -75.85,1.04 -77.98,35.05 -172.08,-14.92 -202.33,-65.08 -5.61,-2.68 -10.86,-5.51 -15.82,-8.41 -21.34,6.43 -50.25,8.71 -81.54,-13.89 -30.84,-22.29 -63.08,-122.26 -57.53,-191.48 0.6,-7.41 14.64,-24.92 19.68,-59.99 5.02,-34.8 8.83,-46.22 8.83,-46.22 -6.86,-11.99 -15.04,-17.35 -16.15,-31.38 -2.42,-30.36 23.49,-46.85 47.76,-62.4 8.65,-4.04 18.42,-6.93 29.04,-7.32 6.41,-10.15 31.11,-44.55 71.94,-44.55 1.01,0 2.04,0.07 3.04,0.13 15.59,-13.13 31.86,-16.66 20.63,-0.47 -0.93,1.33 -1.72,2.83 -2.46,4.38 7.51,-4.47 16.59,-8.82 24.69,-9.61 0.16,-0.02 3.98,-0.98 7.14,-0.98 1.14,0 4.48,0 5.66,2.57 1.18,2.6 -1.2,5.38 -1.99,6.28 -3.27,3.77 -6.95,13.59 -9.72,22.76 3,-5.5 6.25,-10.71 9.9,-15.21 19.43,-23.89 46.63,-35.2 31.44,-11.41 -4.87,7.61 -7.65,17.99 -9.01,29.01 7.53,-9.28 20.49,-20.09 41.56,-24.4 17.42,-16.59 39.07,-23.38 26.1,-5.74 -3.32,4.51 -5.48,10.33 -6.77,16.68 10.5,-12.62 28.26,-28.83 50.03,-28.83 l 1.59,0.03 0.44,0.02 c 14.94,-10.11 27.45,-11.8 16.27,2.79 -4.84,6.36 -7.48,15.16 -8.67,24.45 9.87,-20.16 28.91,-47.92 61.69,-56.83 0.24,-0.1 5.89,-1.65 10.55,-1.65 3.63,0 5.93,0.93 7.02,2.92 1.59,2.87 -0.5,6.19 -1.19,7.28 -2.11,3.41 -4.08,7.64 -5.78,11.82 14.71,-8.64 25.59,-9.38 14.13,4.7 -5.91,7.26 -9.06,17.5 -10.36,28.08 8,-21.41 24.29,-51.48 56.48,-71.19 0.23,-0.11 6.03,-2.83 12.45,-2.83 3.1,0 5.87,0.64 8.26,1.84 2.05,1.07 3.39,2.8 3.94,5 1.68,6.71 -4.68,16.25 -5.25,17.03 -2.65,5.22 -7.5,16.25 -9.89,25.91 l 0.24,-0.2 c 23.26,-18.8 53.46,-27.51 34.83,-8.75 -11.31,11.4 -15.67,30.94 -16.06,46.89 6.8,-19.1 23.32,-52.18 57.54,-58.74 0.23,-0.02 5.53,-1.04 9.45,-1.04 2.17,0 4.79,0.24 5.71,2.34 0.39,0.88 0.55,2.32 -1,4.06 -2.56,2.89 -6.19,11.58 -8.12,18.61 1.62,-1.24 3.2,-2.56 4.89,-3.65 16.6,-10.91 36.19,-16.61 38.75,-13.08 5.3,-4.36 13.61,-10.09 24.89,-15.06 1.06,-2.42 2.1,-4.84 2.95,-7.27 0,0 5.26,-14.67 7.29,-22.61 -26.85,6.97 -72.8,20.47 -106.99,12.91 -27.01,-5.96 -97.4,-44.95 -80.38,-72.36 1.14,-1.83 2.59,-3.1 4.26,-4.14 l 1.05,-0.4 c 6.73,-3.59 18.58,-5.69 31.05,-5.59 l 4.53,0.13 c 7.25,0.4 26.23,3.13 32.67,5.22 18.82,6.13 35.64,2.45 35.64,2.45 l -0.25,-0.17 c 13.38,-1.57 27.5,-6.27 42.08,-13.73 15.66,-7.98 36.97,-21.16 42.4,-27.67 9.78,-11.78 -5.21,-39.4 -10.8,-56.41 -0.27,-1 -0.61,-2.05 -0.94,-3.09 l -0.39,-1.41 -0.06,0.04 c -0.79,-2.39 -1.76,-4.89 -2.81,-7.45 -0.95,1.2 -1.8,2.36 -2.43,3.44 -5.35,9.03 -8.24,16.93 -11,13.3 -2.77,-3.64 -2.9,-18.05 2.36,-31.66 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.06,-11.12 -13.42,-22.77 -21.18,-33.92 -6.03,5.72 -12.13,12.17 -15.09,17.31 -6.89,11.83 -10.56,22.21 -14.08,17.43 -3.56,-4.74 -3.65,-23.89 3.1,-41.86 2.2,-5.87 5.57,-11.18 9.09,-15.82 -5.35,-6.76 -10.57,-13.01 -15.34,-18.31 -2.14,-2.37 -4.66,-5.02 -7.34,-7.8 -7.36,7.62 -16.68,18.03 -20.45,25.58 -6.56,13.19 -9.94,24.43 -13.67,19.64 -3.72,-4.82 -4.45,-25.07 1.76,-44.65 2.55,-8.02 6.95,-15.34 11.3,-21.3 -7.98,-7.6 -16.65,-15.65 -25.55,-23.79 -5.4,7.18 -10.72,15.06 -13.16,21.1 -5.85,14.26 -8.62,26.35 -12.58,21.72 -3.89,-4.67 -5.6,-25.71 -0.35,-46.68 1.29,-5.17 3.26,-10.14 5.51,-14.74 -8.82,-7.89 -17.35,-15.45 -25.18,-22.31 -2.3,5.01 -4.22,9.75 -5.28,13.66 -4.6,16.98 -6.32,31 -10.84,26.71 -4.53,-4.2 -8.38,-26.82 -5.07,-50.86 0.31,-2.3 0.76,-4.59 1.27,-6.88 l -2.21,-1.9 c -5.11,-4.43 -10.68,-9.77 -16.44,-15.64 -1.43,4.52 -2.54,8.74 -3.13,12.25 -2.91,17.7 -3.36,31.85 -7.99,28.47 -4.62,-3.32 -10.15,-25.15 -9.04,-49.57 0.17,-3.84 0.64,-7.72 1.27,-11.52 -6.76,-7.62 -13.45,-15.51 -19.75,-23.18 -3.65,9.38 -6.95,19.1 -8.23,26.11 -3.34,18.53 -4.03,33.4 -8.76,29.75 -4.33,-3.29 -9.08,-23.12 -8.56,-46.19 -4.71,-3.45 -10.82,-19.53 -11.02,-37.76 -0.09,-6.2 1.01,-12.55 2.51,-18.29 -3.05,-4.31 -8.4,-7.29 -12.14,-12.57 -19.3,-27.05 -11.43,-59.27 30.28,-66.44 12.78,-39.46 45.17,-58.61 94.87,-59.05 6.68,-0.07 13.64,2.27 20.18,1.86 7.38,-0.5 13.46,-3.5 20.2,-3.71 36.22,-1.09 55.22,10.43 82.74,18.48 20.55,5.96 41.74,7.89 54.52,12.9 19.57,7.68 28.87,28.77 44.4,38.76 5.78,3.71 16.69,5.46 26.25,11.06 8.07,4.75 15.05,13.39 22.2,16.6 6.24,2.85 16.65,2.28 24.22,5.55 12.67,5.51 26.68,17.4 42.4,25.86 32.91,17.63 59.7,30.68 94.87,46.11 16.8,7.38 34.58,24.72 44.41,25.84 11.65,1.35 25.22,-8.4 34.31,-7.37 18.52,-22.06 24.98,-52.89 24.2,-92.52 1.1,-0.11 0.29,-9.83 0.29,-9.83 0,0 6.47,-85.09 -126.17,-131.03 -41.25,-14.28 -117.07,-51.81 -173.39,-80.72 218.91,6.81 416.91,96.33 564.01,238.52 -44.49,-11.55 -91.92,-41.79 -121.13,-44.56 -79.65,-7.55 -93.92,27.92 -30.29,33.77 24.03,2.21 59.49,4.92 87.8,18.38 49.4,23.51 100.3,46.22 127.3,60.84 4.41,5.31 8.63,10.78 12.92,16.2 -6.55,-0.08 -18.12,-1.77 -36.09,-5.44 -42.4,-8.65 -87.56,-37.47 -122.51,-43.97 -77.25,-14.32 -122.78,-0.55 -82.01,16.35 59.21,24.57 254.55,30.7 274.96,175.91 20.42,145.23 6.13,210.72 -4.09,247.53 -4.89,17.65 -15.85,43.7 -25.98,66.09 -2.85,15.8 -6.61,29.2 -9.88,38.76 -1.84,4.31 -3.67,9.85 -5.48,16.85 0,0 -2.55,17.91 5.61,35.28 7.23,15.43 32.05,48.86 33.73,81.2 0.03,1.96 0.11,3.92 0.08,5.88 -0.1,2.19 -0.29,4.35 -0.63,6.51 l -0.18,1.91 c -3.19,18.14 -13.58,30.77 -27.69,40.18 -9.09,6.04 -21.46,7.95 -28.26,16.59 5.42,17.09 22.71,23.17 29.91,37.14 4.5,12.39 0.83,25.42 -6.01,37.26 -13.17,14.79 -39.04,27.62 -62.26,36.33 -29.07,10.92 -58.62,19.54 -78.59,35.23 -21.11,11.25 -35.29,33.01 -22.34,61.76 3.37,7.48 4.87,15 4.77,22.16 l -0.09,2.09 c -0.03,1.46 -0.23,2.77 -0.41,4.12 -0.16,1.04 -0.33,2.07 -0.56,3.09 l -0.47,1.79 -0.56,2.02 c -5.32,17.95 -33.54,23.01 -43.6,23.9 -22.79,2.05 -37.52,8.24 -49.63,12.08 9.74,-5.08 19.54,-11.85 32.01,-16.88 7.9,-3.22 19.23,-5.15 28.78,-8.33 l 0.07,0.01 c 0,0 17.62,-3.57 22.46,-15.85 4.85,-12.27 2.04,-23.01 0,-29.9 l -0.74,-1.99 c -1.76,-5.39 -3.73,-10.57 -4.14,-15.93 -1.65,-21.14 11.3,-32.16 18.17,-49.84 12.39,-11.79 30.03,-24 54.5,-35.05 21.98,-9.96 48.29,-15.98 64.59,-25.84 9.45,-5.71 26.64,-19.51 26.25,-29.55 -0.3,-7.68 -14.47,-18.17 -20.19,-25.82 -4.07,-5.45 -6.11,-12.68 -9.75,-17.83 -3.19,-5.02 -7.26,-8.26 -11.96,-8.26 -6.12,0 -20.08,-2.37 -10.89,-3.06 9.18,-0.68 33.01,-11.93 33.01,-11.93 l -0.02,-0.03 c 32.2,-13.33 53.84,-38.06 42,-73.32 -9.91,-29.53 -32.71,-54.25 -34.31,-86.74 -1.7,-34.56 14.12,-63.03 16.14,-90.44 3.42,-46.12 -3.19,-77.9 -12.1,-112.58 -4.18,-16.21 -6.4,-32.18 -10.09,-47.96 -15.72,-67.21 -56.27,-96.32 -111.03,-127.36 -23.74,-13.46 -49.22,-38.28 -74.69,-46.13 -4.09,-1.26 -10.41,0.66 -14.14,0 -23.46,-4.25 -44.57,-15.89 -68.63,-20.3 -22.66,-4.17 -46.42,-2.18 -73.31,-8.99 -13.65,-4.88 -31.13,-12.18 -41.34,-16.53 -15.79,-7.19 -31.26,-14.69 -46.7,-22.26 L 2782.7,2380 c 0,0 -28.58,-16.57 3.07,-4.31 25.46,9.88 112.97,53.51 76.31,27.89 -25.28,-12.72 -38.99,-30.79 -61.35,-46.2 0,0 -75.23,-37.37 -86.52,-47.81 -12.4,-11.48 -27.56,-5.13 -37.52,-16.37 -11.69,-13.22 -26.02,-21.13 -36.24,-24.55 -10.2,-3.43 -21.77,-25.92 -37.43,-37.5 -15.66,-11.59 -49.68,-8.18 -79.64,-21.14 -29.94,-12.95 -60.97,-13.12 -60.97,-13.12 -2.98,-0.28 -5.85,-0.46 -8.61,-0.54 -1.18,-0.02 -2.28,0 -3.41,0 -17.52,-0.1 -30.91,3.31 -41.17,7.09 -12.51,4.61 -17.1,2.3 -14.29,0.78 2.8,-1.54 10.95,-9.16 10.95,-9.16 -34.93,0.04 -44.47,23.3 -60.55,40.57 7.31,1.04 28.16,-4.06 17.57,2.08 -20.92,10.03 -61.21,10.74 -61.99,34.85 -0.61,18.9 8.07,14.77 8.07,14.77 14.65,-25.56 59.89,-28.07 92.87,-27.71 61.43,0.73 103.01,34.49 143.27,53.58 13.05,7.86 28.3,18.19 28.3,18.19 l -0.09,-0.31 c 12.72,8.3 25.56,16.35 36.43,26.37 18.96,17.45 31.78,40.22 48.46,59.56 1.94,3.28 6.01,7.3 10.85,11.33 4.7,4.43 9.76,8.54 15.38,12.15 l 0.22,-0.45 2.18,1.47 -0.39,0.82 c 40.51,23.02 78.28,48.49 110.13,79.41 l 0.22,0.36 c 4.56,4.16 28.54,30.96 40.13,43.98 13.65,18.24 23.49,41.29 29.19,64.5 2.06,8.4 0.75,18.61 4.03,27.7 5.08,14.1 17.87,26.65 26.25,40.58 8.68,14.51 14.42,30.31 20.18,46.15 25.25,69.52 54.45,124.86 109,162.4 26.29,18.11 58.21,29.77 76.7,57.24 -13.42,-13.68 -30.91,-23.63 -52.03,-30.26 -59.98,-19.78 -98.99,-70.5 -118.6,-102.69 -15.06,-27.12 -26.7,-57.34 -35.25,-90.38 -2.85,40.73 -12.88,72.51 -26.25,103.36 -11.89,27.42 -22.4,56.41 -44.41,73.8 0,0 -0.85,-0.05 -4.26,2.02 -3.4,2.02 56.74,3.53 56.74,3.53 10.53,-0.38 21.23,-1.88 32.09,-3.3 2.03,0.22 4.53,0.11 7.59,-0.44 33.06,-5.84 67.43,6.49 88.83,22.1 11.11,8.1 30.43,14.59 46.46,18.98 0.27,0.7 1.83,1.48 5.83,2.26 0,0 24.5,7.65 50.53,14.82 17.63,4.84 30.48,8.54 39.39,12.95 5.17,3.29 10.09,7.25 13.9,11.99 7.63,9.42 7.77,20.74 14.14,36.9 6.33,16.1 16.01,28.63 16.14,42.45 0.46,45.3 -42.37,81.38 -88.81,57.23 45.72,11.8 78.15,-10.54 72.67,-53.55 -6.76,-53.12 -86.66,-92.5 -135.25,-112.57 -19.26,-7.94 -41.82,-17.98 -64.59,-20.29 -32.85,-3.33 -62.6,3.7 -90.84,1.86 -36.22,-2.4 -60.3,-21.58 -90.84,-24.01 -26.24,-2.1 -22.68,15.68 -45.45,17.71 -4.72,2.68 -19.04,0 -33.28,0.73 -39.38,-10.42 -64.7,7.62 -96.88,22.16 -23.21,10.51 -47.98,20.06 -72.68,22.15 -62,5.27 -99.7,-3.37 -150.38,2.01 -14.29,1.53 -43.95,3.33 -58.03,8.62 -43.84,16.43 -77.41,10.48 -125.04,11.15 -34.65,0.51 -66.8,2.33 -88.43,-1.46 -5.9,-1.07 -11.87,-2.6 -18.18,-3.7 -46.42,-8.13 -117.12,-12.34 -115.05,-53.52 3.46,2.37 2.5,8.77 8.07,9.23 -0.2,-7.58 -0.39,-15.14 2.01,-20.32 -26.99,0.7 -42.91,19.37 -42.38,40.6 0.9,36.12 58.9,51.22 98.91,60.92 40.1,9.7 81.75,21.05 111.03,25.84 -70.13,-10.33 -144.31,-16.97 -197.84,-42.47 -0.75,2.77 -1.24,5.45 -1.55,8.02 -4.24,19.49 -13.48,49.4 -19.98,78.46 -7.48,33.4 4.07,92.05 4.07,92.05 l 0.29,-0.34 c 4.83,29.8 10.98,43.09 16.94,60.9 12.69,38.01 53.68,49.94 82.38,53.55 -24.19,-17.13 -39.65,-38.36 -49.44,-66.79 -1.21,-10.09 -2.15,-19.55 -2.85,-27.9 21.73,67.74 82.33,93.09 82.33,93.09 l 19.4,20.96 -0.24,-0.95 c 33.45,32.42 77.66,57.54 133.84,59.13 28.31,0.79 62.52,-6.68 62.43,-34.49 -0.05,-15.73 -12.32,-29.09 -29.06,-36.46 4.92,-0.97 9.43,-0.29 13.51,1.4 l 17.4,19.5 c 5.74,14.26 5.24,32.26 -4.46,43.12 25.6,21.93 65.46,-2.67 62.56,-31.76 7.49,6.33 12.06,18.3 6.91,27.78 34.44,20.28 53.72,-28.88 88.39,-17.4 -3.27,9.84 -19.95,7.84 -25.04,16.05 45.31,6.5 85.06,-9.46 130.49,-5.85 2.85,-2.48 5.94,-4.94 9.21,-7.4 -84.98,-9.42 -15.93,-9.37 -15.93,-9.37 10.88,1 37.03,2.83 47.19,1.01 16.65,-3 27.39,1.06 42.09,6.82 0.36,-0.64 1.83,-0.59 2.72,1.08 7.62,3 16.41,6.34 27.56,9.36 4.32,0.61 8.66,1.72 12.88,3.09 l 1.82,0.38 0.25,0.29 c 5.83,2.03 11.31,4.46 16.01,6.75 42.83,20.61 78.34,69.18 114.92,94.66 60.61,42.19 118,-9.93 160.2,-43.76 l -0.27,-0.4 c 10.58,-7.23 24.53,-16.15 39.73,-25.48 39.71,-17.3 92.08,-32.44 120.05,-60.13 22.38,-22.15 29.99,-50.67 39.62,-80.27 8.98,-27.62 26.42,-52.03 36.22,-83.01 1.89,1.58 3.01,3.97 3.64,6.83 -0.27,2.65 -0.7,5.44 0.09,7.16 l 0.53,-0.48 c -0.11,5.41 -1.3,11.74 -3.15,18.42 -8.32,16.97 -22.86,36.29 -21.07,51.41 0,0 51.58,-26.7 110.11,-53.23 20.15,-9.14 38.61,-24.2 54.71,-41.42 l 4.7,0.11 c -0.56,-1.21 -0.5,-2.95 -0.33,-4.78 28.44,-31.94 48.61,-69.98 55.62,-91.97 1.45,-4.52 3.08,-9.09 4.84,-13.64 l 0.01,-0.06 c 2.21,-5.73 4.59,-11.4 7.04,-16.85 l 0.05,0.07 c 1.04,-1.85 1.69,-3.67 2.39,-5.51 8.44,-18.32 16.73,-33.17 19.05,-37.24 9.93,-12.38 17.35,-29.34 26.56,-40.46 -0.53,6.85 -0.88,13.75 -1.56,20.55 z m -826.19,277.09 c 87.27,-80.81 98.01,-168.37 104.71,-193.66 6.6,-25.12 9.82,-16.62 9.82,-16.62 1.21,85.58 -66.47,193.97 -127.36,229.62 -60,35.19 -215.11,29.07 -251.54,31.9 -35.85,2.74 -53.77,-42.93 -53.77,-42.93 -0.46,-9.67 7.43,1.42 7.43,1.42 23.42,42.28 44.01,34.55 44.01,34.55 74.22,-21.72 87.45,-130.94 90.54,-156.26 3.07,-25.11 9.41,-8.76 9.41,-8.76 7.21,62.85 -38.53,139.45 -48.15,149.3 -9.61,9.76 -0.43,15.3 30.23,6.7 92.32,-25.96 100.96,-174.08 106.52,-192.04 5.57,-17.89 9.03,-0.68 9.03,-0.68 -12.48,136.19 -64.16,169.77 -77.93,188.5 -5.72,7.77 40.96,8.94 61.5,-4.45 116.01,-75.08 102.99,-218.89 113.43,-198.36 10.58,20.95 -29.19,151.09 -85.08,195.37 -11.18,8.84 38.79,-6.6 57.2,-23.6 z m 214.59,112.44 c 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87 12.87,7 28.05,52.37 59.22,33.53 z m 2.05,33.45 c 8.47,2.44 35.81,-1.73 18.17,1.85 -17.72,4.96 -28.72,-0.09 -40.36,-7.4 -26.76,-16.75 -48.56,-55.22 -76.72,-71.95 -12.22,-7.31 -24.17,-5.63 -34.33,-18.48 6.58,-13.17 13.26,-5.42 22.22,-7.38 19.86,-4.32 38.16,-12.04 56.52,-23.96 20.33,-13.25 42.35,-37.56 72.67,-35.09 9.67,0.77 27.24,10.15 34.32,14.77 8.84,5.77 29.83,19.54 24.22,40.6 -2.49,9.33 -13.59,10.83 -20.2,18.46 -9.15,10.61 -8.8,21.03 -16.13,33.21 15.98,-3.22 25.13,-12.71 42.37,-14.77 -27.15,24.39 -58.44,45 -96.88,59.07 2.88,1.64 4.72,8.35 14.13,11.07 z M 2223.96,3307.9 c -2.19,16.18 -17.4,30.55 -44.41,22.16 0,0 -34.92,-7.98 -44.43,-69.84 0,0 -1.66,-31.21 8.1,-24.31 -8.22,37.5 27.37,54.49 35.53,58.3 11.48,5.13 20.97,3.4 21.69,-6.37 0.79,-10.54 -11.24,-15.2 -14.84,-26.07 12.77,7.22 41.33,24.13 38.36,46.13 z m 668.31,-133.09 c 27.34,4.37 78.51,23.3 99.04,36.15 22.28,13.93 38.84,67.36 16.13,96.94 -10.17,13.24 -34.52,30.03 -40.38,31.38 -6.68,-3.88 4.2,-7.41 6.05,-9.22 7.7,-7.6 24.88,-21.51 30.28,-33.22 11.03,-23.95 7.65,-60.6 -12.12,-73.85 -13.32,-8.9 -78.47,-33.25 -106.97,-33.21 -80.17,0.11 -88.31,88.29 -137.27,118.12 0.87,-8.43 7.02,-26.13 14.02,-35.28 27.53,-36 53.83,-110.21 131.22,-97.81"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path92"
+ style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2433.33,2370.61 c 0.44,-4.18 2.32,-8.2 3.64,-12.03 0.27,19.49 1.09,47.95 21.49,59.93 3.2,1.86 6.38,2.84 9.52,2.84 8.01,0 13.14,-5.65 16.36,-12.02 -0.35,15.85 1.93,31.07 12.45,38.27 5.18,3.59 10,5.32 14.61,5.32 13.21,0 18.54,-13.65 21.4,-20.98 0.47,-1.15 0.86,-2.18 1.27,-3.11 5.43,-12.42 19.9,-37.76 26.67,-43.33 2.68,2.13 6.03,4.9 7.08,6.42 -0.37,0.5 -0.99,1.17 -1.78,2.1 -42.06,48.68 -29.05,81.43 -10.7,100.35 1.31,1.51 4.77,4.85 9.87,4.85 6.26,0 11.15,-4.56 14.53,-13.49 5.33,-14.1 26.51,-41.61 30.55,-44.43 l 0.99,-0.49 c 2.07,-1.05 4.66,-2.36 6.14,-2.36 l 1.2,0.74 c 1.32,1.41 2.02,2.65 2.41,3.58 -8.82,10.66 -39.16,50.51 -27.93,82.65 1.66,4.78 6.74,19.34 18.65,19.34 10.99,0 18.37,-13.19 20.89,-18.44 6.44,-8.21 23.48,-28.51 32.54,-33.85 2.24,-1.27 4.78,-1.95 7.56,-1.95 4.48,0 8.36,1.68 10.27,2.81 -10.65,8.04 -31.32,39.91 -24.68,67.59 2.94,12.3 13.27,17.81 22.2,17.81 4.37,0 8.25,-1.27 10.93,-3.61 1.01,-0.87 3.11,-3.14 5.94,-6.27 7.87,-8.61 26.27,-28.86 37.27,-32.77 2.14,-0.75 4.09,-1.15 5.87,-1.15 4.13,0 6.86,2.09 9.5,4.82 -0.73,0.56 -1.66,1.22 -2.86,2.02 -4.97,3.36 -29.76,28.79 -19.55,60.6 3.72,11.63 12.01,12.88 15.4,12.88 7.95,0 15.18,-5.84 18.19,-9.31 5.35,-6.09 26.76,-24.07 32.16,-24.45 4.01,0.71 2.25,2.71 8.31,10.37 5,11.5 -10.48,12.08 -25.14,16.79 -8.01,2.57 -25.83,21.87 -41.9,14.16 -16.06,-7.69 -172.23,-113.68 -103.34,-29.72 28.99,35.32 66.68,50.35 63.89,59.45 -4.26,13.83 -48.2,14.69 -60.75,23.8 -6.53,4.73 -12.16,-5.39 -16.07,-14.7 -39.01,-152.94 -175.78,-233.82 -188.79,-242.48 0,0 -35.95,-22.04 -26.53,-21.68 9.43,0.34 27.02,3.64 30.27,-26.87"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path94"
+ style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2747.21,2810.08 c -62.51,-19.99 -119.08,-11.38 -119.08,-11.38 -22.18,0.52 -23.98,27.54 -27.27,49.98 -3.36,23 22.07,-23.5 53.19,-30.48 29.63,-6.74 40.8,-4.57 37.8,18.39 -3.21,24.06 27.8,-3.65 46.52,-7.14 0,0 2.3,-1.48 12,-0.96 9.68,0.53 27.48,-6.91 -3.16,-18.41"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/3rdparty/libuv/include/android-ifaddrs.h b/3rdparty/libuv/include/android-ifaddrs.h
new file mode 100644
index 00000000000..9cd19fec129
--- /dev/null
+++ b/3rdparty/libuv/include/android-ifaddrs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs(struct ifaddrs **ifap);
+extern void freeifaddrs(struct ifaddrs *ifa);
+__END_DECLS
+
+#endif
diff --git a/3rdparty/libuv/include/pthread-fixes.h b/3rdparty/libuv/include/pthread-fixes.h
new file mode 100644
index 00000000000..88c6b66987a
--- /dev/null
+++ b/3rdparty/libuv/include/pthread-fixes.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013, Sony Mobile Communications AB
+ * Copyright (c) 2012, Google Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
+#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
+
+#include <pthread.h>
+
+
+/*Android doesn't provide pthread_barrier_t for now.*/
+#ifndef PTHREAD_BARRIER_SERIAL_THREAD
+
+/* Anything except 0 will do here.*/
+#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned count;
+} pthread_barrier_t;
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count);
+
+int pthread_barrier_wait(pthread_barrier_t* barrier);
+int pthread_barrier_destroy(pthread_barrier_t *barrier);
+#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
+
+int pthread_yield(void);
+
+/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by
+ * replacing all calls to pthread_sigmask with sigprocmask. See:
+ * https://android.googlesource.com/platform/bionic/+/9bf330b5
+ * https://code.google.com/p/android/issues/detail?id=15337
+ */
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
+
+#ifdef pthread_sigmask
+#undef pthread_sigmask
+#endif
+#define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */
diff --git a/3rdparty/libuv/include/stdint-msvc2008.h b/3rdparty/libuv/include/stdint-msvc2008.h
new file mode 100644
index 00000000000..d02608a5972
--- /dev/null
+++ b/3rdparty/libuv/include/stdint-msvc2008.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/3rdparty/libuv/include/tree.h b/3rdparty/libuv/include/tree.h
new file mode 100644
index 00000000000..f936416e3d8
--- /dev/null
+++ b/3rdparty/libuv/include/tree.h
@@ -0,0 +1,768 @@
+/*-
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UV_TREE_H_
+#define UV_TREE_H_
+
+#ifndef UV__UNUSED
+# if __GNUC__
+# define UV__UNUSED __attribute__((unused))
+# else
+# define UV__UNUSED
+# endif
+#endif
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
+ struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old) \
+ RB_LEFT(RB_PARENT(old, field), field) = elm; \
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm; \
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#endif /* UV_TREE_H_ */
diff --git a/3rdparty/libuv/include/uv-aix.h b/3rdparty/libuv/include/uv-aix.h
new file mode 100644
index 00000000000..7dc992fa6d7
--- /dev/null
+++ b/3rdparty/libuv/include/uv-aix.h
@@ -0,0 +1,32 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_AIX_H
+#define UV_AIX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ int fs_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char *dir_filename; \
+
+#endif /* UV_AIX_H */
diff --git a/3rdparty/libuv/include/uv-bsd.h b/3rdparty/libuv/include/uv-bsd.h
new file mode 100644
index 00000000000..2d72b3d7711
--- /dev/null
+++ b/3rdparty/libuv/include/uv-bsd.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_BSD_H
+#define UV_BSD_H
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_BSD_H */
diff --git a/3rdparty/libuv/include/uv-darwin.h b/3rdparty/libuv/include/uv-darwin.h
new file mode 100644
index 00000000000..d226415820b
--- /dev/null
+++ b/3rdparty/libuv/include/uv-darwin.h
@@ -0,0 +1,61 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_DARWIN_H
+#define UV_DARWIN_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach.h>
+# include <mach/task.h>
+# include <mach/semaphore.h>
+# include <TargetConditionals.h>
+# define UV_PLATFORM_SEM_T semaphore_t
+#endif
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv_thread_t cf_thread; \
+ void* _cf_reserved; \
+ void* cf_state; \
+ uv_mutex_t cf_mutex; \
+ uv_sem_t cf_sem; \
+ void* cf_signals[2]; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char* realpath; \
+ int realpath_len; \
+ int cf_flags; \
+ uv_async_t* cf_cb; \
+ void* cf_events[2]; \
+ void* cf_member[2]; \
+ int cf_error; \
+ uv_mutex_t cf_mutex; \
+
+#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+ void* select; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_DARWIN_H */
diff --git a/3rdparty/libuv/include/uv-errno.h b/3rdparty/libuv/include/uv-errno.h
new file mode 100644
index 00000000000..53f30296c1c
--- /dev/null
+++ b/3rdparty/libuv/include/uv-errno.h
@@ -0,0 +1,418 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_ERRNO_H_
+#define UV_ERRNO_H_
+
+#include <errno.h>
+
+#define UV__EOF (-4095)
+#define UV__UNKNOWN (-4094)
+
+#define UV__EAI_ADDRFAMILY (-3000)
+#define UV__EAI_AGAIN (-3001)
+#define UV__EAI_BADFLAGS (-3002)
+#define UV__EAI_CANCELED (-3003)
+#define UV__EAI_FAIL (-3004)
+#define UV__EAI_FAMILY (-3005)
+#define UV__EAI_MEMORY (-3006)
+#define UV__EAI_NODATA (-3007)
+#define UV__EAI_NONAME (-3008)
+#define UV__EAI_OVERFLOW (-3009)
+#define UV__EAI_SERVICE (-3010)
+#define UV__EAI_SOCKTYPE (-3011)
+#define UV__EAI_BADHINTS (-3013)
+#define UV__EAI_PROTOCOL (-3014)
+
+/* Only map to the system errno on non-Windows platforms. It's apparently
+ * a fairly common practice for Windows programmers to redefine errno codes.
+ */
+#if defined(E2BIG) && !defined(_WIN32)
+# define UV__E2BIG (-E2BIG)
+#else
+# define UV__E2BIG (-4093)
+#endif
+
+#if defined(EACCES) && !defined(_WIN32)
+# define UV__EACCES (-EACCES)
+#else
+# define UV__EACCES (-4092)
+#endif
+
+#if defined(EADDRINUSE) && !defined(_WIN32)
+# define UV__EADDRINUSE (-EADDRINUSE)
+#else
+# define UV__EADDRINUSE (-4091)
+#endif
+
+#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
+# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
+#else
+# define UV__EADDRNOTAVAIL (-4090)
+#endif
+
+#if defined(EAFNOSUPPORT) && !defined(_WIN32)
+# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
+#else
+# define UV__EAFNOSUPPORT (-4089)
+#endif
+
+#if defined(EAGAIN) && !defined(_WIN32)
+# define UV__EAGAIN (-EAGAIN)
+#else
+# define UV__EAGAIN (-4088)
+#endif
+
+#if defined(EALREADY) && !defined(_WIN32)
+# define UV__EALREADY (-EALREADY)
+#else
+# define UV__EALREADY (-4084)
+#endif
+
+#if defined(EBADF) && !defined(_WIN32)
+# define UV__EBADF (-EBADF)
+#else
+# define UV__EBADF (-4083)
+#endif
+
+#if defined(EBUSY) && !defined(_WIN32)
+# define UV__EBUSY (-EBUSY)
+#else
+# define UV__EBUSY (-4082)
+#endif
+
+#if defined(ECANCELED) && !defined(_WIN32)
+# define UV__ECANCELED (-ECANCELED)
+#else
+# define UV__ECANCELED (-4081)
+#endif
+
+#if defined(ECHARSET) && !defined(_WIN32)
+# define UV__ECHARSET (-ECHARSET)
+#else
+# define UV__ECHARSET (-4080)
+#endif
+
+#if defined(ECONNABORTED) && !defined(_WIN32)
+# define UV__ECONNABORTED (-ECONNABORTED)
+#else
+# define UV__ECONNABORTED (-4079)
+#endif
+
+#if defined(ECONNREFUSED) && !defined(_WIN32)
+# define UV__ECONNREFUSED (-ECONNREFUSED)
+#else
+# define UV__ECONNREFUSED (-4078)
+#endif
+
+#if defined(ECONNRESET) && !defined(_WIN32)
+# define UV__ECONNRESET (-ECONNRESET)
+#else
+# define UV__ECONNRESET (-4077)
+#endif
+
+#if defined(EDESTADDRREQ) && !defined(_WIN32)
+# define UV__EDESTADDRREQ (-EDESTADDRREQ)
+#else
+# define UV__EDESTADDRREQ (-4076)
+#endif
+
+#if defined(EEXIST) && !defined(_WIN32)
+# define UV__EEXIST (-EEXIST)
+#else
+# define UV__EEXIST (-4075)
+#endif
+
+#if defined(EFAULT) && !defined(_WIN32)
+# define UV__EFAULT (-EFAULT)
+#else
+# define UV__EFAULT (-4074)
+#endif
+
+#if defined(EHOSTUNREACH) && !defined(_WIN32)
+# define UV__EHOSTUNREACH (-EHOSTUNREACH)
+#else
+# define UV__EHOSTUNREACH (-4073)
+#endif
+
+#if defined(EINTR) && !defined(_WIN32)
+# define UV__EINTR (-EINTR)
+#else
+# define UV__EINTR (-4072)
+#endif
+
+#if defined(EINVAL) && !defined(_WIN32)
+# define UV__EINVAL (-EINVAL)
+#else
+# define UV__EINVAL (-4071)
+#endif
+
+#if defined(EIO) && !defined(_WIN32)
+# define UV__EIO (-EIO)
+#else
+# define UV__EIO (-4070)
+#endif
+
+#if defined(EISCONN) && !defined(_WIN32)
+# define UV__EISCONN (-EISCONN)
+#else
+# define UV__EISCONN (-4069)
+#endif
+
+#if defined(EISDIR) && !defined(_WIN32)
+# define UV__EISDIR (-EISDIR)
+#else
+# define UV__EISDIR (-4068)
+#endif
+
+#if defined(ELOOP) && !defined(_WIN32)
+# define UV__ELOOP (-ELOOP)
+#else
+# define UV__ELOOP (-4067)
+#endif
+
+#if defined(EMFILE) && !defined(_WIN32)
+# define UV__EMFILE (-EMFILE)
+#else
+# define UV__EMFILE (-4066)
+#endif
+
+#if defined(EMSGSIZE) && !defined(_WIN32)
+# define UV__EMSGSIZE (-EMSGSIZE)
+#else
+# define UV__EMSGSIZE (-4065)
+#endif
+
+#if defined(ENAMETOOLONG) && !defined(_WIN32)
+# define UV__ENAMETOOLONG (-ENAMETOOLONG)
+#else
+# define UV__ENAMETOOLONG (-4064)
+#endif
+
+#if defined(ENETDOWN) && !defined(_WIN32)
+# define UV__ENETDOWN (-ENETDOWN)
+#else
+# define UV__ENETDOWN (-4063)
+#endif
+
+#if defined(ENETUNREACH) && !defined(_WIN32)
+# define UV__ENETUNREACH (-ENETUNREACH)
+#else
+# define UV__ENETUNREACH (-4062)
+#endif
+
+#if defined(ENFILE) && !defined(_WIN32)
+# define UV__ENFILE (-ENFILE)
+#else
+# define UV__ENFILE (-4061)
+#endif
+
+#if defined(ENOBUFS) && !defined(_WIN32)
+# define UV__ENOBUFS (-ENOBUFS)
+#else
+# define UV__ENOBUFS (-4060)
+#endif
+
+#if defined(ENODEV) && !defined(_WIN32)
+# define UV__ENODEV (-ENODEV)
+#else
+# define UV__ENODEV (-4059)
+#endif
+
+#if defined(ENOENT) && !defined(_WIN32)
+# define UV__ENOENT (-ENOENT)
+#else
+# define UV__ENOENT (-4058)
+#endif
+
+#if defined(ENOMEM) && !defined(_WIN32)
+# define UV__ENOMEM (-ENOMEM)
+#else
+# define UV__ENOMEM (-4057)
+#endif
+
+#if defined(ENONET) && !defined(_WIN32)
+# define UV__ENONET (-ENONET)
+#else
+# define UV__ENONET (-4056)
+#endif
+
+#if defined(ENOSPC) && !defined(_WIN32)
+# define UV__ENOSPC (-ENOSPC)
+#else
+# define UV__ENOSPC (-4055)
+#endif
+
+#if defined(ENOSYS) && !defined(_WIN32)
+# define UV__ENOSYS (-ENOSYS)
+#else
+# define UV__ENOSYS (-4054)
+#endif
+
+#if defined(ENOTCONN) && !defined(_WIN32)
+# define UV__ENOTCONN (-ENOTCONN)
+#else
+# define UV__ENOTCONN (-4053)
+#endif
+
+#if defined(ENOTDIR) && !defined(_WIN32)
+# define UV__ENOTDIR (-ENOTDIR)
+#else
+# define UV__ENOTDIR (-4052)
+#endif
+
+#if defined(ENOTEMPTY) && !defined(_WIN32)
+# define UV__ENOTEMPTY (-ENOTEMPTY)
+#else
+# define UV__ENOTEMPTY (-4051)
+#endif
+
+#if defined(ENOTSOCK) && !defined(_WIN32)
+# define UV__ENOTSOCK (-ENOTSOCK)
+#else
+# define UV__ENOTSOCK (-4050)
+#endif
+
+#if defined(ENOTSUP) && !defined(_WIN32)
+# define UV__ENOTSUP (-ENOTSUP)
+#else
+# define UV__ENOTSUP (-4049)
+#endif
+
+#if defined(EPERM) && !defined(_WIN32)
+# define UV__EPERM (-EPERM)
+#else
+# define UV__EPERM (-4048)
+#endif
+
+#if defined(EPIPE) && !defined(_WIN32)
+# define UV__EPIPE (-EPIPE)
+#else
+# define UV__EPIPE (-4047)
+#endif
+
+#if defined(EPROTO) && !defined(_WIN32)
+# define UV__EPROTO (-EPROTO)
+#else
+# define UV__EPROTO (-4046)
+#endif
+
+#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
+# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
+#else
+# define UV__EPROTONOSUPPORT (-4045)
+#endif
+
+#if defined(EPROTOTYPE) && !defined(_WIN32)
+# define UV__EPROTOTYPE (-EPROTOTYPE)
+#else
+# define UV__EPROTOTYPE (-4044)
+#endif
+
+#if defined(EROFS) && !defined(_WIN32)
+# define UV__EROFS (-EROFS)
+#else
+# define UV__EROFS (-4043)
+#endif
+
+#if defined(ESHUTDOWN) && !defined(_WIN32)
+# define UV__ESHUTDOWN (-ESHUTDOWN)
+#else
+# define UV__ESHUTDOWN (-4042)
+#endif
+
+#if defined(ESPIPE) && !defined(_WIN32)
+# define UV__ESPIPE (-ESPIPE)
+#else
+# define UV__ESPIPE (-4041)
+#endif
+
+#if defined(ESRCH) && !defined(_WIN32)
+# define UV__ESRCH (-ESRCH)
+#else
+# define UV__ESRCH (-4040)
+#endif
+
+#if defined(ETIMEDOUT) && !defined(_WIN32)
+# define UV__ETIMEDOUT (-ETIMEDOUT)
+#else
+# define UV__ETIMEDOUT (-4039)
+#endif
+
+#if defined(ETXTBSY) && !defined(_WIN32)
+# define UV__ETXTBSY (-ETXTBSY)
+#else
+# define UV__ETXTBSY (-4038)
+#endif
+
+#if defined(EXDEV) && !defined(_WIN32)
+# define UV__EXDEV (-EXDEV)
+#else
+# define UV__EXDEV (-4037)
+#endif
+
+#if defined(EFBIG) && !defined(_WIN32)
+# define UV__EFBIG (-EFBIG)
+#else
+# define UV__EFBIG (-4036)
+#endif
+
+#if defined(ENOPROTOOPT) && !defined(_WIN32)
+# define UV__ENOPROTOOPT (-ENOPROTOOPT)
+#else
+# define UV__ENOPROTOOPT (-4035)
+#endif
+
+#if defined(ERANGE) && !defined(_WIN32)
+# define UV__ERANGE (-ERANGE)
+#else
+# define UV__ERANGE (-4034)
+#endif
+
+#if defined(ENXIO) && !defined(_WIN32)
+# define UV__ENXIO (-ENXIO)
+#else
+# define UV__ENXIO (-4033)
+#endif
+
+#if defined(EMLINK) && !defined(_WIN32)
+# define UV__EMLINK (-EMLINK)
+#else
+# define UV__EMLINK (-4032)
+#endif
+
+/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
+ * defined. Fortunately, its value is always 64 so it's possible albeit
+ * icky to hard-code it.
+ */
+#if defined(EHOSTDOWN) && !defined(_WIN32)
+# define UV__EHOSTDOWN (-EHOSTDOWN)
+#elif defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define UV__EHOSTDOWN (-64)
+#else
+# define UV__EHOSTDOWN (-4031)
+#endif
+
+#endif /* UV_ERRNO_H_ */
diff --git a/3rdparty/libuv/include/uv-linux.h b/3rdparty/libuv/include/uv-linux.h
new file mode 100644
index 00000000000..9b38405a190
--- /dev/null
+++ b/3rdparty/libuv/include/uv-linux.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_H
+#define UV_LINUX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t inotify_read_watcher; \
+ void* inotify_watchers; \
+ int inotify_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ void* watchers[2]; \
+ int wd; \
+
+#endif /* UV_LINUX_H */
diff --git a/3rdparty/libuv/include/uv-sunos.h b/3rdparty/libuv/include/uv-sunos.h
new file mode 100644
index 00000000000..042166424e5
--- /dev/null
+++ b/3rdparty/libuv/include/uv-sunos.h
@@ -0,0 +1,44 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_SUNOS_H
+#define UV_SUNOS_H
+
+#include <sys/port.h>
+#include <port.h>
+
+/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c,
+ * add the fs_event fields even when this version of SunOS doesn't support
+ * file watching.
+ */
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t fs_event_watcher; \
+ int fs_fd; \
+
+#if defined(PORT_SOURCE_FILE)
+
+# define UV_PLATFORM_FS_EVENT_FIELDS \
+ file_obj_t fo; \
+ int fd; \
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+#endif /* UV_SUNOS_H */
diff --git a/3rdparty/libuv/include/uv-threadpool.h b/3rdparty/libuv/include/uv-threadpool.h
new file mode 100644
index 00000000000..9708ebdd530
--- /dev/null
+++ b/3rdparty/libuv/include/uv-threadpool.h
@@ -0,0 +1,37 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_THREADPOOL_H_
+#define UV_THREADPOOL_H_
+
+struct uv__work {
+ void (*work)(struct uv__work *w);
+ void (*done)(struct uv__work *w, int status);
+ struct uv_loop_s* loop;
+ void* wq[2];
+};
+
+#endif /* UV_THREADPOOL_H_ */
diff --git a/3rdparty/libuv/include/uv-unix.h b/3rdparty/libuv/include/uv-unix.h
new file mode 100644
index 00000000000..82d193bdca4
--- /dev/null
+++ b/3rdparty/libuv/include/uv-unix.h
@@ -0,0 +1,383 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_H
+#define UV_UNIX_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <termios.h>
+#include <pwd.h>
+
+#include <semaphore.h>
+#include <pthread.h>
+#ifdef __ANDROID__
+#include "pthread-fixes.h"
+#endif
+#include <signal.h>
+
+#include "uv-threadpool.h"
+
+#if defined(__linux__)
+# include "uv-linux.h"
+#elif defined(_AIX)
+# include "uv-aix.h"
+#elif defined(__sun)
+# include "uv-sunos.h"
+#elif defined(__APPLE__)
+# include "uv-darwin.h"
+#elif defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# include "uv-bsd.h"
+#endif
+
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
+# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+struct uv__io_s;
+struct uv__async;
+struct uv_loop_s;
+
+typedef void (*uv__io_cb)(struct uv_loop_s* loop,
+ struct uv__io_s* w,
+ unsigned int events);
+typedef struct uv__io_s uv__io_t;
+
+struct uv__io_s {
+ uv__io_cb cb;
+ void* pending_queue[2];
+ void* watcher_queue[2];
+ unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
+ unsigned int events; /* Current event mask. */
+ int fd;
+ UV_IO_PRIVATE_PLATFORM_FIELDS
+};
+
+typedef void (*uv__async_cb)(struct uv_loop_s* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+
+struct uv__async {
+ uv__async_cb cb;
+ uv__io_t io_watcher;
+ int wfd;
+};
+
+#ifndef UV_PLATFORM_SEM_T
+# define UV_PLATFORM_SEM_T sem_t
+#endif
+
+#ifndef UV_PLATFORM_LOOP_FIELDS
+# define UV_PLATFORM_LOOP_FIELDS /* empty */
+#endif
+
+#ifndef UV_PLATFORM_FS_EVENT_FIELDS
+# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
+#endif
+
+#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS
+# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+/* Note: May be cast to struct iovec. See writev(2). */
+typedef struct uv_buf_t {
+ char* base;
+ size_t len;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef int uv_os_sock_t;
+typedef int uv_os_fd_t;
+
+#define UV_ONCE_INIT PTHREAD_ONCE_INIT
+
+typedef pthread_once_t uv_once_t;
+typedef pthread_t uv_thread_t;
+typedef pthread_mutex_t uv_mutex_t;
+typedef pthread_rwlock_t uv_rwlock_t;
+typedef UV_PLATFORM_SEM_T uv_sem_t;
+typedef pthread_cond_t uv_cond_t;
+typedef pthread_key_t uv_key_t;
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+typedef struct {
+ unsigned int n;
+ unsigned int count;
+ uv_mutex_t mutex;
+ uv_sem_t turnstile1;
+ uv_sem_t turnstile2;
+} uv_barrier_t;
+
+#else /* defined(__APPLE__) && defined(__MACH__) */
+
+typedef pthread_barrier_t uv_barrier_t;
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef gid_t uv_gid_t;
+typedef uid_t uv_uid_t;
+
+typedef struct dirent uv__dirent_t;
+
+#if defined(DT_UNKNOWN)
+# define HAVE_DIRENT_TYPES
+# if defined(DT_REG)
+# define UV__DT_FILE DT_REG
+# else
+# define UV__DT_FILE -1
+# endif
+# if defined(DT_DIR)
+# define UV__DT_DIR DT_DIR
+# else
+# define UV__DT_DIR -2
+# endif
+# if defined(DT_LNK)
+# define UV__DT_LINK DT_LNK
+# else
+# define UV__DT_LINK -3
+# endif
+# if defined(DT_FIFO)
+# define UV__DT_FIFO DT_FIFO
+# else
+# define UV__DT_FIFO -4
+# endif
+# if defined(DT_SOCK)
+# define UV__DT_SOCKET DT_SOCK
+# else
+# define UV__DT_SOCKET -5
+# endif
+# if defined(DT_CHR)
+# define UV__DT_CHAR DT_CHR
+# else
+# define UV__DT_CHAR -6
+# endif
+# if defined(DT_BLK)
+# define UV__DT_BLOCK DT_BLK
+# else
+# define UV__DT_BLOCK -7
+# endif
+#endif
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC /* empty */
+
+typedef struct {
+ void* handle;
+ char* errmsg;
+} uv_lib_t;
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ unsigned long flags; \
+ int backend_fd; \
+ void* pending_queue[2]; \
+ void* watcher_queue[2]; \
+ uv__io_t** watchers; \
+ unsigned int nwatchers; \
+ unsigned int nfds; \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async; \
+ uv_rwlock_t cloexec_lock; \
+ uv_handle_t* closing_handles; \
+ void* process_handles[2]; \
+ void* prepare_handles[2]; \
+ void* check_handles[2]; \
+ void* idle_handles[2]; \
+ void* async_handles[2]; \
+ struct uv__async async_watcher; \
+ struct { \
+ void* min; \
+ unsigned int nelts; \
+ } timer_heap; \
+ uint64_t timer_counter; \
+ uint64_t time; \
+ int signal_pipefd[2]; \
+ uv__io_t signal_io_watcher; \
+ uv_signal_t child_watcher; \
+ int emfile_fd; \
+ UV_PLATFORM_LOOP_FIELDS \
+
+#define UV_REQ_TYPE_PRIVATE /* empty */
+
+#define UV_REQ_PRIVATE_FIELDS /* empty */
+
+#define UV_PRIVATE_REQ_TYPES /* empty */
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ void* queue[2]; \
+ unsigned int write_index; \
+ uv_buf_t* bufs; \
+ unsigned int nbufs; \
+ int error; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ void* queue[2]; \
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ void* queue[2]; \
+ struct sockaddr_storage addr; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ ssize_t status; \
+ uv_udp_send_cb send_cb; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* next_closing; \
+ unsigned int flags; \
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ uv_connect_t *connect_req; \
+ uv_shutdown_t *shutdown_req; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+ uv_connection_cb connection_cb; \
+ int delayed_error; \
+ int accepted_fd; \
+ void* queued_fds; \
+ UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+
+#define UV_TCP_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_PRIVATE_FIELDS \
+ uv_alloc_cb alloc_cb; \
+ uv_udp_recv_cb recv_cb; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ const char* pipe_fname; /* strdup'ed */
+
+#define UV_POLL_PRIVATE_FIELDS \
+ uv__io_t io_watcher;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_cb prepare_cb; \
+ void* queue[2]; \
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_cb check_cb; \
+ void* queue[2]; \
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_cb idle_cb; \
+ void* queue[2]; \
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ uv_async_cb async_cb; \
+ void* queue[2]; \
+ int pending; \
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ uv_timer_cb timer_cb; \
+ void* heap_node[3]; \
+ uint64_t timeout; \
+ uint64_t repeat; \
+ uint64_t start_id;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb cb; \
+ struct addrinfo* hints; \
+ char* hostname; \
+ char* service; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ void* queue[2]; \
+ int status; \
+
+#define UV_FS_PRIVATE_FIELDS \
+ const char *new_path; \
+ uv_file file; \
+ int flags; \
+ mode_t mode; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ off_t off; \
+ uv_uid_t uid; \
+ uv_gid_t gid; \
+ double atime; \
+ double mtime; \
+ struct uv__work work_req; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_TTY_PRIVATE_FIELDS \
+ struct termios orig_termios; \
+ int mode;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ /* RB_ENTRY(uv_signal_s) tree_entry; */ \
+ struct { \
+ struct uv_signal_s* rbe_left; \
+ struct uv_signal_s* rbe_right; \
+ struct uv_signal_s* rbe_parent; \
+ int rbe_color; \
+ } tree_entry; \
+ /* Use two counters here so we don have to fiddle with atomics. */ \
+ unsigned int caught_signals; \
+ unsigned int dispatched_signals;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ uv_fs_event_cb cb; \
+ UV_PLATFORM_FS_EVENT_FIELDS \
+
+#endif /* UV_UNIX_H */
diff --git a/3rdparty/libuv/include/uv-version.h b/3rdparty/libuv/include/uv-version.h
new file mode 100644
index 00000000000..6e61f55ed20
--- /dev/null
+++ b/3rdparty/libuv/include/uv-version.h
@@ -0,0 +1,43 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_VERSION_H
+#define UV_VERSION_H
+
+ /*
+ * Versions with the same major number are ABI stable. API is allowed to
+ * evolve between minor releases, but only in a backwards compatible way.
+ * Make sure you update the -soname directives in configure.ac
+ * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
+ * not UV_VERSION_PATCH.)
+ */
+
+#define UV_VERSION_MAJOR 1
+#define UV_VERSION_MINOR 8
+#define UV_VERSION_PATCH 0
+#define UV_VERSION_IS_RELEASE 1
+#define UV_VERSION_SUFFIX ""
+
+#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
+ (UV_VERSION_MINOR << 8) | \
+ (UV_VERSION_PATCH))
+
+#endif /* UV_VERSION_H */
diff --git a/3rdparty/libuv/include/uv-win.h b/3rdparty/libuv/include/uv-win.h
new file mode 100644
index 00000000000..300be476203
--- /dev/null
+++ b/3rdparty/libuv/include/uv-win.h
@@ -0,0 +1,653 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0502
+#endif
+
+#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
+typedef intptr_t ssize_t;
+# define _SSIZE_T_
+# define _SSIZE_T_DEFINED
+#endif
+
+#include <winsock2.h>
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+#endif
+
+#ifndef LOCALE_INVARIANT
+# define LOCALE_INVARIANT 0x007f
+#endif
+
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include <process.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "tree.h"
+#include "uv-threadpool.h"
+
+#define MAX_PIPENAME_LEN 256
+
+#ifndef S_IFLNK
+# define S_IFLNK 0xA000
+#endif
+
+/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
+ * the following signals already:
+ *
+ * #define SIGINT 2
+ * #define SIGILL 4
+ * #define SIGABRT_COMPAT 6
+ * #define SIGFPE 8
+ * #define SIGSEGV 11
+ * #define SIGTERM 15
+ * #define SIGBREAK 21
+ * #define SIGABRT 22
+ *
+ * The additional signals have values that are common on other Unix
+ * variants (Linux and Darwin)
+ */
+#define SIGHUP 1
+#define SIGKILL 9
+#define SIGWINCH 28
+
+/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
+/* unix-like platforms. However MinGW doesn't define it, so we do. */
+#ifndef SIGABRT_COMPAT
+# define SIGABRT_COMPAT 6
+#endif
+
+/*
+ * Guids and typedefs for winsock extension functions
+ * Mingw32 doesn't have these :-(
+ */
+#ifndef WSAID_ACCEPTEX
+# define WSAID_ACCEPTEX \
+ {0xb5367df1, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_CONNECTEX \
+ {0x25a207b9, 0xddf3, 0x4660, \
+ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
+
+# define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_DISCONNECTEX \
+ {0x7fda2e11, 0x8630, 0x436f, \
+ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
+
+# define WSAID_TRANSMITFILE \
+ {0xb5367df0, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+ typedef BOOL PASCAL (*LPFN_ACCEPTEX)
+ (SOCKET sListenSocket,
+ SOCKET sAcceptSocket,
+ PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPDWORD lpdwBytesReceived,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef BOOL PASCAL (*LPFN_CONNECTEX)
+ (SOCKET s,
+ const struct sockaddr* name,
+ int namelen,
+ PVOID lpSendBuffer,
+ DWORD dwSendDataLength,
+ LPDWORD lpdwBytesSent,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
+ (PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPSOCKADDR* LocalSockaddr,
+ LPINT LocalSockaddrLength,
+ LPSOCKADDR* RemoteSockaddr,
+ LPINT RemoteSockaddrLength);
+
+ typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
+ (SOCKET hSocket,
+ LPOVERLAPPED lpOverlapped,
+ DWORD dwFlags,
+ DWORD reserved);
+
+ typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
+ (SOCKET hSocket,
+ HANDLE hFile,
+ DWORD nNumberOfBytesToWrite,
+ DWORD nNumberOfBytesPerSend,
+ LPOVERLAPPED lpOverlapped,
+ LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
+ DWORD dwFlags);
+
+ typedef PVOID RTL_SRWLOCK;
+ typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+#endif
+
+typedef int (WSAAPI* LPFN_WSARECV)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+typedef int (WSAAPI* LPFN_WSARECVFROM)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ struct sockaddr* addr,
+ LPINT addr_len,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+#ifndef _NTDEF_
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS *PNTSTATUS;
+#endif
+
+#ifndef RTL_CONDITION_VARIABLE_INIT
+ typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
+#endif
+
+typedef struct _AFD_POLL_HANDLE_INFO {
+ HANDLE Handle;
+ ULONG Events;
+ NTSTATUS Status;
+} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
+
+typedef struct _AFD_POLL_INFO {
+ LARGE_INTEGER Timeout;
+ ULONG NumberOfHandles;
+ ULONG Exclusive;
+ AFD_POLL_HANDLE_INFO Handles[1];
+} AFD_POLL_INFO, *PAFD_POLL_INFO;
+
+#define UV_MSAFD_PROVIDER_COUNT 3
+
+
+/**
+ * It should be possible to cast uv_buf_t[] to WSABUF[]
+ * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx
+ */
+typedef struct uv_buf_t {
+ ULONG len;
+ char* base;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef SOCKET uv_os_sock_t;
+typedef HANDLE uv_os_fd_t;
+
+typedef HANDLE uv_thread_t;
+
+typedef HANDLE uv_sem_t;
+
+typedef CRITICAL_SECTION uv_mutex_t;
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+typedef union {
+ CONDITION_VARIABLE cond_var;
+ struct {
+ unsigned int waiters_count;
+ CRITICAL_SECTION waiters_count_lock;
+ HANDLE signal_event;
+ HANDLE broadcast_event;
+ } fallback;
+} uv_cond_t;
+
+typedef union {
+ struct {
+ unsigned int num_readers_;
+ CRITICAL_SECTION num_readers_lock_;
+ HANDLE write_semaphore_;
+ } state_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ SRWLOCK unused_;
+ } unused1_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ uv_mutex_t unused1_;
+ uv_mutex_t unused2_;
+ } unused2_;
+} uv_rwlock_t;
+
+typedef struct {
+ unsigned int n;
+ unsigned int count;
+ uv_mutex_t mutex;
+ uv_sem_t turnstile1;
+ uv_sem_t turnstile2;
+} uv_barrier_t;
+
+typedef struct {
+ DWORD tls_index;
+} uv_key_t;
+
+#define UV_ONCE_INIT { 0, NULL }
+
+typedef struct uv_once_s {
+ unsigned char ran;
+ HANDLE event;
+} uv_once_t;
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef unsigned char uv_uid_t;
+typedef unsigned char uv_gid_t;
+
+typedef struct uv__dirent_s {
+ int d_type;
+ char d_name[1];
+} uv__dirent_t;
+
+#define HAVE_DIRENT_TYPES
+#define UV__DT_DIR UV_DIRENT_DIR
+#define UV__DT_FILE UV_DIRENT_FILE
+#define UV__DT_LINK UV_DIRENT_LINK
+#define UV__DT_FIFO UV_DIRENT_FIFO
+#define UV__DT_SOCKET UV_DIRENT_SOCKET
+#define UV__DT_CHAR UV_DIRENT_CHAR
+#define UV__DT_BLOCK UV_DIRENT_BLOCK
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC FAR WINAPI
+typedef struct {
+ HMODULE handle;
+ char* errmsg;
+} uv_lib_t;
+
+RB_HEAD(uv_timer_tree_s, uv_timer_s);
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ /* The loop's I/O completion port */ \
+ HANDLE iocp; \
+ /* The current time according to the event loop. in msecs. */ \
+ uint64_t time; \
+ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \
+ /* is empty, tail_ is NULL. If there is only one item, */ \
+ /* tail_->next_req == tail_ */ \
+ uv_req_t* pending_reqs_tail; \
+ /* Head of a single-linked list of closed handles */ \
+ uv_handle_t* endgame_handles; \
+ /* The head of the timers tree */ \
+ struct uv_timer_tree_s timers; \
+ /* Lists of active loop (prepare / check / idle) watchers */ \
+ uv_prepare_t* prepare_handles; \
+ uv_check_t* check_handles; \
+ uv_idle_t* idle_handles; \
+ /* This pointer will refer to the prepare/check/idle handle whose */ \
+ /* callback is scheduled to be called next. This is needed to allow */ \
+ /* safe removal from one of the lists above while that list being */ \
+ /* iterated over. */ \
+ uv_prepare_t* next_prepare_handle; \
+ uv_check_t* next_check_handle; \
+ uv_idle_t* next_idle_handle; \
+ /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
+ SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
+ /* Counter to keep track of active tcp streams */ \
+ unsigned int active_tcp_streams; \
+ /* Counter to keep track of active udp streams */ \
+ unsigned int active_udp_streams; \
+ /* Counter to started timer */ \
+ uint64_t timer_counter; \
+ /* Threadpool */ \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async;
+
+#define UV_REQ_TYPE_PRIVATE \
+ /* TODO: remove the req suffix */ \
+ UV_ACCEPT, \
+ UV_FS_EVENT_REQ, \
+ UV_POLL_REQ, \
+ UV_PROCESS_EXIT, \
+ UV_READ, \
+ UV_UDP_RECV, \
+ UV_WAKEUP, \
+ UV_SIGNAL_REQ,
+
+#define UV_REQ_PRIVATE_FIELDS \
+ union { \
+ /* Used by I/O operations */ \
+ struct { \
+ OVERLAPPED overlapped; \
+ size_t queued_bytes; \
+ } io; \
+ } u; \
+ struct uv_req_s* next_req;
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ int ipc_header; \
+ uv_buf_t write_buffer; \
+ HANDLE event_handle; \
+ HANDLE wait_handle;
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_PRIVATE_REQ_TYPES \
+ typedef struct uv_pipe_accept_s { \
+ UV_REQ_FIELDS \
+ HANDLE pipeHandle; \
+ struct uv_pipe_accept_s* next_pending; \
+ } uv_pipe_accept_t; \
+ \
+ typedef struct uv_tcp_accept_s { \
+ UV_REQ_FIELDS \
+ SOCKET accept_socket; \
+ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ struct uv_tcp_accept_s* next_pending; \
+ } uv_tcp_accept_t; \
+ \
+ typedef struct uv_read_s { \
+ UV_REQ_FIELDS \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ } uv_read_t;
+
+#define uv_stream_connection_fields \
+ unsigned int write_reqs_pending; \
+ uv_shutdown_t* shutdown_req;
+
+#define uv_stream_server_fields \
+ uv_connection_cb connection_cb;
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_read_t read_req; \
+ union { \
+ struct { uv_stream_connection_fields } conn; \
+ struct { uv_stream_server_fields } serv; \
+ } stream;
+
+#define uv_tcp_server_fields \
+ uv_tcp_accept_t* accept_reqs; \
+ unsigned int processed_accepts; \
+ uv_tcp_accept_t* pending_accepts; \
+ LPFN_ACCEPTEX func_acceptex;
+
+#define uv_tcp_connection_fields \
+ uv_buf_t read_buffer; \
+ LPFN_CONNECTEX func_connectex;
+
+#define UV_TCP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ int delayed_error; \
+ union { \
+ struct { uv_tcp_server_fields } serv; \
+ struct { uv_tcp_connection_fields } conn; \
+ } tcp;
+
+#define UV_UDP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_req_t recv_req; \
+ uv_buf_t recv_buffer; \
+ struct sockaddr_storage recv_from; \
+ int recv_from_len; \
+ uv_udp_recv_cb recv_cb; \
+ uv_alloc_cb alloc_cb; \
+ LPFN_WSARECV func_wsarecv; \
+ LPFN_WSARECVFROM func_wsarecvfrom;
+
+#define uv_pipe_server_fields \
+ int pending_instances; \
+ uv_pipe_accept_t* accept_reqs; \
+ uv_pipe_accept_t* pending_accepts;
+
+#define uv_pipe_connection_fields \
+ uv_timer_t* eof_timer; \
+ uv_write_t ipc_header_write_req; \
+ int ipc_pid; \
+ uint64_t remaining_ipc_rawdata_bytes; \
+ struct { \
+ void* queue[2]; \
+ int queue_len; \
+ } pending_ipc_info; \
+ uv_write_t* non_overlapped_writes_tail; \
+ uv_mutex_t readfile_mutex; \
+ volatile HANDLE readfile_thread;
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ HANDLE handle; \
+ WCHAR* name; \
+ union { \
+ struct { uv_pipe_server_fields } serv; \
+ struct { uv_pipe_connection_fields } conn; \
+ } pipe;
+
+/* TODO: put the parser states in an union - TTY handles are always */
+/* half-duplex so read-state can safely overlap write-state. */
+#define UV_TTY_PRIVATE_FIELDS \
+ HANDLE handle; \
+ union { \
+ struct { \
+ /* Used for readable TTY handles */ \
+ HANDLE read_line_handle; \
+ uv_buf_t read_line_buffer; \
+ HANDLE read_raw_wait; \
+ /* Fields used for translating win keystrokes into vt100 characters */ \
+ char last_key[8]; \
+ unsigned char last_key_offset; \
+ unsigned char last_key_len; \
+ WCHAR last_utf16_high_surrogate; \
+ INPUT_RECORD last_input_record; \
+ } rd; \
+ struct { \
+ /* Used for writable TTY handles */ \
+ /* utf8-to-utf16 conversion state */ \
+ unsigned int utf8_codepoint; \
+ unsigned char utf8_bytes_left; \
+ /* eol conversion state */ \
+ unsigned char previous_eol; \
+ /* ansi parser state */ \
+ unsigned char ansi_parser_state; \
+ unsigned char ansi_csi_argc; \
+ unsigned short ansi_csi_argv[4]; \
+ COORD saved_position; \
+ WORD saved_attributes; \
+ } wr; \
+ } tty;
+
+#define UV_POLL_PRIVATE_FIELDS \
+ SOCKET socket; \
+ /* Used in fast mode */ \
+ SOCKET peer_socket; \
+ AFD_POLL_INFO afd_poll_info_1; \
+ AFD_POLL_INFO afd_poll_info_2; \
+ /* Used in fast and slow mode. */ \
+ uv_req_t poll_req_1; \
+ uv_req_t poll_req_2; \
+ unsigned char submitted_events_1; \
+ unsigned char submitted_events_2; \
+ unsigned char mask_events_1; \
+ unsigned char mask_events_2; \
+ unsigned char events;
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ RB_ENTRY(uv_timer_s) tree_entry; \
+ uint64_t due; \
+ uint64_t repeat; \
+ uint64_t start_id; \
+ uv_timer_cb timer_cb;
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ struct uv_req_s async_req; \
+ uv_async_cb async_cb; \
+ /* char to avoid alignment issues */ \
+ char volatile async_sent;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_t* prepare_prev; \
+ uv_prepare_t* prepare_next; \
+ uv_prepare_cb prepare_cb;
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_t* check_prev; \
+ uv_check_t* check_next; \
+ uv_check_cb check_cb;
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_t* idle_prev; \
+ uv_idle_t* idle_next; \
+ uv_idle_cb idle_cb;
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* endgame_next; \
+ unsigned int flags;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb getaddrinfo_cb; \
+ void* alloc; \
+ WCHAR* node; \
+ WCHAR* service; \
+ /* The addrinfoW field is used to store a pointer to the hints, and */ \
+ /* later on to store the result of GetAddrInfoW. The final result will */ \
+ /* be converted to struct addrinfo* and stored in the addrinfo field. */ \
+ struct addrinfoW* addrinfow; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ struct uv_process_exit_s { \
+ UV_REQ_FIELDS \
+ } exit_req; \
+ BYTE* child_stdio_buffer; \
+ int exit_signal; \
+ HANDLE wait_handle; \
+ HANDLE process_handle; \
+ volatile char exit_cb_pending;
+
+#define UV_FS_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ int flags; \
+ DWORD sys_errno_; \
+ union { \
+ /* TODO: remove me in 0.9. */ \
+ WCHAR* pathw; \
+ int fd; \
+ } file; \
+ union { \
+ struct { \
+ int mode; \
+ WCHAR* new_pathw; \
+ int file_flags; \
+ int fd_out; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ int64_t offset; \
+ uv_buf_t bufsml[4]; \
+ } info; \
+ struct { \
+ double atime; \
+ double mtime; \
+ } time; \
+ } fs;
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ struct uv_fs_event_req_s { \
+ UV_REQ_FIELDS \
+ } req; \
+ HANDLE dir_handle; \
+ int req_pending; \
+ uv_fs_event_cb cb; \
+ WCHAR* filew; \
+ WCHAR* short_filew; \
+ WCHAR* dirw; \
+ char* buffer;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ RB_ENTRY(uv_signal_s) tree_entry; \
+ struct uv_req_s signal_req; \
+ unsigned long pending_signum;
+
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
+ char* utf8Buffer, size_t utf8Size);
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
+ size_t utf16Size);
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
diff --git a/3rdparty/libuv/include/uv.h b/3rdparty/libuv/include/uv.h
new file mode 100644
index 00000000000..dd3111a960e
--- /dev/null
+++ b/3rdparty/libuv/include/uv.h
@@ -0,0 +1,1482 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* See https://github.com/libuv/libuv#documentation for documentation. */
+
+#ifndef UV_H
+#define UV_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+ /* Windows - set up dll import/export decorators. */
+# if defined(BUILDING_UV_SHARED)
+ /* Building shared library. */
+# define UV_EXTERN __declspec(dllexport)
+# elif defined(USING_UV_SHARED)
+ /* Using shared library. */
+# define UV_EXTERN __declspec(dllimport)
+# else
+ /* Building static library. */
+# define UV_EXTERN /* nothing */
+# endif
+#elif __GNUC__ >= 4
+# define UV_EXTERN __attribute__((visibility("default")))
+#else
+# define UV_EXTERN /* nothing */
+#endif
+
+#include "uv-errno.h"
+#include "uv-version.h"
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#if defined(_WIN32)
+# include "uv-win.h"
+#else
+# include "uv-unix.h"
+#endif
+
+/* Expand this list if necessary. */
+#define UV_ERRNO_MAP(XX) \
+ XX(E2BIG, "argument list too long") \
+ XX(EACCES, "permission denied") \
+ XX(EADDRINUSE, "address already in use") \
+ XX(EADDRNOTAVAIL, "address not available") \
+ XX(EAFNOSUPPORT, "address family not supported") \
+ XX(EAGAIN, "resource temporarily unavailable") \
+ XX(EAI_ADDRFAMILY, "address family not supported") \
+ XX(EAI_AGAIN, "temporary failure") \
+ XX(EAI_BADFLAGS, "bad ai_flags value") \
+ XX(EAI_BADHINTS, "invalid value for hints") \
+ XX(EAI_CANCELED, "request canceled") \
+ XX(EAI_FAIL, "permanent failure") \
+ XX(EAI_FAMILY, "ai_family not supported") \
+ XX(EAI_MEMORY, "out of memory") \
+ XX(EAI_NODATA, "no address") \
+ XX(EAI_NONAME, "unknown node or service") \
+ XX(EAI_OVERFLOW, "argument buffer overflow") \
+ XX(EAI_PROTOCOL, "resolved protocol is unknown") \
+ XX(EAI_SERVICE, "service not available for socket type") \
+ XX(EAI_SOCKTYPE, "socket type not supported") \
+ XX(EALREADY, "connection already in progress") \
+ XX(EBADF, "bad file descriptor") \
+ XX(EBUSY, "resource busy or locked") \
+ XX(ECANCELED, "operation canceled") \
+ XX(ECHARSET, "invalid Unicode character") \
+ XX(ECONNABORTED, "software caused connection abort") \
+ XX(ECONNREFUSED, "connection refused") \
+ XX(ECONNRESET, "connection reset by peer") \
+ XX(EDESTADDRREQ, "destination address required") \
+ XX(EEXIST, "file already exists") \
+ XX(EFAULT, "bad address in system call argument") \
+ XX(EFBIG, "file too large") \
+ XX(EHOSTUNREACH, "host is unreachable") \
+ XX(EINTR, "interrupted system call") \
+ XX(EINVAL, "invalid argument") \
+ XX(EIO, "i/o error") \
+ XX(EISCONN, "socket is already connected") \
+ XX(EISDIR, "illegal operation on a directory") \
+ XX(ELOOP, "too many symbolic links encountered") \
+ XX(EMFILE, "too many open files") \
+ XX(EMSGSIZE, "message too long") \
+ XX(ENAMETOOLONG, "name too long") \
+ XX(ENETDOWN, "network is down") \
+ XX(ENETUNREACH, "network is unreachable") \
+ XX(ENFILE, "file table overflow") \
+ XX(ENOBUFS, "no buffer space available") \
+ XX(ENODEV, "no such device") \
+ XX(ENOENT, "no such file or directory") \
+ XX(ENOMEM, "not enough memory") \
+ XX(ENONET, "machine is not on the network") \
+ XX(ENOPROTOOPT, "protocol not available") \
+ XX(ENOSPC, "no space left on device") \
+ XX(ENOSYS, "function not implemented") \
+ XX(ENOTCONN, "socket is not connected") \
+ XX(ENOTDIR, "not a directory") \
+ XX(ENOTEMPTY, "directory not empty") \
+ XX(ENOTSOCK, "socket operation on non-socket") \
+ XX(ENOTSUP, "operation not supported on socket") \
+ XX(EPERM, "operation not permitted") \
+ XX(EPIPE, "broken pipe") \
+ XX(EPROTO, "protocol error") \
+ XX(EPROTONOSUPPORT, "protocol not supported") \
+ XX(EPROTOTYPE, "protocol wrong type for socket") \
+ XX(ERANGE, "result too large") \
+ XX(EROFS, "read-only file system") \
+ XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
+ XX(ESPIPE, "invalid seek") \
+ XX(ESRCH, "no such process") \
+ XX(ETIMEDOUT, "connection timed out") \
+ XX(ETXTBSY, "text file is busy") \
+ XX(EXDEV, "cross-device link not permitted") \
+ XX(UNKNOWN, "unknown error") \
+ XX(EOF, "end of file") \
+ XX(ENXIO, "no such device or address") \
+ XX(EMLINK, "too many links") \
+ XX(EHOSTDOWN, "host is down") \
+
+#define UV_HANDLE_TYPE_MAP(XX) \
+ XX(ASYNC, async) \
+ XX(CHECK, check) \
+ XX(FS_EVENT, fs_event) \
+ XX(FS_POLL, fs_poll) \
+ XX(HANDLE, handle) \
+ XX(IDLE, idle) \
+ XX(NAMED_PIPE, pipe) \
+ XX(POLL, poll) \
+ XX(PREPARE, prepare) \
+ XX(PROCESS, process) \
+ XX(STREAM, stream) \
+ XX(TCP, tcp) \
+ XX(TIMER, timer) \
+ XX(TTY, tty) \
+ XX(UDP, udp) \
+ XX(SIGNAL, signal) \
+
+#define UV_REQ_TYPE_MAP(XX) \
+ XX(REQ, req) \
+ XX(CONNECT, connect) \
+ XX(WRITE, write) \
+ XX(SHUTDOWN, shutdown) \
+ XX(UDP_SEND, udp_send) \
+ XX(FS, fs) \
+ XX(WORK, work) \
+ XX(GETADDRINFO, getaddrinfo) \
+ XX(GETNAMEINFO, getnameinfo) \
+
+typedef enum {
+#define XX(code, _) UV_ ## code = UV__ ## code,
+ UV_ERRNO_MAP(XX)
+#undef XX
+ UV_ERRNO_MAX = UV__EOF - 1
+} uv_errno_t;
+
+typedef enum {
+ UV_UNKNOWN_HANDLE = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ UV_FILE,
+ UV_HANDLE_TYPE_MAX
+} uv_handle_type;
+
+typedef enum {
+ UV_UNKNOWN_REQ = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ UV_REQ_TYPE_PRIVATE
+ UV_REQ_TYPE_MAX
+} uv_req_type;
+
+
+/* Handle types. */
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_handle_s uv_handle_t;
+typedef struct uv_stream_s uv_stream_t;
+typedef struct uv_tcp_s uv_tcp_t;
+typedef struct uv_udp_s uv_udp_t;
+typedef struct uv_pipe_s uv_pipe_t;
+typedef struct uv_tty_s uv_tty_t;
+typedef struct uv_poll_s uv_poll_t;
+typedef struct uv_timer_s uv_timer_t;
+typedef struct uv_prepare_s uv_prepare_t;
+typedef struct uv_check_s uv_check_t;
+typedef struct uv_idle_s uv_idle_t;
+typedef struct uv_async_s uv_async_t;
+typedef struct uv_process_s uv_process_t;
+typedef struct uv_fs_event_s uv_fs_event_t;
+typedef struct uv_fs_poll_s uv_fs_poll_t;
+typedef struct uv_signal_s uv_signal_t;
+
+/* Request types. */
+typedef struct uv_req_s uv_req_t;
+typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
+typedef struct uv_getnameinfo_s uv_getnameinfo_t;
+typedef struct uv_shutdown_s uv_shutdown_t;
+typedef struct uv_write_s uv_write_t;
+typedef struct uv_connect_s uv_connect_t;
+typedef struct uv_udp_send_s uv_udp_send_t;
+typedef struct uv_fs_s uv_fs_t;
+typedef struct uv_work_s uv_work_t;
+
+/* None of the above. */
+typedef struct uv_cpu_info_s uv_cpu_info_t;
+typedef struct uv_interface_address_s uv_interface_address_t;
+typedef struct uv_dirent_s uv_dirent_t;
+
+typedef enum {
+ UV_LOOP_BLOCK_SIGNAL
+} uv_loop_option;
+
+typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+} uv_run_mode;
+
+
+UV_EXTERN unsigned int uv_version(void);
+UV_EXTERN const char* uv_version_string(void);
+
+typedef void* (*uv_malloc_func)(size_t size);
+typedef void* (*uv_realloc_func)(void* ptr, size_t size);
+typedef void* (*uv_calloc_func)(size_t count, size_t size);
+typedef void (*uv_free_func)(void* ptr);
+
+UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func);
+
+UV_EXTERN uv_loop_t* uv_default_loop(void);
+UV_EXTERN int uv_loop_init(uv_loop_t* loop);
+UV_EXTERN int uv_loop_close(uv_loop_t* loop);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12), users should
+ * allocate the loop manually and use uv_loop_init instead.
+ */
+UV_EXTERN uv_loop_t* uv_loop_new(void);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12). Users should use
+ * uv_loop_close and free the memory manually instead.
+ */
+UV_EXTERN void uv_loop_delete(uv_loop_t*);
+UV_EXTERN size_t uv_loop_size(void);
+UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
+UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
+
+UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
+UV_EXTERN void uv_stop(uv_loop_t*);
+
+UV_EXTERN void uv_ref(uv_handle_t*);
+UV_EXTERN void uv_unref(uv_handle_t*);
+UV_EXTERN int uv_has_ref(const uv_handle_t*);
+
+UV_EXTERN void uv_update_time(uv_loop_t*);
+UV_EXTERN uint64_t uv_now(const uv_loop_t*);
+
+UV_EXTERN int uv_backend_fd(const uv_loop_t*);
+UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
+
+typedef void (*uv_alloc_cb)(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+typedef void (*uv_read_cb)(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf);
+typedef void (*uv_write_cb)(uv_write_t* req, int status);
+typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
+typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
+typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
+typedef void (*uv_close_cb)(uv_handle_t* handle);
+typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
+typedef void (*uv_timer_cb)(uv_timer_t* handle);
+typedef void (*uv_async_cb)(uv_async_t* handle);
+typedef void (*uv_prepare_cb)(uv_prepare_t* handle);
+typedef void (*uv_check_cb)(uv_check_t* handle);
+typedef void (*uv_idle_cb)(uv_idle_t* handle);
+typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal);
+typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
+typedef void (*uv_fs_cb)(uv_fs_t* req);
+typedef void (*uv_work_cb)(uv_work_t* req);
+typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
+typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res);
+typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service);
+
+typedef struct {
+ long tv_sec;
+ long tv_nsec;
+} uv_timespec_t;
+
+
+typedef struct {
+ uint64_t st_dev;
+ uint64_t st_mode;
+ uint64_t st_nlink;
+ uint64_t st_uid;
+ uint64_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_ino;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_flags;
+ uint64_t st_gen;
+ uv_timespec_t st_atim;
+ uv_timespec_t st_mtim;
+ uv_timespec_t st_ctim;
+ uv_timespec_t st_birthtim;
+} uv_stat_t;
+
+
+typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status);
+
+typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
+
+
+typedef enum {
+ UV_LEAVE_GROUP = 0,
+ UV_JOIN_GROUP
+} uv_membership;
+
+
+UV_EXTERN const char* uv_strerror(int err);
+UV_EXTERN const char* uv_err_name(int err);
+
+
+#define UV_REQ_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_req_type type; \
+ /* private */ \
+ void* active_queue[2]; \
+ void* reserved[4]; \
+ UV_REQ_PRIVATE_FIELDS \
+
+/* Abstract base class of all requests. */
+struct uv_req_s {
+ UV_REQ_FIELDS
+};
+
+
+/* Platform-specific request types. */
+UV_PRIVATE_REQ_TYPES
+
+
+UV_EXTERN int uv_shutdown(uv_shutdown_t* req,
+ uv_stream_t* handle,
+ uv_shutdown_cb cb);
+
+struct uv_shutdown_s {
+ UV_REQ_FIELDS
+ uv_stream_t* handle;
+ uv_shutdown_cb cb;
+ UV_SHUTDOWN_PRIVATE_FIELDS
+};
+
+
+#define UV_HANDLE_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_loop_t* loop; \
+ uv_handle_type type; \
+ /* private */ \
+ uv_close_cb close_cb; \
+ void* handle_queue[2]; \
+ union { \
+ int fd; \
+ void* reserved[4]; \
+ } u; \
+ UV_HANDLE_PRIVATE_FIELDS \
+
+/* The abstract base class of all handles. */
+struct uv_handle_s {
+ UV_HANDLE_FIELDS
+};
+
+UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN size_t uv_req_size(uv_req_type type);
+
+UV_EXTERN int uv_is_active(const uv_handle_t* handle);
+
+UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
+
+/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */
+UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream);
+UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream);
+
+UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
+
+UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
+UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value);
+
+UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
+
+UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
+
+
+#define UV_STREAM_FIELDS \
+ /* number of bytes queued for writing */ \
+ size_t write_queue_size; \
+ uv_alloc_cb alloc_cb; \
+ uv_read_cb read_cb; \
+ /* private */ \
+ UV_STREAM_PRIVATE_FIELDS
+
+/*
+ * uv_stream_t is a subclass of uv_handle_t.
+ *
+ * uv_stream is an abstract class.
+ *
+ * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t.
+ */
+struct uv_stream_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+};
+
+UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
+UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
+
+UV_EXTERN int uv_read_start(uv_stream_t*,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+UV_EXTERN int uv_read_stop(uv_stream_t*);
+
+UV_EXTERN int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb);
+UV_EXTERN int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb);
+UV_EXTERN int uv_try_write(uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+/* uv_write_t is a subclass of uv_req_t. */
+struct uv_write_s {
+ UV_REQ_FIELDS
+ uv_write_cb cb;
+ uv_stream_t* send_handle;
+ uv_stream_t* handle;
+ UV_WRITE_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_is_readable(const uv_stream_t* handle);
+UV_EXTERN int uv_is_writable(const uv_stream_t* handle);
+
+UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking);
+
+UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
+
+
+/*
+ * uv_tcp_t is a subclass of uv_stream_t.
+ *
+ * Represents a TCP stream or TCP server.
+ */
+struct uv_tcp_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TCP_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
+UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
+UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
+UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
+ int enable,
+ unsigned int delay);
+UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
+
+enum uv_tcp_flags {
+ /* Used with uv_tcp_bind, when an IPv6 address is used. */
+ UV_TCP_IPV6ONLY = 1
+};
+
+UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb);
+
+/* uv_connect_t is a subclass of uv_req_t. */
+struct uv_connect_s {
+ UV_REQ_FIELDS
+ uv_connect_cb cb;
+ uv_stream_t* handle;
+ UV_CONNECT_PRIVATE_FIELDS
+};
+
+
+/*
+ * UDP support.
+ */
+
+enum uv_udp_flags {
+ /* Disables dual stack mode. */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2,
+ /*
+ * Indicates if SO_REUSEADDR will be set when binding the handle.
+ * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
+ * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
+ * multiple threads or processes can bind to the same address without error
+ * (provided they all set the flag) but only the last one to bind will receive
+ * any traffic, in effect "stealing" the port from the previous listener.
+ */
+ UV_UDP_REUSEADDR = 4
+};
+
+typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
+typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags);
+
+/* uv_udp_t is a subclass of uv_handle_t. */
+struct uv_udp_s {
+ UV_HANDLE_FIELDS
+ /* read-only */
+ /*
+ * Number of bytes queued for sending. This field strictly shows how much
+ * information is currently queued.
+ */
+ size_t send_queue_size;
+ /*
+ * Number of send requests currently in the queue awaiting to be processed.
+ */
+ size_t send_queue_count;
+ UV_UDP_PRIVATE_FIELDS
+};
+
+/* uv_udp_send_t is a subclass of uv_req_t. */
+struct uv_udp_send_s {
+ UV_REQ_FIELDS
+ uv_udp_t* handle;
+ uv_udp_send_cb cb;
+ UV_UDP_SEND_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
+UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
+UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+
+UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership);
+UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
+ const char* interface_addr);
+UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb);
+UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr);
+UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb);
+UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
+
+
+/*
+ * uv_tty_t is a subclass of uv_stream_t.
+ *
+ * Representing a stream for the console.
+ */
+struct uv_tty_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TTY_PRIVATE_FIELDS
+};
+
+typedef enum {
+ /* Initial/normal terminal mode */
+ UV_TTY_MODE_NORMAL,
+ /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+ UV_TTY_MODE_RAW,
+ /* Binary-safe I/O mode for IPC (Unix-only) */
+ UV_TTY_MODE_IO
+} uv_tty_mode_t;
+
+UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
+UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
+UV_EXTERN int uv_tty_reset_mode(void);
+UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
+
+#ifdef __cplusplus
+extern "C++" {
+
+inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
+ return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
+}
+
+}
+#endif
+
+UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
+
+/*
+ * uv_pipe_t is a subclass of uv_stream_t.
+ *
+ * Representing a pipe stream or pipe server. On Windows this is a Named
+ * Pipe. On Unix this is a Unix domain socket.
+ */
+struct uv_pipe_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ int ipc; /* non-zero if this pipe is used for passing handles */
+ UV_PIPE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
+UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
+UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
+UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb);
+UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
+UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
+UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+
+
+struct uv_poll_s {
+ UV_HANDLE_FIELDS
+ uv_poll_cb poll_cb;
+ UV_POLL_PRIVATE_FIELDS
+};
+
+enum uv_poll_event {
+ UV_READABLE = 1,
+ UV_WRITABLE = 2
+};
+
+UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
+UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop,
+ uv_poll_t* handle,
+ uv_os_sock_t socket);
+UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
+UV_EXTERN int uv_poll_stop(uv_poll_t* handle);
+
+
+struct uv_prepare_s {
+ UV_HANDLE_FIELDS
+ UV_PREPARE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
+UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
+UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare);
+
+
+struct uv_check_s {
+ UV_HANDLE_FIELDS
+ UV_CHECK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check);
+UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb);
+UV_EXTERN int uv_check_stop(uv_check_t* check);
+
+
+struct uv_idle_s {
+ UV_HANDLE_FIELDS
+ UV_IDLE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
+UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
+UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
+
+
+struct uv_async_s {
+ UV_HANDLE_FIELDS
+ UV_ASYNC_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_async_init(uv_loop_t*,
+ uv_async_t* async,
+ uv_async_cb async_cb);
+UV_EXTERN int uv_async_send(uv_async_t* async);
+
+
+/*
+ * uv_timer_t is a subclass of uv_handle_t.
+ *
+ * Used to get woken up at a specified time in the future.
+ */
+struct uv_timer_s {
+ UV_HANDLE_FIELDS
+ UV_TIMER_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
+UV_EXTERN int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat);
+UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
+UV_EXTERN int uv_timer_again(uv_timer_t* handle);
+UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
+UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
+
+
+/*
+ * uv_getaddrinfo_t is a subclass of uv_req_t.
+ *
+ * Request object for uv_getaddrinfo.
+ */
+struct uv_getaddrinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* struct addrinfo* addrinfo is marked as private, but it really isn't. */
+ UV_GETADDRINFO_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints);
+UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
+
+
+/*
+* uv_getnameinfo_t is a subclass of uv_req_t.
+*
+* Request object for uv_getnameinfo.
+*/
+struct uv_getnameinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* host and service are marked as private, but they really aren't. */
+ UV_GETNAMEINFO_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags);
+
+
+/* uv_spawn() options. */
+typedef enum {
+ UV_IGNORE = 0x00,
+ UV_CREATE_PIPE = 0x01,
+ UV_INHERIT_FD = 0x02,
+ UV_INHERIT_STREAM = 0x04,
+
+ /*
+ * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
+ * determine the direction of flow, from the child process' perspective. Both
+ * flags may be specified to create a duplex data stream.
+ */
+ UV_READABLE_PIPE = 0x10,
+ UV_WRITABLE_PIPE = 0x20
+} uv_stdio_flags;
+
+typedef struct uv_stdio_container_s {
+ uv_stdio_flags flags;
+
+ union {
+ uv_stream_t* stream;
+ int fd;
+ } data;
+} uv_stdio_container_t;
+
+typedef struct uv_process_options_s {
+ uv_exit_cb exit_cb; /* Called after the process exits. */
+ const char* file; /* Path to program to execute. */
+ /*
+ * Command line arguments. args[0] should be the path to the program. On
+ * Windows this uses CreateProcess which concatenates the arguments into a
+ * string this can cause some strange errors. See the note at
+ * windows_verbatim_arguments.
+ */
+ char** args;
+ /*
+ * This will be set as the environ variable in the subprocess. If this is
+ * NULL then the parents environ will be used.
+ */
+ char** env;
+ /*
+ * If non-null this represents a directory the subprocess should execute
+ * in. Stands for current working directory.
+ */
+ const char* cwd;
+ /*
+ * Various flags that control how uv_spawn() behaves. See the definition of
+ * `enum uv_process_flags` below.
+ */
+ unsigned int flags;
+ /*
+ * The `stdio` field points to an array of uv_stdio_container_t structs that
+ * describe the file descriptors that will be made available to the child
+ * process. The convention is that stdio[0] points to stdin, fd 1 is used for
+ * stdout, and fd 2 is stderr.
+ *
+ * Note that on windows file descriptors greater than 2 are available to the
+ * child process only if the child processes uses the MSVCRT runtime.
+ */
+ int stdio_count;
+ uv_stdio_container_t* stdio;
+ /*
+ * Libuv can change the child process' user/group id. This happens only when
+ * the appropriate bits are set in the flags fields. This is not supported on
+ * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
+ */
+ uv_uid_t uid;
+ uv_gid_t gid;
+} uv_process_options_t;
+
+/*
+ * These are the flags that can be used for the uv_process_options.flags field.
+ */
+enum uv_process_flags {
+ /*
+ * Set the child process' user id. The user id is supplied in the `uid` field
+ * of the options struct. This does not work on windows; setting this flag
+ * will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id. The user id is supplied in the `gid`
+ * field of the options struct. This does not work on windows; setting this
+ * flag will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On Unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
+ /*
+ * Spawn the child process in a detached state - this will make it a process
+ * group leader, and will effectively enable the child to keep running after
+ * the parent exits. Note that the child process will still keep the
+ * parent's event loop alive unless the parent process calls uv_unref() on
+ * the child's process handle.
+ */
+ UV_PROCESS_DETACHED = (1 << 3),
+ /*
+ * Hide the subprocess console window that would normally be created. This
+ * option is only meaningful on Windows systems. On Unix it is silently
+ * ignored.
+ */
+ UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+};
+
+/*
+ * uv_process_t is a subclass of uv_handle_t.
+ */
+struct uv_process_s {
+ UV_HANDLE_FIELDS
+ uv_exit_cb exit_cb;
+ int pid;
+ UV_PROCESS_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_spawn(uv_loop_t* loop,
+ uv_process_t* handle,
+ const uv_process_options_t* options);
+UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
+UV_EXTERN int uv_kill(int pid, int signum);
+
+
+/*
+ * uv_work_t is a subclass of uv_req_t.
+ */
+struct uv_work_s {
+ UV_REQ_FIELDS
+ uv_loop_t* loop;
+ uv_work_cb work_cb;
+ uv_after_work_cb after_work_cb;
+ UV_WORK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb);
+
+UV_EXTERN int uv_cancel(uv_req_t* req);
+
+
+struct uv_cpu_info_s {
+ char* model;
+ int speed;
+ struct uv_cpu_times_s {
+ uint64_t user;
+ uint64_t nice;
+ uint64_t sys;
+ uint64_t idle;
+ uint64_t irq;
+ } cpu_times;
+};
+
+struct uv_interface_address_s {
+ char* name;
+ char phys_addr[6];
+ int is_internal;
+ union {
+ struct sockaddr_in address4;
+ struct sockaddr_in6 address6;
+ } address;
+ union {
+ struct sockaddr_in netmask4;
+ struct sockaddr_in6 netmask6;
+ } netmask;
+};
+
+typedef enum {
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK
+} uv_dirent_type_t;
+
+struct uv_dirent_s {
+ const char* name;
+ uv_dirent_type_t type;
+};
+
+UV_EXTERN char** uv_setup_args(int argc, char** argv);
+UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
+UV_EXTERN int uv_set_process_title(const char* title);
+UV_EXTERN int uv_resident_set_memory(size_t* rss);
+UV_EXTERN int uv_uptime(double* uptime);
+
+typedef struct {
+ long tv_sec;
+ long tv_usec;
+} uv_timeval_t;
+
+typedef struct {
+ uv_timeval_t ru_utime; /* user CPU time used */
+ uv_timeval_t ru_stime; /* system CPU time used */
+ uint64_t ru_maxrss; /* maximum resident set size */
+ uint64_t ru_ixrss; /* integral shared memory size */
+ uint64_t ru_idrss; /* integral unshared data size */
+ uint64_t ru_isrss; /* integral unshared stack size */
+ uint64_t ru_minflt; /* page reclaims (soft page faults) */
+ uint64_t ru_majflt; /* page faults (hard page faults) */
+ uint64_t ru_nswap; /* swaps */
+ uint64_t ru_inblock; /* block input operations */
+ uint64_t ru_oublock; /* block output operations */
+ uint64_t ru_msgsnd; /* IPC messages sent */
+ uint64_t ru_msgrcv; /* IPC messages received */
+ uint64_t ru_nsignals; /* signals received */
+ uint64_t ru_nvcsw; /* voluntary context switches */
+ uint64_t ru_nivcsw; /* involuntary context switches */
+} uv_rusage_t;
+
+UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
+
+UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
+
+UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
+UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
+
+UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count);
+UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count);
+
+
+typedef enum {
+ UV_FS_UNKNOWN = -1,
+ UV_FS_CUSTOM,
+ UV_FS_OPEN,
+ UV_FS_CLOSE,
+ UV_FS_READ,
+ UV_FS_WRITE,
+ UV_FS_SENDFILE,
+ UV_FS_STAT,
+ UV_FS_LSTAT,
+ UV_FS_FSTAT,
+ UV_FS_FTRUNCATE,
+ UV_FS_UTIME,
+ UV_FS_FUTIME,
+ UV_FS_ACCESS,
+ UV_FS_CHMOD,
+ UV_FS_FCHMOD,
+ UV_FS_FSYNC,
+ UV_FS_FDATASYNC,
+ UV_FS_UNLINK,
+ UV_FS_RMDIR,
+ UV_FS_MKDIR,
+ UV_FS_MKDTEMP,
+ UV_FS_RENAME,
+ UV_FS_SCANDIR,
+ UV_FS_LINK,
+ UV_FS_SYMLINK,
+ UV_FS_READLINK,
+ UV_FS_CHOWN,
+ UV_FS_FCHOWN,
+ UV_FS_REALPATH
+} uv_fs_type;
+
+/* uv_fs_t is a subclass of uv_req_t. */
+struct uv_fs_s {
+ UV_REQ_FIELDS
+ uv_fs_type fs_type;
+ uv_loop_t* loop;
+ uv_fs_cb cb;
+ ssize_t result;
+ void* ptr;
+ const char* path;
+ uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */
+ UV_FS_PRIVATE_FIELDS
+};
+
+UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
+UV_EXTERN int uv_fs_close(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_unlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req,
+ uv_dirent_t* ent);
+UV_EXTERN int uv_fs_stat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fsync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t in_offset,
+ size_t length,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * path argument points to a directory.
+ */
+#define UV_FS_SYMLINK_DIR 0x0001
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * the symlink is to be created using junction points.
+ */
+#define UV_FS_SYMLINK_JUNCTION 0x0002
+
+UV_EXTERN int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+
+
+enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+};
+
+
+struct uv_fs_event_s {
+ UV_HANDLE_FIELDS
+ /* private */
+ char* path;
+ UV_FS_EVENT_PRIVATE_FIELDS
+};
+
+
+/*
+ * uv_fs_stat() based polling file watcher.
+ */
+struct uv_fs_poll_s {
+ UV_HANDLE_FIELDS
+ /* Private, don't touch. */
+ void* poll_ctx;
+};
+
+UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb poll_cb,
+ const char* path,
+ unsigned int interval);
+UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle,
+ char* buffer,
+ size_t* size);
+
+
+struct uv_signal_s {
+ UV_HANDLE_FIELDS
+ uv_signal_cb signal_cb;
+ int signum;
+ UV_SIGNAL_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
+UV_EXTERN int uv_signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum);
+UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
+
+UV_EXTERN void uv_loadavg(double avg[3]);
+
+
+/*
+ * Flags to be passed to uv_fs_event_start().
+ */
+enum uv_fs_event_flags {
+ /*
+ * By default, if the fs event watcher is given a directory name, we will
+ * watch for all events in that directory. This flags overrides this behavior
+ * and makes fs_event report only changes to the directory entry itself. This
+ * flag does not affect individual files watched.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_WATCH_ENTRY = 1,
+
+ /*
+ * By default uv_fs_event will try to use a kernel interface such as inotify
+ * or kqueue to detect events. This may not work on remote filesystems such
+ * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
+ * regular interval.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_STAT = 2,
+
+ /*
+ * By default, event watcher, when watching directory, is not registering
+ * (is ignoring) changes in it's subdirectories.
+ * This flag will override this behaviour on platforms that support it.
+ */
+ UV_FS_EVENT_RECURSIVE = 4
+};
+
+
+UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags);
+UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle,
+ char* buffer,
+ size_t* size);
+
+UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
+UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
+
+UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
+UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
+
+UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
+UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
+
+UV_EXTERN int uv_exepath(char* buffer, size_t* size);
+
+UV_EXTERN int uv_cwd(char* buffer, size_t* size);
+
+UV_EXTERN int uv_chdir(const char* dir);
+
+UV_EXTERN uint64_t uv_get_free_memory(void);
+UV_EXTERN uint64_t uv_get_total_memory(void);
+
+UV_EXTERN uint64_t uv_hrtime(void);
+
+UV_EXTERN void uv_disable_stdio_inheritance(void);
+
+UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
+UV_EXTERN void uv_dlclose(uv_lib_t* lib);
+UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
+UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
+
+UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
+
+UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
+
+UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
+UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
+UV_EXTERN void uv_sem_post(uv_sem_t* sem);
+UV_EXTERN void uv_sem_wait(uv_sem_t* sem);
+UV_EXTERN int uv_sem_trywait(uv_sem_t* sem);
+
+UV_EXTERN int uv_cond_init(uv_cond_t* cond);
+UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
+UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
+UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
+
+UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
+UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
+UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
+
+UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex,
+ uint64_t timeout);
+
+UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
+
+UV_EXTERN int uv_key_create(uv_key_t* key);
+UV_EXTERN void uv_key_delete(uv_key_t* key);
+UV_EXTERN void* uv_key_get(uv_key_t* key);
+UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
+
+typedef void (*uv_thread_cb)(void* arg);
+
+UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
+UV_EXTERN uv_thread_t uv_thread_self(void);
+UV_EXTERN int uv_thread_join(uv_thread_t *tid);
+UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
+
+/* The presence of these unions force similar struct layout. */
+#define XX(_, name) uv_ ## name ## _t name;
+union uv_any_handle {
+ UV_HANDLE_TYPE_MAP(XX)
+};
+
+union uv_any_req {
+ UV_REQ_TYPE_MAP(XX)
+};
+#undef XX
+
+
+struct uv_loop_s {
+ /* User data - use this for whatever. */
+ void* data;
+ /* Loop reference counting. */
+ unsigned int active_handles;
+ void* handle_queue[2];
+ void* active_reqs[2];
+ /* Internal flag to signal loop stop. */
+ unsigned int stop_flag;
+ UV_LOOP_PRIVATE_FIELDS
+};
+
+
+/* Don't export the private CPP symbols. */
+#undef UV_HANDLE_TYPE_PRIVATE
+#undef UV_REQ_TYPE_PRIVATE
+#undef UV_REQ_PRIVATE_FIELDS
+#undef UV_STREAM_PRIVATE_FIELDS
+#undef UV_TCP_PRIVATE_FIELDS
+#undef UV_PREPARE_PRIVATE_FIELDS
+#undef UV_CHECK_PRIVATE_FIELDS
+#undef UV_IDLE_PRIVATE_FIELDS
+#undef UV_ASYNC_PRIVATE_FIELDS
+#undef UV_TIMER_PRIVATE_FIELDS
+#undef UV_GETADDRINFO_PRIVATE_FIELDS
+#undef UV_GETNAMEINFO_PRIVATE_FIELDS
+#undef UV_FS_REQ_PRIVATE_FIELDS
+#undef UV_WORK_PRIVATE_FIELDS
+#undef UV_FS_EVENT_PRIVATE_FIELDS
+#undef UV_SIGNAL_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* UV_H */
diff --git a/3rdparty/libuv/libuv.nsi b/3rdparty/libuv/libuv.nsi
new file mode 100644
index 00000000000..159756e196c
--- /dev/null
+++ b/3rdparty/libuv/libuv.nsi
@@ -0,0 +1,86 @@
+; NSIS installer script for libuv
+
+!include "MUI2.nsh"
+
+Name "libuv"
+OutFile "libuv-${ARCH}-${VERSION}.exe"
+
+!include "x64.nsh"
+# Default install location, for 32-bit files
+InstallDir "$PROGRAMFILES\libuv"
+
+# Override install and registry locations if this is a 64-bit install.
+function .onInit
+ ${If} ${ARCH} == "x64"
+ SetRegView 64
+ StrCpy $INSTDIR "$PROGRAMFILES64\libuv"
+ ${EndIf}
+functionEnd
+
+;--------------------------------
+; Installer pages
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+
+;--------------------------------
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+; Languages
+!insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+; Installer sections
+
+Section "Files" SecInstall
+ SectionIn RO
+ SetOutPath "$INSTDIR"
+ File "Release\*.dll"
+ File "Release\*.lib"
+ File "LICENSE"
+ File "README.md"
+
+ SetOutPath "$INSTDIR\include"
+ File "include\uv.h"
+ File "include\uv-errno.h"
+ File "include\uv-threadpool.h"
+ File "include\uv-version.h"
+ File "include\uv-win.h"
+ File "include\tree.h"
+
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayName" "libuv-${ARCH}-${VERSION}"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "HelpLink" "http://libuv.org/"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "URLInfoAbout" "http://libuv.org/"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayVersion" "${VERSION}"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoModify" "1"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoRepair" "1"
+SectionEnd
+
+Section "Uninstall"
+ Delete "$INSTDIR\libuv.dll"
+ Delete "$INSTDIR\libuv.lib"
+ Delete "$INSTDIR\LICENSE"
+ Delete "$INSTDIR\README.md"
+
+ Delete "$INSTDIR\include\uv.h"
+ Delete "$INSTDIR\include\uv-errno.h"
+ Delete "$INSTDIR\include\uv-threadpool.h"
+ Delete "$INSTDIR\include\uv-version.h"
+ Delete "$INSTDIR\include\uv-win.h"
+ Delete "$INSTDIR\include\tree.h"
+
+ Delete "$INSTDIR\Uninstall.exe"
+ RMDir "$INSTDIR"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}"
+SectionEnd
+
diff --git a/3rdparty/libuv/libuv.pc.in b/3rdparty/libuv/libuv.pc.in
new file mode 100644
index 00000000000..2933ec22526
--- /dev/null
+++ b/3rdparty/libuv/libuv.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Version: @PACKAGE_VERSION@
+Description: multi-platform support library with a focus on asynchronous I/O.
+
+Libs: -L${libdir} -luv @LIBS@
+Cflags: -I${includedir}
diff --git a/3rdparty/libuv/m4/.gitignore b/3rdparty/libuv/m4/.gitignore
new file mode 100644
index 00000000000..c44e4c2929a
--- /dev/null
+++ b/3rdparty/libuv/m4/.gitignore
@@ -0,0 +1,4 @@
+# Ignore libtoolize-generated files.
+*.m4
+!as_case.m4
+!libuv-check-flags.m4
diff --git a/3rdparty/libuv/m4/as_case.m4 b/3rdparty/libuv/m4/as_case.m4
new file mode 100644
index 00000000000..c7ae0f0f5ed
--- /dev/null
+++ b/3rdparty/libuv/m4/as_case.m4
@@ -0,0 +1,21 @@
+# AS_CASE(WORD, [PATTERN1], [IF-MATCHED1]...[DEFAULT])
+# ----------------------------------------------------
+# Expand into
+# | case WORD in
+# | PATTERN1) IF-MATCHED1 ;;
+# | ...
+# | *) DEFAULT ;;
+# | esac
+m4_define([_AS_CASE],
+[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
+ [$#], 1, [ *) $1 ;;],
+ [$#], 2, [ $1) m4_default([$2], [:]) ;;],
+ [ $1) m4_default([$2], [:]) ;;
+$0(m4_shiftn(2, $@))])dnl
+])
+m4_defun([AS_CASE],
+[m4_ifval([$2$3],
+[case $1 in
+_AS_CASE(m4_shift($@))
+esac])])
+
diff --git a/3rdparty/libuv/m4/libuv-check-flags.m4 b/3rdparty/libuv/m4/libuv-check-flags.m4
new file mode 100644
index 00000000000..59c30635577
--- /dev/null
+++ b/3rdparty/libuv/m4/libuv-check-flags.m4
@@ -0,0 +1,319 @@
+dnl Macros to check the presence of generic (non-typed) symbols.
+dnl Copyright (c) 2006-2008 Diego Pettenà <flameeyes gmail com>
+dnl Copyright (c) 2006-2008 xine project
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+dnl 02110-1301, USA.
+dnl
+dnl As a special exception, the copyright owners of the
+dnl macro gives unlimited permission to copy, distribute and modify the
+dnl configure scripts that are the output of Autoconf when processing the
+dnl Macro. You need not follow the terms of the GNU General Public
+dnl License when using or distributing such scripts, even though portions
+dnl of the text of the Macro appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that
+dnl constitutes the Autoconf Macro.
+dnl
+dnl This special exception to the GPL applies to versions of the
+dnl Autoconf Macro released by this project. When you make and
+dnl distribute a modified version of the Autoconf Macro, you may extend
+dnl this special exception to the GPL to apply to your modified version as
+dnl well.
+
+dnl Check if the flag is supported by compiler
+dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
+ AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl Check if the flag is supported by compiler (cacheable)
+dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_CFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_cflags_$1]),
+ CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
+ )
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found])
+dnl Check for CFLAG and appends them to CFLAGS if supported
+AC_DEFUN([CC_CHECK_CFLAG_APPEND], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_cflags_$1]),
+ CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
+ )
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3])
+])
+
+dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not])
+AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [
+ for flag in $1; do
+ CC_CHECK_CFLAG_APPEND($flag, [$2], [$3])
+ done
+])
+
+dnl Check if the flag is supported by linker (cacheable)
+dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_LDFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_ldflags_$1]),
+ [ac_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $1"
+ AC_LANG_PUSH([C])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])="])
+ AC_LANG_POP([C])
+ LDFLAGS="$ac_save_LDFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
+dnl the current linker to avoid undefined references in a shared object.
+AC_DEFUN([CC_NOUNDEFINED], [
+ dnl We check $host for which systems to enable this for.
+ AC_REQUIRE([AC_CANONICAL_HOST])
+
+ case $host in
+ dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
+ dnl are requested, as different implementations are present; to avoid problems
+ dnl use -Wl,-z,defs only for those platform not behaving this way.
+ *-freebsd* | *-openbsd*) ;;
+ *)
+ dnl First of all check for the --no-undefined variant of GNU ld. This allows
+ dnl for a much more readable commandline, so that people can understand what
+ dnl it does without going to look for what the heck -z defs does.
+ for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
+ CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
+ break
+ done
+ ;;
+ esac
+
+ AC_SUBST([LDFLAGS_NOUNDEFINED])
+])
+
+dnl Check for a -Werror flag or equivalent. -Werror is the GCC
+dnl and ICC flag that tells the compiler to treat all the warnings
+dnl as fatal. We usually need this option to make sure that some
+dnl constructs (like attributes) are not simply ignored.
+dnl
+dnl Other compilers don't support -Werror per se, but they support
+dnl an equivalent flag:
+dnl - Sun Studio compiler supports -errwarn=%all
+AC_DEFUN([CC_CHECK_WERROR], [
+ AC_CACHE_CHECK(
+ [for $CC way to treat warnings as errors],
+ [cc_cv_werror],
+ [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
+ [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
+ ])
+])
+
+AC_DEFUN([CC_CHECK_ATTRIBUTE], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
+ AS_TR_SH([cc_cv_attribute_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
+ [AC_DEFINE(
+ AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
+ [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
+ )
+ $4],
+ [$5])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
+ CC_CHECK_ATTRIBUTE(
+ [constructor],,
+ [void __attribute__((constructor)) ctor() { int a; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
+ CC_CHECK_ATTRIBUTE(
+ [format], [format(printf, n, n)],
+ [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
+ CC_CHECK_ATTRIBUTE(
+ [format_arg], [format_arg(printf)],
+ [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
+ CC_CHECK_ATTRIBUTE(
+ [visibility_$1], [visibility("$1")],
+ [void __attribute__((visibility("$1"))) $1_function() { }],
+ [$2], [$3])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
+ CC_CHECK_ATTRIBUTE(
+ [nonnull], [nonnull()],
+ [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
+ CC_CHECK_ATTRIBUTE(
+ [unused], ,
+ [void some_function(void *foo, __attribute__((unused)) void *bar);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
+ CC_CHECK_ATTRIBUTE(
+ [sentinel], ,
+ [void some_function(void *foo, ...) __attribute__((sentinel));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
+ CC_CHECK_ATTRIBUTE(
+ [deprecated], ,
+ [void some_function(void *foo, ...) __attribute__((deprecated));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
+ CC_CHECK_ATTRIBUTE(
+ [alias], [weak, alias],
+ [void other_function(void *foo) { }
+ void some_function(void *foo) __attribute__((weak, alias("other_function")));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
+ CC_CHECK_ATTRIBUTE(
+ [malloc], ,
+ [void * __attribute__((malloc)) my_alloc(int n);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_PACKED], [
+ CC_CHECK_ATTRIBUTE(
+ [packed], ,
+ [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONST], [
+ CC_CHECK_ATTRIBUTE(
+ [const], ,
+ [int __attribute__((const)) twopow(int n) { return 1 << n; } ],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_FLAG_VISIBILITY], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
+ [cc_cv_flag_visibility],
+ [cc_flag_visibility_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
+ cc_cv_flag_visibility='yes',
+ cc_cv_flag_visibility='no')
+ CFLAGS="$cc_flag_visibility_save_CFLAGS"])
+
+ AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
+ [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
+ [Define this if the compiler supports the -fvisibility flag])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_FUNC_EXPECT], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if compiler has __builtin_expect function],
+ [cc_cv_func_expect],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ [int some_function() {
+ int a = 3;
+ return (int)__builtin_expect(a, 3);
+ }])],
+ [cc_cv_func_expect=yes],
+ [cc_cv_func_expect=no])
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([test "x$cc_cv_func_expect" = "xyes"],
+ [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
+ [Define this if the compiler supports __builtin_expect() function])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
+ [cc_cv_attribute_aligned],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ for cc_attribute_align_try in 64 32 16 8 4 2; do
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ int main() {
+ static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
+ return c;
+ }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
+ done
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ if test "x$cc_cv_attribute_aligned" != "x"; then
+ AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
+ [Define the highest alignment supported])
+ fi
+]) \ No newline at end of file
diff --git a/3rdparty/libuv/samples/.gitignore b/3rdparty/libuv/samples/.gitignore
new file mode 100644
index 00000000000..f868091ba32
--- /dev/null
+++ b/3rdparty/libuv/samples/.gitignore
@@ -0,0 +1,22 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+*.mk
+*.Makefile
diff --git a/3rdparty/libuv/samples/socks5-proxy/.gitignore b/3rdparty/libuv/samples/socks5-proxy/.gitignore
new file mode 100644
index 00000000000..c177f374510
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/.gitignore
@@ -0,0 +1,21 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+/build/
diff --git a/3rdparty/libuv/samples/socks5-proxy/LICENSE b/3rdparty/libuv/samples/socks5-proxy/LICENSE
new file mode 100644
index 00000000000..63c1447fc55
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/LICENSE
@@ -0,0 +1,53 @@
+Files: *
+========
+
+Copyright StrongLoop, Inc. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+
+Files: getopt.c
+===============
+
+Copyright (c) 1987, 1993, 1994
+The Regents of the University of California. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/3rdparty/libuv/samples/socks5-proxy/Makefile b/3rdparty/libuv/samples/socks5-proxy/Makefile
new file mode 100644
index 00000000000..ca43985ec80
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/Makefile
@@ -0,0 +1,46 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+BUILDTYPE ?= Debug
+BUILDDIR ?= build
+GYP ?= gyp
+V ?=
+
+SOURCES := client.c defs.h getopt.c main.c s5.c s5.h server.c util.c
+
+.PHONY: all clean
+
+all: $(BUILDDIR)/$(BUILDTYPE)/s5-proxy
+
+clean:
+ $(RM) $(BUILDDIR)
+
+$(BUILDDIR)/$(BUILDTYPE)/s5-proxy: $(BUILDDIR)/Makefile $(SOURCES)
+ $(MAKE) -C $(BUILDDIR) V=$(V)
+
+$(BUILDDIR)/Makefile: ../../common.gypi build.gyp
+ $(GYP) \
+ -Duv_library=static_library \
+ -Goutput_dir=. \
+ -I../../common.gypi \
+ -f make \
+ --depth=. \
+ --generator-output=$(BUILDDIR) \
+ build.gyp
diff --git a/3rdparty/libuv/samples/socks5-proxy/build.gyp b/3rdparty/libuv/samples/socks5-proxy/build.gyp
new file mode 100644
index 00000000000..771a1e146db
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/build.gyp
@@ -0,0 +1,46 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+{
+ 'targets': [
+ {
+ 'dependencies': ['../../uv.gyp:libuv'],
+ 'target_name': 's5-proxy',
+ 'type': 'executable',
+ 'sources': [
+ 'client.c',
+ 'defs.h',
+ 'main.c',
+ 's5.c',
+ 's5.h',
+ 'server.c',
+ 'util.c',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': ['HAVE_UNISTD_H=0'],
+ 'sources': ['getopt.c']
+ }, {
+ 'defines': ['HAVE_UNISTD_H=1']
+ }]
+ ]
+ }
+ ]
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/client.c b/3rdparty/libuv/samples/socks5-proxy/client.c
new file mode 100644
index 00000000000..ae9913a1c6e
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/client.c
@@ -0,0 +1,737 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* A connection is modeled as an abstraction on top of two simple state
+ * machines, one for reading and one for writing. Either state machine
+ * is, when active, in one of three states: busy, done or stop; the fourth
+ * and final state, dead, is an end state and only relevant when shutting
+ * down the connection. A short overview:
+ *
+ * busy done stop
+ * ----------|---------------------------|--------------------|------|
+ * readable | waiting for incoming data | have incoming data | idle |
+ * writable | busy writing out data | completed write | idle |
+ *
+ * We could remove the done state from the writable state machine. For our
+ * purposes, it's functionally equivalent to the stop state.
+ *
+ * When the connection with upstream has been established, the client_ctx
+ * moves into a state where incoming data from the client is sent upstream
+ * and vice versa, incoming data from upstream is sent to the client. In
+ * other words, we're just piping data back and forth. See conn_cycle()
+ * for details.
+ *
+ * An interesting deviation from libuv's I/O model is that reads are discrete
+ * rather than continuous events. In layman's terms, when a read operation
+ * completes, the connection stops reading until further notice.
+ *
+ * The rationale for this approach is that we have to wait until the data
+ * has been sent out again before we can reuse the read buffer.
+ *
+ * It also pleasingly unifies with the request model that libuv uses for
+ * writes and everything else; libuv may switch to a request model for
+ * reads in the future.
+ */
+enum conn_state {
+ c_busy, /* Busy; waiting for incoming data or for a write to complete. */
+ c_done, /* Done; read incoming data or write finished. */
+ c_stop, /* Stopped. */
+ c_dead
+};
+
+/* Session states. */
+enum sess_state {
+ s_handshake, /* Wait for client handshake. */
+ s_handshake_auth, /* Wait for client authentication data. */
+ s_req_start, /* Start waiting for request data. */
+ s_req_parse, /* Wait for request data. */
+ s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */
+ s_req_connect, /* Wait for uv_tcp_connect() to complete. */
+ s_proxy_start, /* Connected. Start piping data. */
+ s_proxy, /* Connected. Pipe data back and forth. */
+ s_kill, /* Tear down session. */
+ s_almost_dead_0, /* Waiting for finalizers to complete. */
+ s_almost_dead_1, /* Waiting for finalizers to complete. */
+ s_almost_dead_2, /* Waiting for finalizers to complete. */
+ s_almost_dead_3, /* Waiting for finalizers to complete. */
+ s_almost_dead_4, /* Waiting for finalizers to complete. */
+ s_dead /* Dead. Safe to free now. */
+};
+
+static void do_next(client_ctx *cx);
+static int do_handshake(client_ctx *cx);
+static int do_handshake_auth(client_ctx *cx);
+static int do_req_start(client_ctx *cx);
+static int do_req_parse(client_ctx *cx);
+static int do_req_lookup(client_ctx *cx);
+static int do_req_connect_start(client_ctx *cx);
+static int do_req_connect(client_ctx *cx);
+static int do_proxy_start(client_ctx *cx);
+static int do_proxy(client_ctx *cx);
+static int do_kill(client_ctx *cx);
+static int do_almost_dead(client_ctx *cx);
+static int conn_cycle(const char *who, conn *a, conn *b);
+static void conn_timer_reset(conn *c);
+static void conn_timer_expire(uv_timer_t *handle, int status);
+static void conn_getaddrinfo(conn *c, const char *hostname);
+static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
+ int status,
+ struct addrinfo *ai);
+static int conn_connect(conn *c);
+static void conn_connect_done(uv_connect_t *req, int status);
+static void conn_read(conn *c);
+static void conn_read_done(uv_stream_t *handle,
+ ssize_t nread,
+ const uv_buf_t *buf);
+static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf);
+static void conn_write(conn *c, const void *data, unsigned int len);
+static void conn_write_done(uv_write_t *req, int status);
+static void conn_close(conn *c);
+static void conn_close_done(uv_handle_t *handle);
+
+/* |incoming| has been initialized by server.c when this is called. */
+void client_finish_init(server_ctx *sx, client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+
+ cx->sx = sx;
+ cx->state = s_handshake;
+ s5_init(&cx->parser);
+
+ incoming = &cx->incoming;
+ incoming->client = cx;
+ incoming->result = 0;
+ incoming->rdstate = c_stop;
+ incoming->wrstate = c_stop;
+ incoming->idle_timeout = sx->idle_timeout;
+ CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle));
+
+ outgoing = &cx->outgoing;
+ outgoing->client = cx;
+ outgoing->result = 0;
+ outgoing->rdstate = c_stop;
+ outgoing->wrstate = c_stop;
+ outgoing->idle_timeout = sx->idle_timeout;
+ CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp));
+ CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle));
+
+ /* Wait for the initial packet. */
+ conn_read(incoming);
+}
+
+/* This is the core state machine that drives the client <-> upstream proxy.
+ * We move through the initial handshake and authentication steps first and
+ * end up (if all goes well) in the proxy state where we're just proxying
+ * data between the client and upstream.
+ */
+static void do_next(client_ctx *cx) {
+ int new_state;
+
+ ASSERT(cx->state != s_dead);
+ switch (cx->state) {
+ case s_handshake:
+ new_state = do_handshake(cx);
+ break;
+ case s_handshake_auth:
+ new_state = do_handshake_auth(cx);
+ break;
+ case s_req_start:
+ new_state = do_req_start(cx);
+ break;
+ case s_req_parse:
+ new_state = do_req_parse(cx);
+ break;
+ case s_req_lookup:
+ new_state = do_req_lookup(cx);
+ break;
+ case s_req_connect:
+ new_state = do_req_connect(cx);
+ break;
+ case s_proxy_start:
+ new_state = do_proxy_start(cx);
+ break;
+ case s_proxy:
+ new_state = do_proxy(cx);
+ break;
+ case s_kill:
+ new_state = do_kill(cx);
+ break;
+ case s_almost_dead_0:
+ case s_almost_dead_1:
+ case s_almost_dead_2:
+ case s_almost_dead_3:
+ case s_almost_dead_4:
+ new_state = do_almost_dead(cx);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ cx->state = new_state;
+
+ if (cx->state == s_dead) {
+ if (DEBUG_CHECKS) {
+ memset(cx, -1, sizeof(*cx));
+ }
+ free(cx);
+ }
+}
+
+static int do_handshake(client_ctx *cx) {
+ unsigned int methods;
+ conn *incoming;
+ s5_ctx *parser;
+ uint8_t *data;
+ size_t size;
+ int err;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ ASSERT(incoming->rdstate == c_done);
+ ASSERT(incoming->wrstate == c_stop);
+ incoming->rdstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("read error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ data = (uint8_t *) incoming->t.buf;
+ size = (size_t) incoming->result;
+ err = s5_parse(parser, &data, &size);
+ if (err == s5_ok) {
+ conn_read(incoming);
+ return s_handshake; /* Need more data. */
+ }
+
+ if (size != 0) {
+ /* Could allow a round-trip saving shortcut here if the requested auth
+ * method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.)
+ * Requires client support however.
+ */
+ pr_err("junk in handshake");
+ return do_kill(cx);
+ }
+
+ if (err != s5_auth_select) {
+ pr_err("handshake error: %s", s5_strerror(err));
+ return do_kill(cx);
+ }
+
+ methods = s5_auth_methods(parser);
+ if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) {
+ s5_select_auth(parser, S5_AUTH_NONE);
+ conn_write(incoming, "\5\0", 2); /* No auth required. */
+ return s_req_start;
+ }
+
+ if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) {
+ /* TODO(bnoordhuis) Implement username/password auth. */
+ }
+
+ conn_write(incoming, "\5\377", 2); /* No acceptable auth. */
+ return s_kill;
+}
+
+/* TODO(bnoordhuis) Implement username/password auth. */
+static int do_handshake_auth(client_ctx *cx) {
+ UNREACHABLE();
+ return do_kill(cx);
+}
+
+static int do_req_start(client_ctx *cx) {
+ conn *incoming;
+
+ incoming = &cx->incoming;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_done);
+ incoming->wrstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("write error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ conn_read(incoming);
+ return s_req_parse;
+}
+
+static int do_req_parse(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+ s5_ctx *parser;
+ uint8_t *data;
+ size_t size;
+ int err;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_done);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+ incoming->rdstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("read error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ data = (uint8_t *) incoming->t.buf;
+ size = (size_t) incoming->result;
+ err = s5_parse(parser, &data, &size);
+ if (err == s5_ok) {
+ conn_read(incoming);
+ return s_req_parse; /* Need more data. */
+ }
+
+ if (size != 0) {
+ pr_err("junk in request %u", (unsigned) size);
+ return do_kill(cx);
+ }
+
+ if (err != s5_exec_cmd) {
+ pr_err("request error: %s", s5_strerror(err));
+ return do_kill(cx);
+ }
+
+ if (parser->cmd == s5_cmd_tcp_bind) {
+ /* Not supported but relatively straightforward to implement. */
+ pr_warn("BIND requests are not supported.");
+ return do_kill(cx);
+ }
+
+ if (parser->cmd == s5_cmd_udp_assoc) {
+ /* Not supported. Might be hard to implement because libuv has no
+ * functionality for detecting the MTU size which the RFC mandates.
+ */
+ pr_warn("UDP ASSOC requests are not supported.");
+ return do_kill(cx);
+ }
+ ASSERT(parser->cmd == s5_cmd_tcp_connect);
+
+ if (parser->atyp == s5_atyp_host) {
+ conn_getaddrinfo(outgoing, (const char *) parser->daddr);
+ return s_req_lookup;
+ }
+
+ if (parser->atyp == s5_atyp_ipv4) {
+ memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4));
+ outgoing->t.addr4.sin_family = AF_INET;
+ outgoing->t.addr4.sin_port = htons(parser->dport);
+ memcpy(&outgoing->t.addr4.sin_addr,
+ parser->daddr,
+ sizeof(outgoing->t.addr4.sin_addr));
+ } else if (parser->atyp == s5_atyp_ipv6) {
+ memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6));
+ outgoing->t.addr6.sin6_family = AF_INET6;
+ outgoing->t.addr6.sin6_port = htons(parser->dport);
+ memcpy(&outgoing->t.addr6.sin6_addr,
+ parser->daddr,
+ sizeof(outgoing->t.addr6.sin6_addr));
+ } else {
+ UNREACHABLE();
+ }
+
+ return do_req_connect_start(cx);
+}
+
+static int do_req_lookup(client_ctx *cx) {
+ s5_ctx *parser;
+ conn *incoming;
+ conn *outgoing;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ if (outgoing->result < 0) {
+ /* TODO(bnoordhuis) Escape control characters in parser->daddr. */
+ pr_err("lookup error for \"%s\": %s",
+ parser->daddr,
+ uv_strerror(outgoing->result));
+ /* Send back a 'Host unreachable' reply. */
+ conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ /* Don't make assumptions about the offset of sin_port/sin6_port. */
+ switch (outgoing->t.addr.sa_family) {
+ case AF_INET:
+ outgoing->t.addr4.sin_port = htons(parser->dport);
+ break;
+ case AF_INET6:
+ outgoing->t.addr6.sin6_port = htons(parser->dport);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return do_req_connect_start(cx);
+}
+
+/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */
+static int do_req_connect_start(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+ int err;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ if (!can_access(cx->sx, cx, &outgoing->t.addr)) {
+ pr_warn("connection not allowed by ruleset");
+ /* Send a 'Connection not allowed by ruleset' reply. */
+ conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ err = conn_connect(outgoing);
+ if (err != 0) {
+ pr_err("connect error: %s\n", uv_strerror(err));
+ return do_kill(cx);
+ }
+
+ return s_req_connect;
+}
+
+static int do_req_connect(client_ctx *cx) {
+ const struct sockaddr_in6 *in6;
+ const struct sockaddr_in *in;
+ char addr_storage[sizeof(*in6)];
+ conn *incoming;
+ conn *outgoing;
+ uint8_t *buf;
+ int addrlen;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ /* Build and send the reply. Not very pretty but gets the job done. */
+ buf = (uint8_t *) incoming->t.buf;
+ if (outgoing->result == 0) {
+ /* The RFC mandates that the SOCKS server must include the local port
+ * and address in the reply. So that's what we do.
+ */
+ addrlen = sizeof(addr_storage);
+ CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp,
+ (struct sockaddr *) addr_storage,
+ &addrlen));
+ buf[0] = 5; /* Version. */
+ buf[1] = 0; /* Success. */
+ buf[2] = 0; /* Reserved. */
+ if (addrlen == sizeof(*in)) {
+ buf[3] = 1; /* IPv4. */
+ in = (const struct sockaddr_in *) &addr_storage;
+ memcpy(buf + 4, &in->sin_addr, 4);
+ memcpy(buf + 8, &in->sin_port, 2);
+ conn_write(incoming, buf, 10);
+ } else if (addrlen == sizeof(*in6)) {
+ buf[3] = 4; /* IPv6. */
+ in6 = (const struct sockaddr_in6 *) &addr_storage;
+ memcpy(buf + 4, &in6->sin6_addr, 16);
+ memcpy(buf + 20, &in6->sin6_port, 2);
+ conn_write(incoming, buf, 22);
+ } else {
+ UNREACHABLE();
+ }
+ return s_proxy_start;
+ } else {
+ pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result));
+ /* Send a 'Connection refused' reply. */
+ conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ UNREACHABLE();
+ return s_kill;
+}
+
+static int do_proxy_start(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_done);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+ incoming->wrstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("write error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ conn_read(incoming);
+ conn_read(outgoing);
+ return s_proxy;
+}
+
+/* Proxy incoming data back and forth. */
+static int do_proxy(client_ctx *cx) {
+ if (conn_cycle("client", &cx->incoming, &cx->outgoing)) {
+ return do_kill(cx);
+ }
+
+ if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) {
+ return do_kill(cx);
+ }
+
+ return s_proxy;
+}
+
+static int do_kill(client_ctx *cx) {
+ int new_state;
+
+ if (cx->state >= s_almost_dead_0) {
+ return cx->state;
+ }
+
+ /* Try to cancel the request. The callback still runs but if the
+ * cancellation succeeded, it gets called with status=UV_ECANCELED.
+ */
+ new_state = s_almost_dead_1;
+ if (cx->state == s_req_lookup) {
+ new_state = s_almost_dead_0;
+ uv_cancel(&cx->outgoing.t.req);
+ }
+
+ conn_close(&cx->incoming);
+ conn_close(&cx->outgoing);
+ return new_state;
+}
+
+static int do_almost_dead(client_ctx *cx) {
+ ASSERT(cx->state >= s_almost_dead_0);
+ return cx->state + 1; /* Another finalizer completed. */
+}
+
+static int conn_cycle(const char *who, conn *a, conn *b) {
+ if (a->result < 0) {
+ if (a->result != UV_EOF) {
+ pr_err("%s error: %s", who, uv_strerror(a->result));
+ }
+ return -1;
+ }
+
+ if (b->result < 0) {
+ return -1;
+ }
+
+ if (a->wrstate == c_done) {
+ a->wrstate = c_stop;
+ }
+
+ /* The logic is as follows: read when we don't write and write when we don't
+ * read. That gives us back-pressure handling for free because if the peer
+ * sends data faster than we consume it, TCP congestion control kicks in.
+ */
+ if (a->wrstate == c_stop) {
+ if (b->rdstate == c_stop) {
+ conn_read(b);
+ } else if (b->rdstate == c_done) {
+ conn_write(a, b->t.buf, b->result);
+ b->rdstate = c_stop; /* Triggers the call to conn_read() above. */
+ }
+ }
+
+ return 0;
+}
+
+static void conn_timer_reset(conn *c) {
+ CHECK(0 == uv_timer_start(&c->timer_handle,
+ conn_timer_expire,
+ c->idle_timeout,
+ 0));
+}
+
+static void conn_timer_expire(uv_timer_t *handle, int status) {
+ conn *c;
+
+ CHECK(0 == status);
+ c = CONTAINER_OF(handle, conn, timer_handle);
+ c->result = UV_ETIMEDOUT;
+ do_next(c->client);
+}
+
+static void conn_getaddrinfo(conn *c, const char *hostname) {
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ CHECK(0 == uv_getaddrinfo(c->client->sx->loop,
+ &c->t.addrinfo_req,
+ conn_getaddrinfo_done,
+ hostname,
+ NULL,
+ &hints));
+ conn_timer_reset(c);
+}
+
+static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
+ int status,
+ struct addrinfo *ai) {
+ conn *c;
+
+ c = CONTAINER_OF(req, conn, t.addrinfo_req);
+ c->result = status;
+
+ if (status == 0) {
+ /* FIXME(bnoordhuis) Should try all addresses. */
+ if (ai->ai_family == AF_INET) {
+ c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
+ } else if (ai->ai_family == AF_INET6) {
+ c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
+ } else {
+ UNREACHABLE();
+ }
+ }
+
+ uv_freeaddrinfo(ai);
+ do_next(c->client);
+}
+
+/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */
+static int conn_connect(conn *c) {
+ ASSERT(c->t.addr.sa_family == AF_INET ||
+ c->t.addr.sa_family == AF_INET6);
+ conn_timer_reset(c);
+ return uv_tcp_connect(&c->t.connect_req,
+ &c->handle.tcp,
+ &c->t.addr,
+ conn_connect_done);
+}
+
+static void conn_connect_done(uv_connect_t *req, int status) {
+ conn *c;
+
+ if (status == UV_ECANCELED) {
+ return; /* Handle has been closed. */
+ }
+
+ c = CONTAINER_OF(req, conn, t.connect_req);
+ c->result = status;
+ do_next(c->client);
+}
+
+static void conn_read(conn *c) {
+ ASSERT(c->rdstate == c_stop);
+ CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done));
+ c->rdstate = c_busy;
+ conn_timer_reset(c);
+}
+
+static void conn_read_done(uv_stream_t *handle,
+ ssize_t nread,
+ const uv_buf_t *buf) {
+ conn *c;
+
+ c = CONTAINER_OF(handle, conn, handle);
+ ASSERT(c->t.buf == buf->base);
+ ASSERT(c->rdstate == c_busy);
+ c->rdstate = c_done;
+ c->result = nread;
+
+ uv_read_stop(&c->handle.stream);
+ do_next(c->client);
+}
+
+static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
+ conn *c;
+
+ c = CONTAINER_OF(handle, conn, handle);
+ ASSERT(c->rdstate == c_busy);
+ buf->base = c->t.buf;
+ buf->len = sizeof(c->t.buf);
+}
+
+static void conn_write(conn *c, const void *data, unsigned int len) {
+ uv_buf_t buf;
+
+ ASSERT(c->wrstate == c_stop || c->wrstate == c_done);
+ c->wrstate = c_busy;
+
+ /* It's okay to cast away constness here, uv_write() won't modify the
+ * memory.
+ */
+ buf.base = (char *) data;
+ buf.len = len;
+
+ CHECK(0 == uv_write(&c->write_req,
+ &c->handle.stream,
+ &buf,
+ 1,
+ conn_write_done));
+ conn_timer_reset(c);
+}
+
+static void conn_write_done(uv_write_t *req, int status) {
+ conn *c;
+
+ if (status == UV_ECANCELED) {
+ return; /* Handle has been closed. */
+ }
+
+ c = CONTAINER_OF(req, conn, write_req);
+ ASSERT(c->wrstate == c_busy);
+ c->wrstate = c_done;
+ c->result = status;
+ do_next(c->client);
+}
+
+static void conn_close(conn *c) {
+ ASSERT(c->rdstate != c_dead);
+ ASSERT(c->wrstate != c_dead);
+ c->rdstate = c_dead;
+ c->wrstate = c_dead;
+ c->timer_handle.data = c;
+ c->handle.handle.data = c;
+ uv_close(&c->handle.handle, conn_close_done);
+ uv_close((uv_handle_t *) &c->timer_handle, conn_close_done);
+}
+
+static void conn_close_done(uv_handle_t *handle) {
+ conn *c;
+
+ c = handle->data;
+ do_next(c->client);
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/defs.h b/3rdparty/libuv/samples/socks5-proxy/defs.h
new file mode 100644
index 00000000000..99ee8160c8a
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/defs.h
@@ -0,0 +1,139 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef DEFS_H_
+#define DEFS_H_
+
+#include "s5.h"
+#include "uv.h"
+
+#include <assert.h>
+#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
+#include <stddef.h> /* size_t, ssize_t */
+#include <stdint.h>
+#include <sys/socket.h> /* sockaddr */
+
+struct client_ctx;
+
+typedef struct {
+ const char *bind_host;
+ unsigned short bind_port;
+ unsigned int idle_timeout;
+} server_config;
+
+typedef struct {
+ unsigned int idle_timeout; /* Connection idle timeout in ms. */
+ uv_tcp_t tcp_handle;
+ uv_loop_t *loop;
+} server_ctx;
+
+typedef struct {
+ unsigned char rdstate;
+ unsigned char wrstate;
+ unsigned int idle_timeout;
+ struct client_ctx *client; /* Backlink to owning client context. */
+ ssize_t result;
+ union {
+ uv_handle_t handle;
+ uv_stream_t stream;
+ uv_tcp_t tcp;
+ uv_udp_t udp;
+ } handle;
+ uv_timer_t timer_handle; /* For detecting timeouts. */
+ uv_write_t write_req;
+ /* We only need one of these at a time so make them share memory. */
+ union {
+ uv_getaddrinfo_t addrinfo_req;
+ uv_connect_t connect_req;
+ uv_req_t req;
+ struct sockaddr_in6 addr6;
+ struct sockaddr_in addr4;
+ struct sockaddr addr;
+ char buf[2048]; /* Scratch space. Used to read data into. */
+ } t;
+} conn;
+
+typedef struct client_ctx {
+ unsigned int state;
+ server_ctx *sx; /* Backlink to owning server context. */
+ s5_ctx parser; /* The SOCKS protocol parser. */
+ conn incoming; /* Connection with the SOCKS client. */
+ conn outgoing; /* Connection with upstream. */
+} client_ctx;
+
+/* server.c */
+int server_run(const server_config *cf, uv_loop_t *loop);
+int can_auth_none(const server_ctx *sx, const client_ctx *cx);
+int can_auth_passwd(const server_ctx *sx, const client_ctx *cx);
+int can_access(const server_ctx *sx,
+ const client_ctx *cx,
+ const struct sockaddr *addr);
+
+/* client.c */
+void client_finish_init(server_ctx *sx, client_ctx *cx);
+
+/* util.c */
+#if defined(__GNUC__)
+# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b)))
+#else
+# define ATTRIBUTE_FORMAT_PRINTF(a, b)
+#endif
+void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void *xmalloc(size_t size);
+
+/* main.c */
+const char *_getprogname(void);
+
+/* getopt.c */
+#if !HAVE_UNISTD_H
+extern char *optarg;
+int getopt(int argc, char **argv, const char *options);
+#endif
+
+/* ASSERT() is for debug checks, CHECK() for run-time sanity checks.
+ * DEBUG_CHECKS is for expensive debug checks that we only want to
+ * enable in debug builds but still want type-checked by the compiler
+ * in release builds.
+ */
+#if defined(NDEBUG)
+# define ASSERT(exp)
+# define CHECK(exp) do { if (!(exp)) abort(); } while (0)
+# define DEBUG_CHECKS (0)
+#else
+# define ASSERT(exp) assert(exp)
+# define CHECK(exp) assert(exp)
+# define DEBUG_CHECKS (1)
+#endif
+
+#define UNREACHABLE() CHECK(!"Unreachable code reached.")
+
+/* This macro looks complicated but it's not: it calculates the address
+ * of the embedding struct through the address of the embedded struct.
+ * In other words, if struct A embeds struct B, then we can obtain
+ * the address of A by taking the address of B and subtracting the
+ * field offset of B in A.
+ */
+#define CONTAINER_OF(ptr, type, field) \
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+
+#endif /* DEFS_H_ */
diff --git a/3rdparty/libuv/samples/socks5-proxy/getopt.c b/3rdparty/libuv/samples/socks5-proxy/getopt.c
new file mode 100644
index 00000000000..8481b2264f2
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/getopt.c
@@ -0,0 +1,131 @@
+/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern const char *_getprogname(void);
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == NULL)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(),
+ optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/main.c b/3rdparty/libuv/samples/socks5-proxy/main.c
new file mode 100644
index 00000000000..04020cbd3ad
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/main.c
@@ -0,0 +1,99 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#define DEFAULT_BIND_HOST "127.0.0.1"
+#define DEFAULT_BIND_PORT 1080
+#define DEFAULT_IDLE_TIMEOUT (60 * 1000)
+
+static void parse_opts(server_config *cf, int argc, char **argv);
+static void usage(void);
+
+static const char *progname = __FILE__; /* Reset in main(). */
+
+int main(int argc, char **argv) {
+ server_config config;
+ int err;
+
+ progname = argv[0];
+ memset(&config, 0, sizeof(config));
+ config.bind_host = DEFAULT_BIND_HOST;
+ config.bind_port = DEFAULT_BIND_PORT;
+ config.idle_timeout = DEFAULT_IDLE_TIMEOUT;
+ parse_opts(&config, argc, argv);
+
+ err = server_run(&config, uv_default_loop());
+ if (err) {
+ exit(1);
+ }
+
+ return 0;
+}
+
+const char *_getprogname(void) {
+ return progname;
+}
+
+static void parse_opts(server_config *cf, int argc, char **argv) {
+ int opt;
+
+ while (-1 != (opt = getopt(argc, argv, "H:hp:"))) {
+ switch (opt) {
+ case 'H':
+ cf->bind_host = optarg;
+ break;
+
+ case 'p':
+ if (1 != sscanf(optarg, "%hu", &cf->bind_port)) {
+ pr_err("bad port number: %s", optarg);
+ usage();
+ }
+ break;
+
+ default:
+ usage();
+ }
+ }
+}
+
+static void usage(void) {
+ printf("Usage:\n"
+ "\n"
+ " %s [-b <address> [-h] [-p <port>]\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " -b <hostname|address> Bind to this address or hostname.\n"
+ " Default: \"127.0.0.1\"\n"
+ " -h Show this help message.\n"
+ " -p <port> Bind to this port number. Default: 1080\n"
+ "",
+ progname);
+ exit(1);
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/s5.c b/3rdparty/libuv/samples/socks5-proxy/s5.c
new file mode 100644
index 00000000000..4f08e345247
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/s5.c
@@ -0,0 +1,271 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "s5.h"
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h> /* abort() */
+#include <string.h> /* memset() */
+
+enum {
+ s5_version,
+ s5_nmethods,
+ s5_methods,
+ s5_auth_pw_version,
+ s5_auth_pw_userlen,
+ s5_auth_pw_username,
+ s5_auth_pw_passlen,
+ s5_auth_pw_password,
+ s5_req_version,
+ s5_req_cmd,
+ s5_req_reserved,
+ s5_req_atyp,
+ s5_req_atyp_host,
+ s5_req_daddr,
+ s5_req_dport0,
+ s5_req_dport1,
+ s5_dead
+};
+
+void s5_init(s5_ctx *cx) {
+ memset(cx, 0, sizeof(*cx));
+ cx->state = s5_version;
+}
+
+s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) {
+ s5_err err;
+ uint8_t *p;
+ uint8_t c;
+ size_t i;
+ size_t n;
+
+ p = *data;
+ n = *size;
+ i = 0;
+
+ while (i < n) {
+ c = p[i];
+ i += 1;
+ switch (cx->state) {
+ case s5_version:
+ if (c != 5) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_nmethods;
+ break;
+
+ case s5_nmethods:
+ cx->arg0 = 0;
+ cx->arg1 = c; /* Number of bytes to read. */
+ cx->state = s5_methods;
+ break;
+
+ case s5_methods:
+ if (cx->arg0 < cx->arg1) {
+ switch (c) {
+ case 0:
+ cx->methods |= S5_AUTH_NONE;
+ break;
+ case 1:
+ cx->methods |= S5_AUTH_GSSAPI;
+ break;
+ case 2:
+ cx->methods |= S5_AUTH_PASSWD;
+ break;
+ /* Ignore everything we don't understand. */
+ }
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->arg1) {
+ err = s5_auth_select;
+ goto out;
+ }
+ break;
+
+ case s5_auth_pw_version:
+ if (c != 1) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_auth_pw_userlen;
+ break;
+
+ case s5_auth_pw_userlen:
+ cx->arg0 = 0;
+ cx->userlen = c;
+ cx->state = s5_auth_pw_username;
+ break;
+
+ case s5_auth_pw_username:
+ if (cx->arg0 < cx->userlen) {
+ cx->username[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->userlen) {
+ cx->username[cx->userlen] = '\0';
+ cx->state = s5_auth_pw_passlen;
+ }
+ break;
+
+ case s5_auth_pw_passlen:
+ cx->arg0 = 0;
+ cx->passlen = c;
+ cx->state = s5_auth_pw_password;
+ break;
+
+ case s5_auth_pw_password:
+ if (cx->arg0 < cx->passlen) {
+ cx->password[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->passlen) {
+ cx->password[cx->passlen] = '\0';
+ cx->state = s5_req_version;
+ err = s5_auth_verify;
+ goto out;
+ }
+ break;
+
+ case s5_req_version:
+ if (c != 5) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_req_cmd;
+ break;
+
+ case s5_req_cmd:
+ switch (c) {
+ case 1: /* TCP connect */
+ cx->cmd = s5_cmd_tcp_connect;
+ break;
+ case 3: /* UDP associate */
+ cx->cmd = s5_cmd_udp_assoc;
+ break;
+ default:
+ err = s5_bad_cmd;
+ goto out;
+ }
+ cx->state = s5_req_reserved;
+ break;
+
+ case s5_req_reserved:
+ cx->state = s5_req_atyp;
+ break;
+
+ case s5_req_atyp:
+ cx->arg0 = 0;
+ switch (c) {
+ case 1: /* IPv4, four octets. */
+ cx->state = s5_req_daddr;
+ cx->atyp = s5_atyp_ipv4;
+ cx->arg1 = 4;
+ break;
+ case 3: /* Hostname. First byte is length. */
+ cx->state = s5_req_atyp_host;
+ cx->atyp = s5_atyp_host;
+ cx->arg1 = 0;
+ break;
+ case 4: /* IPv6, sixteen octets. */
+ cx->state = s5_req_daddr;
+ cx->atyp = s5_atyp_ipv6;
+ cx->arg1 = 16;
+ break;
+ default:
+ err = s5_bad_atyp;
+ goto out;
+ }
+ break;
+
+ case s5_req_atyp_host:
+ cx->arg1 = c;
+ cx->state = s5_req_daddr;
+ break;
+
+ case s5_req_daddr:
+ if (cx->arg0 < cx->arg1) {
+ cx->daddr[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->arg1) {
+ cx->daddr[cx->arg1] = '\0';
+ cx->state = s5_req_dport0;
+ }
+ break;
+
+ case s5_req_dport0:
+ cx->dport = c << 8;
+ cx->state = s5_req_dport1;
+ break;
+
+ case s5_req_dport1:
+ cx->dport |= c;
+ cx->state = s5_dead;
+ err = s5_exec_cmd;
+ goto out;
+
+ case s5_dead:
+ break;
+
+ default:
+ abort();
+ }
+ }
+ err = s5_ok;
+
+out:
+ *data = p + i;
+ *size = n - i;
+ return err;
+}
+
+unsigned int s5_auth_methods(const s5_ctx *cx) {
+ return cx->methods;
+}
+
+int s5_select_auth(s5_ctx *cx, s5_auth_method method) {
+ int err;
+
+ err = 0;
+ switch (method) {
+ case S5_AUTH_NONE:
+ cx->state = s5_req_version;
+ break;
+ case S5_AUTH_PASSWD:
+ cx->state = s5_auth_pw_version;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+const char *s5_strerror(s5_err err) {
+#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg;
+ switch (err) {
+ S5_ERR_MAP(S5_ERR_GEN)
+ default: ; /* Silence s5_max_errors -Wswitch warning. */
+ }
+#undef S5_ERR_GEN
+ return "Unknown error.";
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/s5.h b/3rdparty/libuv/samples/socks5-proxy/s5.h
new file mode 100644
index 00000000000..715f322287d
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/s5.h
@@ -0,0 +1,94 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef S5_H_
+#define S5_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define S5_ERR_MAP(V) \
+ V(-1, bad_version, "Bad protocol version.") \
+ V(-2, bad_cmd, "Bad protocol command.") \
+ V(-3, bad_atyp, "Bad address type.") \
+ V(0, ok, "No error.") \
+ V(1, auth_select, "Select authentication method.") \
+ V(2, auth_verify, "Verify authentication.") \
+ V(3, exec_cmd, "Execute command.") \
+
+typedef enum {
+#define S5_ERR_GEN(code, name, _) s5_ ## name = code,
+ S5_ERR_MAP(S5_ERR_GEN)
+#undef S5_ERR_GEN
+ s5_max_errors
+} s5_err;
+
+typedef enum {
+ S5_AUTH_NONE = 1 << 0,
+ S5_AUTH_GSSAPI = 1 << 1,
+ S5_AUTH_PASSWD = 1 << 2
+} s5_auth_method;
+
+typedef enum {
+ s5_auth_allow,
+ s5_auth_deny
+} s5_auth_result;
+
+typedef enum {
+ s5_atyp_ipv4,
+ s5_atyp_ipv6,
+ s5_atyp_host
+} s5_atyp;
+
+typedef enum {
+ s5_cmd_tcp_connect,
+ s5_cmd_tcp_bind,
+ s5_cmd_udp_assoc
+} s5_cmd;
+
+typedef struct {
+ uint32_t arg0; /* Scratch space for the state machine. */
+ uint32_t arg1; /* Scratch space for the state machine. */
+ uint8_t state;
+ uint8_t methods;
+ uint8_t cmd;
+ uint8_t atyp;
+ uint8_t userlen;
+ uint8_t passlen;
+ uint16_t dport;
+ uint8_t username[257];
+ uint8_t password[257];
+ uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */
+} s5_ctx;
+
+void s5_init(s5_ctx *ctx);
+
+s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size);
+
+/* Only call after s5_parse() has returned s5_want_auth_method. */
+unsigned int s5_auth_methods(const s5_ctx *cx);
+
+/* Call after s5_parse() has returned s5_want_auth_method. */
+int s5_select_auth(s5_ctx *cx, s5_auth_method method);
+
+const char *s5_strerror(s5_err err);
+
+#endif /* S5_H_ */
diff --git a/3rdparty/libuv/samples/socks5-proxy/server.c b/3rdparty/libuv/samples/socks5-proxy/server.c
new file mode 100644
index 00000000000..3f1ba42c9e1
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/server.c
@@ -0,0 +1,241 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <netinet/in.h> /* INET6_ADDRSTRLEN */
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 63
+#endif
+
+typedef struct {
+ uv_getaddrinfo_t getaddrinfo_req;
+ server_config config;
+ server_ctx *servers;
+ uv_loop_t *loop;
+} server_state;
+
+static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai);
+static void on_connection(uv_stream_t *server, int status);
+
+int server_run(const server_config *cf, uv_loop_t *loop) {
+ struct addrinfo hints;
+ server_state state;
+ int err;
+
+ memset(&state, 0, sizeof(state));
+ state.servers = NULL;
+ state.config = *cf;
+ state.loop = loop;
+
+ /* Resolve the address of the interface that we should bind to.
+ * The getaddrinfo callback starts the server and everything else.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ err = uv_getaddrinfo(loop,
+ &state.getaddrinfo_req,
+ do_bind,
+ cf->bind_host,
+ NULL,
+ &hints);
+ if (err != 0) {
+ pr_err("getaddrinfo: %s", uv_strerror(err));
+ return err;
+ }
+
+ /* Start the event loop. Control continues in do_bind(). */
+ if (uv_run(loop, UV_RUN_DEFAULT)) {
+ abort();
+ }
+
+ /* Please Valgrind. */
+ uv_loop_delete(loop);
+ free(state.servers);
+ return 0;
+}
+
+/* Bind a server to each address that getaddrinfo() reported. */
+static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
+ char addrbuf[INET6_ADDRSTRLEN + 1];
+ unsigned int ipv4_naddrs;
+ unsigned int ipv6_naddrs;
+ server_state *state;
+ server_config *cf;
+ struct addrinfo *ai;
+ const void *addrv;
+ const char *what;
+ uv_loop_t *loop;
+ server_ctx *sx;
+ unsigned int n;
+ int err;
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } s;
+
+ state = CONTAINER_OF(req, server_state, getaddrinfo_req);
+ loop = state->loop;
+ cf = &state->config;
+
+ if (status < 0) {
+ pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status));
+ uv_freeaddrinfo(addrs);
+ return;
+ }
+
+ ipv4_naddrs = 0;
+ ipv6_naddrs = 0;
+ for (ai = addrs; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family == AF_INET) {
+ ipv4_naddrs += 1;
+ } else if (ai->ai_family == AF_INET6) {
+ ipv6_naddrs += 1;
+ }
+ }
+
+ if (ipv4_naddrs == 0 && ipv6_naddrs == 0) {
+ pr_err("%s has no IPv4/6 addresses", cf->bind_host);
+ uv_freeaddrinfo(addrs);
+ return;
+ }
+
+ state->servers =
+ xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0]));
+
+ n = 0;
+ for (ai = addrs; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
+ continue;
+ }
+
+ if (ai->ai_family == AF_INET) {
+ s.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
+ s.addr4.sin_port = htons(cf->bind_port);
+ addrv = &s.addr4.sin_addr;
+ } else if (ai->ai_family == AF_INET6) {
+ s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
+ s.addr6.sin6_port = htons(cf->bind_port);
+ addrv = &s.addr6.sin6_addr;
+ } else {
+ UNREACHABLE();
+ }
+
+ if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) {
+ UNREACHABLE();
+ }
+
+ sx = state->servers + n;
+ sx->loop = loop;
+ sx->idle_timeout = state->config.idle_timeout;
+ CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
+
+ what = "uv_tcp_bind";
+ err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0);
+ if (err == 0) {
+ what = "uv_listen";
+ err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);
+ }
+
+ if (err != 0) {
+ pr_err("%s(\"%s:%hu\"): %s",
+ what,
+ addrbuf,
+ cf->bind_port,
+ uv_strerror(err));
+ while (n > 0) {
+ n -= 1;
+ uv_close((uv_handle_t *) (state->servers + n), NULL);
+ }
+ break;
+ }
+
+ pr_info("listening on %s:%hu", addrbuf, cf->bind_port);
+ n += 1;
+ }
+
+ uv_freeaddrinfo(addrs);
+}
+
+static void on_connection(uv_stream_t *server, int status) {
+ server_ctx *sx;
+ client_ctx *cx;
+
+ CHECK(status == 0);
+ sx = CONTAINER_OF(server, server_ctx, tcp_handle);
+ cx = xmalloc(sizeof(*cx));
+ CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp));
+ CHECK(0 == uv_accept(server, &cx->incoming.handle.stream));
+ client_finish_init(sx, cx);
+}
+
+int can_auth_none(const server_ctx *sx, const client_ctx *cx) {
+ return 1;
+}
+
+int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) {
+ return 0;
+}
+
+int can_access(const server_ctx *sx,
+ const client_ctx *cx,
+ const struct sockaddr *addr) {
+ const struct sockaddr_in6 *addr6;
+ const struct sockaddr_in *addr4;
+ const uint32_t *p;
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+
+ /* TODO(bnoordhuis) Implement proper access checks. For now, just reject
+ * traffic to localhost.
+ */
+ if (addr->sa_family == AF_INET) {
+ addr4 = (const struct sockaddr_in *) addr;
+ d = ntohl(addr4->sin_addr.s_addr);
+ return (d >> 24) != 0x7F;
+ }
+
+ if (addr->sa_family == AF_INET6) {
+ addr6 = (const struct sockaddr_in6 *) addr;
+ p = (const uint32_t *) &addr6->sin6_addr.s6_addr;
+ a = ntohl(p[0]);
+ b = ntohl(p[1]);
+ c = ntohl(p[2]);
+ d = ntohl(p[3]);
+ if (a == 0 && b == 0 && c == 0 && d == 1) {
+ return 0; /* "::1" style address. */
+ }
+ if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) {
+ return 0; /* "::ffff:127.x.x.x" style address. */
+ }
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/util.c b/3rdparty/libuv/samples/socks5-proxy/util.c
new file mode 100644
index 00000000000..af34f055936
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/util.c
@@ -0,0 +1,72 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void pr_do(FILE *stream,
+ const char *label,
+ const char *fmt,
+ va_list ap);
+
+void *xmalloc(size_t size) {
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ pr_err("out of memory, need %lu bytes", (unsigned long) size);
+ exit(1);
+ }
+
+ return ptr;
+}
+
+void pr_info(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stdout, "info", fmt, ap);
+ va_end(ap);
+}
+
+void pr_warn(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stderr, "warn", fmt, ap);
+ va_end(ap);
+}
+
+void pr_err(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stderr, "error", fmt, ap);
+ va_end(ap);
+}
+
+static void pr_do(FILE *stream,
+ const char *label,
+ const char *fmt,
+ va_list ap) {
+ char fmtbuf[1024];
+ vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
+ fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf);
+}
diff --git a/3rdparty/libuv/src/fs-poll.c b/3rdparty/libuv/src/fs-poll.c
new file mode 100644
index 00000000000..44d47b88ed2
--- /dev/null
+++ b/3rdparty/libuv/src/fs-poll.c
@@ -0,0 +1,255 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct poll_ctx {
+ uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
+ int busy_polling;
+ unsigned int interval;
+ uint64_t start_time;
+ uv_loop_t* loop;
+ uv_fs_poll_cb poll_cb;
+ uv_timer_t timer_handle;
+ uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
+ uv_stat_t statbuf;
+ char path[1]; /* variable length */
+};
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
+static void poll_cb(uv_fs_t* req);
+static void timer_cb(uv_timer_t* timer);
+static void timer_close_cb(uv_handle_t* handle);
+
+static uv_stat_t zero_statbuf;
+
+
+int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
+ return 0;
+}
+
+
+int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb cb,
+ const char* path,
+ unsigned int interval) {
+ struct poll_ctx* ctx;
+ uv_loop_t* loop;
+ size_t len;
+ int err;
+
+ if (uv__is_active(handle))
+ return 0;
+
+ loop = handle->loop;
+ len = strlen(path);
+ ctx = uv__calloc(1, sizeof(*ctx) + len);
+
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->loop = loop;
+ ctx->poll_cb = cb;
+ ctx->interval = interval ? interval : 1;
+ ctx->start_time = uv_now(loop);
+ ctx->parent_handle = handle;
+ memcpy(ctx->path, path, len + 1);
+
+ err = uv_timer_init(loop, &ctx->timer_handle);
+ if (err < 0)
+ goto error;
+
+ ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&ctx->timer_handle);
+
+ err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
+ if (err < 0)
+ goto error;
+
+ handle->poll_ctx = ctx;
+ uv__handle_start(handle);
+
+ return 0;
+
+error:
+ uv__free(ctx);
+ return err;
+}
+
+
+int uv_fs_poll_stop(uv_fs_poll_t* handle) {
+ struct poll_ctx* ctx;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+ assert(ctx->parent_handle != NULL);
+ ctx->parent_handle = NULL;
+ handle->poll_ctx = NULL;
+
+ /* Close the timer if it's active. If it's inactive, there's a stat request
+ * in progress and poll_cb will take care of the cleanup.
+ */
+ if (uv__is_active(&ctx->timer_handle))
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
+ struct poll_ctx* ctx;
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+
+ required_len = strlen(ctx->path);
+ if (required_len > *size) {
+ *size = required_len;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, ctx->path, required_len);
+ *size = required_len;
+
+ return 0;
+}
+
+
+void uv__fs_poll_close(uv_fs_poll_t* handle) {
+ uv_fs_poll_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* timer) {
+ struct poll_ctx* ctx;
+
+ ctx = container_of(timer, struct poll_ctx, timer_handle);
+ assert(ctx->parent_handle != NULL);
+ assert(ctx->parent_handle->poll_ctx == ctx);
+ ctx->start_time = uv_now(ctx->loop);
+
+ if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
+ abort();
+}
+
+
+static void poll_cb(uv_fs_t* req) {
+ uv_stat_t* statbuf;
+ struct poll_ctx* ctx;
+ uint64_t interval;
+
+ ctx = container_of(req, struct poll_ctx, fs_req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ uv_fs_req_cleanup(req);
+ return;
+ }
+
+ if (req->result != 0) {
+ if (ctx->busy_polling != req->result) {
+ ctx->poll_cb(ctx->parent_handle,
+ req->result,
+ &ctx->statbuf,
+ &zero_statbuf);
+ ctx->busy_polling = req->result;
+ }
+ goto out;
+ }
+
+ statbuf = &req->statbuf;
+
+ if (ctx->busy_polling != 0)
+ if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
+ ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
+
+ ctx->statbuf = *statbuf;
+ ctx->busy_polling = 1;
+
+out:
+ uv_fs_req_cleanup(req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ return;
+ }
+
+ /* Reschedule timer, subtract the delay from doing the stat(). */
+ interval = ctx->interval;
+ interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
+
+ if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
+ abort();
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ uv__free(container_of(handle, struct poll_ctx, timer_handle));
+}
+
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
+ return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
+ && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
+ && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
+ && a->st_ctim.tv_sec == b->st_ctim.tv_sec
+ && a->st_mtim.tv_sec == b->st_mtim.tv_sec
+ && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
+ && a->st_size == b->st_size
+ && a->st_mode == b->st_mode
+ && a->st_uid == b->st_uid
+ && a->st_gid == b->st_gid
+ && a->st_ino == b->st_ino
+ && a->st_dev == b->st_dev
+ && a->st_flags == b->st_flags
+ && a->st_gen == b->st_gen;
+}
+
+
+#if defined(_WIN32)
+
+#include "win/internal.h"
+#include "win/handle-inl.h"
+
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/src/heap-inl.h b/3rdparty/libuv/src/heap-inl.h
new file mode 100644
index 00000000000..1e2ed60e094
--- /dev/null
+++ b/3rdparty/libuv/src/heap-inl.h
@@ -0,0 +1,245 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SRC_HEAP_H_
+#define UV_SRC_HEAP_H_
+
+#include <stddef.h> /* NULL */
+
+#if defined(__GNUC__)
+# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
+#else
+# define HEAP_EXPORT(declaration) static declaration
+#endif
+
+struct heap_node {
+ struct heap_node* left;
+ struct heap_node* right;
+ struct heap_node* parent;
+};
+
+/* A binary min heap. The usual properties hold: the root is the lowest
+ * element in the set, the height of the tree is at most log2(nodes) and
+ * it's always a complete binary tree.
+ *
+ * The heap function try hard to detect corrupted tree nodes at the cost
+ * of a minor reduction in performance. Compile with -DNDEBUG to disable.
+ */
+struct heap {
+ struct heap_node* min;
+ unsigned int nelts;
+};
+
+/* Return non-zero if a < b. */
+typedef int (*heap_compare_fn)(const struct heap_node* a,
+ const struct heap_node* b);
+
+/* Public functions. */
+HEAP_EXPORT(void heap_init(struct heap* heap));
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
+
+/* Implementation follows. */
+
+HEAP_EXPORT(void heap_init(struct heap* heap)) {
+ heap->min = NULL;
+ heap->nelts = 0;
+}
+
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
+ return heap->min;
+}
+
+/* Swap parent with child. Child moves closer to the root, parent moves away. */
+static void heap_node_swap(struct heap* heap,
+ struct heap_node* parent,
+ struct heap_node* child) {
+ struct heap_node* sibling;
+ struct heap_node t;
+
+ t = *parent;
+ *parent = *child;
+ *child = t;
+
+ parent->parent = child;
+ if (child->left == child) {
+ child->left = parent;
+ sibling = child->right;
+ } else {
+ child->right = parent;
+ sibling = child->left;
+ }
+ if (sibling != NULL)
+ sibling->parent = child;
+
+ if (parent->left != NULL)
+ parent->left->parent = parent;
+ if (parent->right != NULL)
+ parent->right->parent = parent;
+
+ if (child->parent == NULL)
+ heap->min = child;
+ else if (child->parent->left == parent)
+ child->parent->left = child;
+ else
+ child->parent->right = child;
+}
+
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than)) {
+ struct heap_node** parent;
+ struct heap_node** child;
+ unsigned int path;
+ unsigned int n;
+ unsigned int k;
+
+ newnode->left = NULL;
+ newnode->right = NULL;
+ newnode->parent = NULL;
+
+ /* Calculate the path from the root to the insertion point. This is a min
+ * heap so we always insert at the left-most free node of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ parent = child = &heap->min;
+ while (k > 0) {
+ parent = child;
+ if (path & 1)
+ child = &(*child)->right;
+ else
+ child = &(*child)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ /* Insert the new node. */
+ newnode->parent = *parent;
+ *child = newnode;
+ heap->nelts += 1;
+
+ /* Walk up the tree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true.
+ */
+ while (newnode->parent != NULL && less_than(newnode, newnode->parent))
+ heap_node_swap(heap, newnode->parent, newnode);
+}
+
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than)) {
+ struct heap_node* smallest;
+ struct heap_node** max;
+ struct heap_node* child;
+ unsigned int path;
+ unsigned int k;
+ unsigned int n;
+
+ if (heap->nelts == 0)
+ return;
+
+ /* Calculate the path from the min (the root) to the max, the left-most node
+ * of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ max = &heap->min;
+ while (k > 0) {
+ if (path & 1)
+ max = &(*max)->right;
+ else
+ max = &(*max)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ heap->nelts -= 1;
+
+ /* Unlink the max node. */
+ child = *max;
+ *max = NULL;
+
+ if (child == node) {
+ /* We're removing either the max or the last node in the tree. */
+ if (child == heap->min) {
+ heap->min = NULL;
+ }
+ return;
+ }
+
+ /* Replace the to be deleted node with the max node. */
+ child->left = node->left;
+ child->right = node->right;
+ child->parent = node->parent;
+
+ if (child->left != NULL) {
+ child->left->parent = child;
+ }
+
+ if (child->right != NULL) {
+ child->right->parent = child;
+ }
+
+ if (node->parent == NULL) {
+ heap->min = child;
+ } else if (node->parent->left == node) {
+ node->parent->left = child;
+ } else {
+ node->parent->right = child;
+ }
+
+ /* Walk down the subtree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true. If the parent is bigger,
+ * swap it with the smallest child.
+ */
+ for (;;) {
+ smallest = child;
+ if (child->left != NULL && less_than(child->left, smallest))
+ smallest = child->left;
+ if (child->right != NULL && less_than(child->right, smallest))
+ smallest = child->right;
+ if (smallest == child)
+ break;
+ heap_node_swap(heap, child, smallest);
+ }
+
+ /* Walk up the subtree and check that each parent is less than the node
+ * this is required, because `max` node is not guaranteed to be the
+ * actual maximum in tree
+ */
+ while (child->parent != NULL && less_than(child, child->parent))
+ heap_node_swap(heap, child->parent, child);
+}
+
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
+ heap_remove(heap, heap->min, less_than);
+}
+
+#undef HEAP_EXPORT
+
+#endif /* UV_SRC_HEAP_H_ */
diff --git a/3rdparty/libuv/src/inet.c b/3rdparty/libuv/src/inet.c
new file mode 100644
index 00000000000..da63a688c4e
--- /dev/null
+++ b/3rdparty/libuv/src/inet.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "uv.h"
+#include "uv-common.h"
+
+#define UV__INET_ADDRSTRLEN 16
+#define UV__INET6_ADDRSTRLEN 46
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+
+int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[UV__INET_ADDRSTRLEN];
+ int l;
+
+ l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || (size_t) l >= size) {
+ return UV_ENOSPC;
+ }
+ strncpy(dst, tmp, size);
+ dst[size - 1] = '\0';
+ return 0;
+}
+
+
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[UV__INET6_ADDRSTRLEN], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < (int) sizeof(struct in6_addr); i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
+ if (err)
+ return err;
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ return UV_ENOSPC;
+ }
+ strcpy(dst, tmp);
+ return 0;
+}
+
+
+int uv_inet_pton(int af, const char* src, void* dst) {
+ if (src == NULL || dst == NULL)
+ return UV_EINVAL;
+
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6: {
+ int len;
+ char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
+ s = (char*) src;
+ p = strchr(src, '%');
+ if (p != NULL) {
+ s = tmp;
+ len = p - src;
+ if (len > UV__INET6_ADDRSTRLEN-1)
+ return UV_EINVAL;
+ memcpy(s, src, len);
+ s[len] = '\0';
+ }
+ return inet_pton6(s, dst);
+ }
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[sizeof(struct in_addr)], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int nw = *tp * 10 + (pch - digits);
+
+ if (saw_digit && *tp == 0)
+ return UV_EINVAL;
+ if (nw > 255)
+ return UV_EINVAL;
+ *tp = nw;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return UV_EINVAL;
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return UV_EINVAL;
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return UV_EINVAL;
+ }
+ if (octets < 4)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof(struct in_addr));
+ return 0;
+}
+
+
+static int inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', sizeof tmp);
+ endp = tp + sizeof tmp;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return UV_EINVAL;
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return UV_EINVAL;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return UV_EINVAL;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return UV_EINVAL;
+ }
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
+ int err = inet_pton4(curtok, tp);
+ if (err == 0) {
+ tp += sizeof(struct in_addr);
+ seen_xdigits = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ }
+ return UV_EINVAL;
+ }
+ if (seen_xdigits) {
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return UV_EINVAL;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof tmp);
+ return 0;
+}
diff --git a/3rdparty/libuv/src/queue.h b/3rdparty/libuv/src/queue.h
new file mode 100644
index 00000000000..ff3540a0a51
--- /dev/null
+++ b/3rdparty/libuv/src/queue.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+#include <stddef.h>
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - offsetof(type, field)))
+
+/* Important note: mutating the list while QUEUE_FOREACH is
+ * iterating over its elements results in undefined behavior.
+ */
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_MOVE(h, n) \
+ do { \
+ if (QUEUE_EMPTY(h)) \
+ QUEUE_INIT(n); \
+ else { \
+ QUEUE* q = QUEUE_HEAD(h); \
+ QUEUE_SPLIT(h, q, n); \
+ } \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/3rdparty/libuv/src/threadpool.c b/3rdparty/libuv/src/threadpool.c
new file mode 100644
index 00000000000..2c5152b4200
--- /dev/null
+++ b/3rdparty/libuv/src/threadpool.c
@@ -0,0 +1,303 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv-common.h"
+
+#if !defined(_WIN32)
+# include "unix/internal.h"
+#else
+# include "win/req-inl.h"
+/* TODO(saghul): unify internal req functions */
+static void uv__req_init(uv_loop_t* loop,
+ uv_req_t* req,
+ uv_req_type type) {
+ uv_req_init(loop, req);
+ req->type = type;
+ uv__req_register(loop, req);
+}
+# define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+#endif
+
+#include <stdlib.h>
+
+#define MAX_THREADPOOL_SIZE 128
+
+static uv_once_t once = UV_ONCE_INIT;
+static uv_cond_t cond;
+static uv_mutex_t mutex;
+static unsigned int idle_threads;
+static unsigned int nthreads;
+static uv_thread_t* threads;
+static uv_thread_t default_threads[4];
+static QUEUE exit_message;
+static QUEUE wq;
+static volatile int initialized;
+
+
+static void uv__cancelled(struct uv__work* w) {
+ abort();
+}
+
+
+/* To avoid deadlock with uv_cancel() it's crucial that the worker
+ * never holds the global mutex and the loop-local mutex at the same time.
+ */
+static void worker(void* arg) {
+ struct uv__work* w;
+ QUEUE* q;
+
+ (void) arg;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+
+ while (QUEUE_EMPTY(&wq)) {
+ idle_threads += 1;
+ uv_cond_wait(&cond, &mutex);
+ idle_threads -= 1;
+ }
+
+ q = QUEUE_HEAD(&wq);
+
+ if (q == &exit_message)
+ uv_cond_signal(&cond);
+ else {
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
+ executing. */
+ }
+
+ uv_mutex_unlock(&mutex);
+
+ if (q == &exit_message)
+ break;
+
+ w = QUEUE_DATA(q, struct uv__work, wq);
+ w->work(w);
+
+ uv_mutex_lock(&w->loop->wq_mutex);
+ w->work = NULL; /* Signal uv_cancel() that the work req is done
+ executing. */
+ QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
+ uv_async_send(&w->loop->wq_async);
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ }
+}
+
+
+static void post(QUEUE* q) {
+ uv_mutex_lock(&mutex);
+ QUEUE_INSERT_TAIL(&wq, q);
+ if (idle_threads > 0)
+ uv_cond_signal(&cond);
+ uv_mutex_unlock(&mutex);
+}
+
+
+#ifndef _WIN32
+UV_DESTRUCTOR(static void cleanup(void)) {
+ unsigned int i;
+
+ if (initialized == 0)
+ return;
+
+ post(&exit_message);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_join(threads + i))
+ abort();
+
+ if (threads != default_threads)
+ uv__free(threads);
+
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&cond);
+
+ threads = NULL;
+ nthreads = 0;
+ initialized = 0;
+}
+#endif
+
+
+static void init_once(void) {
+ unsigned int i;
+ const char* val;
+
+ nthreads = ARRAY_SIZE(default_threads);
+ val = getenv("UV_THREADPOOL_SIZE");
+ if (val != NULL)
+ nthreads = atoi(val);
+ if (nthreads == 0)
+ nthreads = 1;
+ if (nthreads > MAX_THREADPOOL_SIZE)
+ nthreads = MAX_THREADPOOL_SIZE;
+
+ threads = default_threads;
+ if (nthreads > ARRAY_SIZE(default_threads)) {
+ threads = uv__malloc(nthreads * sizeof(threads[0]));
+ if (threads == NULL) {
+ nthreads = ARRAY_SIZE(default_threads);
+ threads = default_threads;
+ }
+ }
+
+ if (uv_cond_init(&cond))
+ abort();
+
+ if (uv_mutex_init(&mutex))
+ abort();
+
+ QUEUE_INIT(&wq);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_create(threads + i, worker, NULL))
+ abort();
+
+ initialized = 1;
+}
+
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work* w,
+ void (*work)(struct uv__work* w),
+ void (*done)(struct uv__work* w, int status)) {
+ uv_once(&once, init_once);
+ w->loop = loop;
+ w->work = work;
+ w->done = done;
+ post(&w->wq);
+}
+
+
+static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
+ int cancelled;
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_lock(&w->loop->wq_mutex);
+
+ cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
+ if (cancelled)
+ QUEUE_REMOVE(&w->wq);
+
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ uv_mutex_unlock(&mutex);
+
+ if (!cancelled)
+ return UV_EBUSY;
+
+ w->work = uv__cancelled;
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
+ uv_async_send(&loop->wq_async);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ return 0;
+}
+
+
+void uv__work_done(uv_async_t* handle) {
+ struct uv__work* w;
+ uv_loop_t* loop;
+ QUEUE* q;
+ QUEUE wq;
+ int err;
+
+ loop = container_of(handle, uv_loop_t, wq_async);
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_MOVE(&loop->wq, &wq);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ while (!QUEUE_EMPTY(&wq)) {
+ q = QUEUE_HEAD(&wq);
+ QUEUE_REMOVE(q);
+
+ w = container_of(q, struct uv__work, wq);
+ err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
+ w->done(w, err);
+ }
+}
+
+
+static void uv__queue_work(struct uv__work* w) {
+ uv_work_t* req = container_of(w, uv_work_t, work_req);
+
+ req->work_cb(req);
+}
+
+
+static void uv__queue_done(struct uv__work* w, int err) {
+ uv_work_t* req;
+
+ req = container_of(w, uv_work_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (req->after_work_cb == NULL)
+ return;
+
+ req->after_work_cb(req, err);
+}
+
+
+int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb) {
+ if (work_cb == NULL)
+ return UV_EINVAL;
+
+ uv__req_init(loop, req, UV_WORK);
+ req->loop = loop;
+ req->work_cb = work_cb;
+ req->after_work_cb = after_work_cb;
+ uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
+ return 0;
+}
+
+
+int uv_cancel(uv_req_t* req) {
+ struct uv__work* wreq;
+ uv_loop_t* loop;
+
+ switch (req->type) {
+ case UV_FS:
+ loop = ((uv_fs_t*) req)->loop;
+ wreq = &((uv_fs_t*) req)->work_req;
+ break;
+ case UV_GETADDRINFO:
+ loop = ((uv_getaddrinfo_t*) req)->loop;
+ wreq = &((uv_getaddrinfo_t*) req)->work_req;
+ break;
+ case UV_GETNAMEINFO:
+ loop = ((uv_getnameinfo_t*) req)->loop;
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
+ break;
+ case UV_WORK:
+ loop = ((uv_work_t*) req)->loop;
+ wreq = &((uv_work_t*) req)->work_req;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ return uv__work_cancel(loop, req, wreq);
+}
diff --git a/3rdparty/libuv/src/unix/aix.c b/3rdparty/libuv/src/unix/aix.c
new file mode 100644
index 00000000000..c90b7e5cb9b
--- /dev/null
+++ b/3rdparty/libuv/src/unix/aix.c
@@ -0,0 +1,1158 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <libperfstat.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <sys/poll.h>
+
+#include <sys/pollset.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+#include <sys/ahafs_evProds.h>
+#endif
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+#define RDWR_BUF_SIZE 4096
+#define EQ(a,b) (strcmp(a,b) == 0)
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->fs_fd = -1;
+
+ /* Passing maxfd of -1 should mean the limit is determined
+ * by the user's ulimit or the global limit as per the doc */
+ loop->backend_fd = pollset_create(-1);
+
+ if (loop->backend_fd == -1)
+ return -1;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ pollset_destroy(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct pollfd events[1024];
+ struct pollfd pqry;
+ struct pollfd* pe;
+ struct poll_ctl pc;
+ QUEUE* q;
+ uv__io_t* w;
+ uint64_t base;
+ uint64_t diff;
+ int nevents;
+ int count;
+ int nfds;
+ int i;
+ int rc;
+ int add_failed;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ pc.events = w->pevents;
+ pc.fd = w->fd;
+
+ add_failed = 0;
+ if (w->events == 0) {
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ if (errno != EINVAL) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ /* Check if the fd is already in the pollset */
+ pqry.fd = pc.fd;
+ rc = pollset_query(loop->backend_fd, &pqry);
+ switch (rc) {
+ case -1:
+ assert(0 && "Failed to query pollset for file descriptor");
+ abort();
+ case 0:
+ assert(0 && "Pollset does not contain file descriptor");
+ abort();
+ }
+ /* If we got here then the pollset already contained the file descriptor even though
+ * we didn't think it should. This probably shouldn't happen, but we can continue. */
+ add_failed = 1;
+ }
+ }
+ if (w->events != 0 || add_failed) {
+ /* Modify, potentially removing events -- need to delete then add.
+ * Could maybe mod if we knew for sure no events are removed, but
+ * content of w->events is handled above as not reliable (falls back)
+ * so may require a pollset_query() which would have to be pretty cheap
+ * compared to a PS_DELETE to be worth optimizing. Alternatively, could
+ * lazily remove events, squelching them in the mean time. */
+ pc.cmd = PS_DELETE;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
+ abort();
+ }
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ nfds = pollset_poll(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR) {
+ abort();
+ }
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ pc.cmd = PS_DELETE;
+ pc.fd = pe->fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (pc.fd == -1)
+ continue;
+
+ assert(pc.fd >= 0);
+ assert((unsigned) pc.fd < loop->nwatchers);
+
+ w = loop->watchers[pc.fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ pollset_ctl(loop->backend_fd, &pc, 1);
+ continue;
+ }
+
+ w->cb(loop, w, pe->revents);
+ nevents++;
+ }
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uint64_t G = 1000000000;
+ timebasestruct_t t;
+ read_wall_time(&t, TIMEBASE_SZ);
+ time_base_to_time(&t, TIMEBASE_SZ);
+ return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ struct procsinfo pi;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pi.pi_pid = getpid();
+ res = getargs(&pi, sizeof(pi), args, sizeof(args));
+ if (res < 0)
+ return -EINVAL;
+
+ /*
+ * Possibilities for args:
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
+ * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+ * iii) a bare filename such as "node", after exporting PATH variable
+ * to its location.
+ */
+
+ /* Case i) and ii) absolute or relative paths */
+ if (strchr(args, '/') != NULL) {
+ if (realpath(args, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+ } else {
+ /* Case iii). Search PATH environment variable */
+ char trypath[PATH_MAX];
+ char *clonedpath = NULL;
+ char *token = NULL;
+ char *path = getenv("PATH");
+
+ if (path == NULL)
+ return -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -ENOMEM;
+
+ token = strtok(clonedpath, ":");
+ while (token != NULL) {
+ snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+ if (realpath(trypath, abspath) == abspath) {
+ /* Check the match is executable */
+ if (access(abspath, X_OK) == 0) {
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ uv__free(clonedpath);
+ return 0;
+ }
+ }
+ token = strtok(NULL, ":");
+ }
+ uv__free(clonedpath);
+
+ /* Out of tokens (path entries), and no match found */
+ return -EINVAL;
+ }
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_free * 4096;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_total * 4096;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ perfstat_cpu_total_t ps_total;
+ int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
+ return;
+ }
+ avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
+ avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
+ avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
+}
+
+
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+static char *uv__rawname(char *cp) {
+ static char rawbuf[FILENAME_MAX+1];
+ char *dp = rindex(cp, '/');
+
+ if (dp == 0)
+ return 0;
+
+ *dp = 0;
+ strcpy(rawbuf, cp);
+ *dp = '/';
+ strcat(rawbuf, "/r");
+ strcat(rawbuf, dp+1);
+ return rawbuf;
+}
+
+
+/*
+ * Determine whether given pathname is a directory
+ * Returns 0 if the path is a directory, -1 if not
+ *
+ * Note: Opportunity here for more detailed error information but
+ * that requires changing callers of this function as well
+ */
+static int uv__path_is_a_directory(char* filename) {
+ struct stat statbuf;
+
+ if (stat(filename, &statbuf) < 0)
+ return -1; /* failed: not a directory, assume it is a file */
+
+ if (statbuf.st_type == VDIR)
+ return 0;
+
+ return -1;
+}
+
+
+/*
+ * Check whether AHAFS is mounted.
+ * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
+ */
+static int uv__is_ahafs_mounted(void){
+ int rv, i = 2;
+ struct vmount *p;
+ int size_multiplier = 10;
+ size_t siz = sizeof(struct vmount)*size_multiplier;
+ struct vmount *vmt;
+ const char *dev = "/aha";
+ char *obj, *stub;
+
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+
+ /* Retrieve all mounted filesystems */
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ if (rv == 0) {
+ /* buffer was not large enough, reallocate to correct size */
+ siz = *(int*)p;
+ uv__free(p);
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ }
+
+ /* Look for dev in filesystems mount info */
+ for(vmt = p, i = 0; i < rv; i++) {
+ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
+ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
+
+ if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
+ uv__free(p); /* Found a match */
+ return 0;
+ }
+ vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
+ }
+
+ /* /aha is required for monitoring filesystem changes */
+ return -1;
+}
+
+/*
+ * Recursive call to mkdir() to create intermediate folders, if any
+ * Returns code from mkdir call
+ */
+static int uv__makedir_p(const char *dir) {
+ char tmp[256];
+ char *p = NULL;
+ size_t len;
+ int err;
+
+ snprintf(tmp, sizeof(tmp),"%s",dir);
+ len = strlen(tmp);
+ if (tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for (p = tmp + 1; *p; p++) {
+ if (*p == '/') {
+ *p = 0;
+ err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if(err != 0)
+ return err;
+ *p = '/';
+ }
+ }
+ return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+}
+
+/*
+ * Creates necessary subdirectories in the AIX Event Infrastructure
+ * file system for monitoring the object specified.
+ * Returns code from mkdir call
+ */
+static int uv__make_subdirs_p(const char *filename) {
+ char cmd[2048];
+ char *p;
+ int rc = 0;
+
+ /* Strip off the monitor file name */
+ p = strrchr(filename, '/');
+
+ if (p == NULL)
+ return 0;
+
+ if (uv__path_is_a_directory((char*)filename) == 0) {
+ sprintf(cmd, "/aha/fs/modDir.monFactory");
+ } else {
+ sprintf(cmd, "/aha/fs/modFile.monFactory");
+ }
+
+ strncat(cmd, filename, (p - filename));
+ rc = uv__makedir_p(cmd);
+
+ if (rc == -1 && errno != EEXIST){
+ return -errno;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Checks if /aha is mounted, then proceeds to set up the monitoring
+ * objects for the specified file.
+ * Returns 0 on success, or an error code < 0 on failure
+ */
+static int uv__setup_ahafs(const char* filename, int *fd) {
+ int rc = 0;
+ char mon_file_write_string[RDWR_BUF_SIZE];
+ char mon_file[PATH_MAX];
+ int file_is_directory = 0; /* -1 == NO, 0 == YES */
+
+ /* Create monitor file name for object */
+ file_is_directory = uv__path_is_a_directory((char*)filename);
+
+ if (file_is_directory == 0)
+ sprintf(mon_file, "/aha/fs/modDir.monFactory");
+ else
+ sprintf(mon_file, "/aha/fs/modFile.monFactory");
+
+ if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
+ return -ENAMETOOLONG;
+
+ /* Make the necessary subdirectories for the monitor file */
+ rc = uv__make_subdirs_p(filename);
+ if (rc == -1 && errno != EEXIST)
+ return rc;
+
+ strcat(mon_file, filename);
+ strcat(mon_file, ".mon");
+
+ *fd = 0; errno = 0;
+
+ /* Open the monitor file, creating it if necessary */
+ *fd = open(mon_file, O_CREAT|O_RDWR);
+ if (*fd < 0)
+ return -errno;
+
+ /* Write out the monitoring specifications.
+ * In this case, we are monitoring for a state change event type
+ * CHANGED=YES
+ * We will be waiting in select call, rather than a read:
+ * WAIT_TYPE=WAIT_IN_SELECT
+ * We only want minimal information for files:
+ * INFO_LVL=1
+ * For directories, we want more information to track what file
+ * caused the change
+ * INFO_LVL=2
+ */
+
+ if (file_is_directory == 0)
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
+ else
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
+
+ rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
+ if (rc < 0)
+ return -errno;
+
+ return 0;
+}
+
+/*
+ * Skips a specified number of lines in the buffer passed in.
+ * Walks the buffer pointed to by p and attempts to skip n lines.
+ * Returns the total number of lines skipped
+ */
+static int uv__skip_lines(char **p, int n) {
+ int lines = 0;
+
+ while(n > 0) {
+ *p = strchr(*p, '\n');
+ if (!p)
+ return lines;
+
+ (*p)++;
+ n--;
+ lines++;
+ }
+ return lines;
+}
+
+
+/*
+ * Parse the event occurrence data to figure out what event just occurred
+ * and take proper action.
+ *
+ * The buf is a pointer to the buffer containing the event occurrence data
+ * Returns 0 on success, -1 if unrecoverable error in parsing
+ *
+ */
+static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
+ int evp_rc, i;
+ char *p;
+ char filename[PATH_MAX]; /* To be used when handling directories */
+
+ p = buf;
+ *events = 0;
+
+ /* Clean the filename buffer*/
+ for(i = 0; i < PATH_MAX; i++) {
+ filename[i] = 0;
+ }
+ i = 0;
+
+ /* Check for BUF_WRAP */
+ if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
+ assert(0 && "Buffer wrap detected, Some event occurrences lost!");
+ return 0;
+ }
+
+ /* Since we are using the default buffer size (4K), and have specified
+ * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
+ * should check for this keyword if they are using an INFO_LVL of 2 or
+ * higher, and have a buffer size of <= 4K
+ */
+
+ /* Skip to RC_FROM_EVPROD */
+ if (uv__skip_lines(&p, 9) != 9)
+ return -1;
+
+ if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
+ if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
+ if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
+ /* The directory is no longer available for monitoring */
+ *events = UV_RENAME;
+ handle->dir_filename = NULL;
+ } else {
+ /* A file was added/removed inside the directory */
+ *events = UV_CHANGE;
+
+ /* Get the EVPROD_INFO */
+ if (uv__skip_lines(&p, 1) != 1)
+ return -1;
+
+ /* Scan out the name of the file that triggered the event*/
+ if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
+ handle->dir_filename = uv__strdup((const char*)&filename);
+ } else
+ return -1;
+ }
+ } else { /* Regular File */
+ if (evp_rc == AHAFS_MODFILE_RENAME)
+ *events = UV_RENAME;
+ else
+ *events = UV_CHANGE;
+ }
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+
+/* This is the internal callback */
+static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
+ char result_data[RDWR_BUF_SIZE];
+ int bytes, rc = 0;
+ uv_fs_event_t* handle;
+ int events = 0;
+ int i = 0;
+ char fname[PATH_MAX];
+ char *p;
+
+ handle = container_of(event_watch, uv_fs_event_t, event_watcher);
+
+ /* Clean all the buffers*/
+ for(i = 0; i < PATH_MAX; i++) {
+ fname[i] = 0;
+ }
+ i = 0;
+
+ /* At this point, we assume that polling has been done on the
+ * file descriptor, so we can just read the AHAFS event occurrence
+ * data and parse its results without having to block anything
+ */
+ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
+
+ assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
+
+ /* Parse the data */
+ if(bytes > 0)
+ rc = uv__parse_data(result_data, &events, handle);
+
+ /* For directory changes, the name of the files that triggered the change
+ * are never absolute pathnames
+ */
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ p = handle->dir_filename;
+ while(*p != NULL){
+ fname[i]= *p;
+ i++;
+ p++;
+ }
+ } else {
+ /* For file changes, figure out whether filename is absolute or not */
+ if (handle->path[0] == '/') {
+ p = strrchr(handle->path, '/');
+ p++;
+
+ while(*p != NULL) {
+ fname[i]= *p;
+ i++;
+ p++;
+ }
+ }
+ }
+
+ /* Unrecoverable error */
+ if (rc == -1)
+ return;
+ else /* Call the actual JavaScript callback function */
+ handle->cb(handle, (const char*)&fname, events, 0);
+}
+#endif
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ int fd, rc, i = 0, res = 0;
+ char cwd[PATH_MAX];
+ char absolute_path[PATH_MAX];
+ char fname[PATH_MAX];
+ char *p;
+
+ /* Clean all the buffers*/
+ for(i = 0; i < PATH_MAX; i++) {
+ cwd[i] = 0;
+ absolute_path[i] = 0;
+ fname[i] = 0;
+ }
+ i = 0;
+
+ /* Figure out whether filename is absolute or not */
+ if (filename[0] == '/') {
+ /* We have absolute pathname, create the relative pathname*/
+ sprintf(absolute_path, filename);
+ p = strrchr(filename, '/');
+ p++;
+ } else {
+ if (filename[0] == '.' && filename[1] == '/') {
+ /* We have a relative pathname, compose the absolute pathname */
+ sprintf(fname, filename);
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
+ if (res < 0)
+ return res;
+ p = strrchr(absolute_path, '/');
+ p++;
+ p++;
+ } else {
+ /* We have a relative pathname, compose the absolute pathname */
+ sprintf(fname, filename);
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
+ if (res < 0)
+ return res;
+ p = strrchr(absolute_path, '/');
+ p++;
+ }
+ /* Copy to filename buffer */
+ while(filename[i] != NULL) {
+ *p = filename[i];
+ i++;
+ p++;
+ }
+ }
+
+ if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
+ return UV_ENOSYS;
+
+ /* Setup ahafs */
+ rc = uv__setup_ahafs((const char *)absolute_path, &fd);
+ if (rc != 0)
+ return rc;
+
+ /* Setup/Initialize all the libuv routines */
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
+ handle->path = uv__strdup((const char*)&absolute_path);
+ handle->cb = cb;
+
+ uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__io_close(handle->loop, &handle->event_watcher);
+ uv__handle_stop(handle);
+
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ uv__free(handle->dir_filename);
+ handle->dir_filename = NULL;
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv_fs_event_stop(handle);
+#else
+ UNREACHABLE();
+#endif
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char pp[64];
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
+
+ fd = open(pp, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ struct utmp *utmp_buf;
+ size_t entries = 0;
+ time_t boot_time;
+
+ utmpname(UTMP_FILE);
+
+ setutent();
+
+ while ((utmp_buf = getutent()) != NULL) {
+ if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
+ ++entries;
+ if (utmp_buf->ut_type == BOOT_TIME)
+ boot_time = utmp_buf->ut_time;
+ }
+
+ endutent();
+
+ if (boot_time == 0)
+ return -ENOSYS;
+
+ *uptime = time(NULL) - boot_time;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ uv_cpu_info_t* cpu_info;
+ perfstat_cpu_total_t ps_total;
+ perfstat_cpu_t* ps_cpus;
+ perfstat_id_t cpu_id;
+ int result, ncpus, idx = 0;
+
+ result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
+ if (!ps_cpus) {
+ return -ENOMEM;
+ }
+
+ strcpy(cpu_id.name, FIRST_CPU);
+ result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
+ if (result == -1) {
+ uv__free(ps_cpus);
+ return -ENOSYS;
+ }
+
+ *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos) {
+ uv__free(ps_cpus);
+ return -ENOMEM;
+ }
+
+ *count = ncpus;
+
+ cpu_info = *cpu_infos;
+ while (idx < ncpus) {
+ cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
+ cpu_info->model = uv__strdup(ps_total.description);
+ cpu_info->cpu_times.user = ps_cpus[idx].user;
+ cpu_info->cpu_times.sys = ps_cpus[idx].sys;
+ cpu_info->cpu_times.idle = ps_cpus[idx].idle;
+ cpu_info->cpu_times.irq = ps_cpus[idx].wait;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info++;
+ idx++;
+ }
+
+ uv__free(ps_cpus);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd, size = 1;
+ struct ifconf ifc;
+ struct ifreq *ifr, *p, flg;
+
+ *count = 0;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+ return -errno;
+ }
+
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+ ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+ ifc.ifc_len = size;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = (uv_interface_address_t*)
+ uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (p->ifr_addr.sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+ }
+
+ /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+#undef ADDR_SIZE
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct pollfd* events;
+ uintptr_t i;
+ uintptr_t nfds;
+ struct poll_ctl pc;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct pollfd*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].fd == fd)
+ events[i].fd = -1;
+
+ /* Remove the file descriptor from the poll set */
+ pc.events = 0;
+ pc.cmd = PS_DELETE;
+ pc.fd = fd;
+ if(loop->backend_fd >= 0)
+ pollset_ctl(loop->backend_fd, &pc, 1);
+}
diff --git a/3rdparty/libuv/src/unix/android-ifaddrs.c b/3rdparty/libuv/src/unix/android-ifaddrs.c
new file mode 100644
index 00000000000..30f681b7d04
--- /dev/null
+++ b/3rdparty/libuv/src/unix/android-ifaddrs.c
@@ -0,0 +1,703 @@
+/*
+Copyright (c) 2013, Kenneth MacKay
+Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "android-ifaddrs.h"
+#include "uv-common.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+typedef struct NetlinkList
+{
+ struct NetlinkList *m_next;
+ struct nlmsghdr *m_data;
+ unsigned int m_size;
+} NetlinkList;
+
+static int netlink_socket(void)
+{
+ struct sockaddr_nl l_addr;
+
+ int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ return l_socket;
+}
+
+static int netlink_send(int p_socket, int p_request)
+{
+ char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+
+ struct nlmsghdr *l_hdr;
+ struct rtgenmsg *l_msg;
+ struct sockaddr_nl l_addr;
+
+ memset(l_buffer, 0, sizeof(l_buffer));
+
+ l_hdr = (struct nlmsghdr *)l_buffer;
+ l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
+
+ l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
+ l_hdr->nlmsg_type = p_request;
+ l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ l_hdr->nlmsg_pid = 0;
+ l_hdr->nlmsg_seq = p_socket;
+ l_msg->rtgen_family = AF_UNSPEC;
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
+}
+
+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
+{
+ struct sockaddr_nl l_addr;
+ struct msghdr l_msg;
+
+ struct iovec l_iov;
+ l_iov.iov_base = p_buffer;
+ l_iov.iov_len = p_len;
+
+ for(;;)
+ {
+ int l_result;
+ l_msg.msg_name = (void *)&l_addr;
+ l_msg.msg_namelen = sizeof(l_addr);
+ l_msg.msg_iov = &l_iov;
+ l_msg.msg_iovlen = 1;
+ l_msg.msg_control = NULL;
+ l_msg.msg_controllen = 0;
+ l_msg.msg_flags = 0;
+ l_result = recvmsg(p_socket, &l_msg, 0);
+
+ if(l_result < 0)
+ {
+ if(errno == EINTR)
+ {
+ continue;
+ }
+ return -2;
+ }
+
+ /* Buffer was too small */
+ if(l_msg.msg_flags & MSG_TRUNC)
+ {
+ return -1;
+ }
+ return l_result;
+ }
+}
+
+static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+{
+ size_t l_size = 4096;
+ void *l_buffer = NULL;
+
+ for(;;)
+ {
+ int l_read;
+
+ uv__free(l_buffer);
+ l_buffer = uv__malloc(l_size);
+ if (l_buffer == NULL)
+ {
+ return NULL;
+ }
+
+ l_read = netlink_recv(p_socket, l_buffer, l_size);
+ *p_size = l_read;
+ if(l_read == -2)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ if(l_read >= 0)
+ {
+ pid_t l_pid = getpid();
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ *p_done = 1;
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_ERROR)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ }
+ return l_buffer;
+ }
+
+ l_size *= 2;
+ }
+}
+
+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
+{
+ NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
+ if (l_item == NULL)
+ {
+ return NULL;
+ }
+
+ l_item->m_next = NULL;
+ l_item->m_data = p_data;
+ l_item->m_size = p_size;
+ return l_item;
+}
+
+static void freeResultList(NetlinkList *p_list)
+{
+ NetlinkList *l_cur;
+ while(p_list)
+ {
+ l_cur = p_list;
+ p_list = p_list->m_next;
+ uv__free(l_cur->m_data);
+ uv__free(l_cur);
+ }
+}
+
+static NetlinkList *getResultList(int p_socket, int p_request)
+{
+ int l_size;
+ int l_done;
+ NetlinkList *l_list;
+ NetlinkList *l_end;
+
+ if(netlink_send(p_socket, p_request) < 0)
+ {
+ return NULL;
+ }
+
+ l_list = NULL;
+ l_end = NULL;
+
+ l_done = 0;
+ while(!l_done)
+ {
+ NetlinkList *l_item;
+
+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+ /* Error */
+ if(!l_hdr)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+
+ l_item = newListItem(l_hdr, l_size);
+ if (!l_item)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+ if(!l_list)
+ {
+ l_list = l_item;
+ }
+ else
+ {
+ l_end->m_next = l_item;
+ }
+ l_end = l_item;
+ }
+ return l_list;
+}
+
+static size_t maxSize(size_t a, size_t b)
+{
+ return (a > b ? a : b);
+}
+
+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_PACKET:
+ return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
+ default:
+ return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
+ }
+}
+
+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
+ break;
+ case AF_INET6:
+ memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
+ break;
+ case AF_PACKET:
+ memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
+ ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
+ break;
+ default:
+ memcpy(p_dest->sa_data, p_data, p_size);
+ break;
+ }
+ p_dest->sa_family = p_family;
+}
+
+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+{
+ if(!*p_resultList)
+ {
+ *p_resultList = p_entry;
+ }
+ else
+ {
+ struct ifaddrs *l_cur = *p_resultList;
+ while(l_cur->ifa_next)
+ {
+ l_cur = l_cur->ifa_next;
+ }
+ l_cur->ifa_next = p_entry;
+ }
+}
+
+static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
+{
+ struct ifaddrs *l_entry;
+
+ char *l_index;
+ char *l_name;
+ char *l_addr;
+ char *l_data;
+
+ struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+ size_t l_dataSize = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ struct rtattr *l_rta;
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
+ break;
+ case IFLA_IFNAME:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ case IFLA_STATS:
+ l_dataSize += NLMSG_ALIGN(l_rtaSize);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = "";
+
+ l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_name = l_index + sizeof(int);
+ l_addr = l_name + l_nameSize;
+ l_data = l_addr + l_addrSize;
+
+ /* Save the interface index so we can look it up when handling the
+ * addresses.
+ */
+ memcpy(l_index, &l_info->ifi_index, sizeof(int));
+
+ l_entry->ifa_flags = l_info->ifi_flags;
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ {
+ size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
+ makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
+ ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
+ if(l_rta->rta_type == IFLA_ADDRESS)
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFLA_IFNAME:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ case IFLA_STATS:
+ memcpy(l_data, l_rtaData, l_rtaDataSize);
+ l_entry->ifa_data = l_data;
+ break;
+ default:
+ break;
+ }
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
+{
+ int l_num = 0;
+ struct ifaddrs *l_cur = *p_links;
+ while(l_cur && l_num < p_numLinks)
+ {
+ char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
+ int l_index;
+ memcpy(&l_index, l_indexPtr, sizeof(int));
+ if(l_index == p_index)
+ {
+ return l_cur;
+ }
+
+ l_cur = l_cur->ifa_next;
+ ++l_num;
+ }
+ return NULL;
+}
+
+static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
+ struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+
+ int l_addedNetmask = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ struct rtattr *l_rta;
+ struct ifaddrs *l_entry;
+
+ char *l_name;
+ char *l_addr;
+
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ if(l_info->ifa_family == AF_PACKET)
+ {
+ continue;
+ }
+
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_LOCAL:
+ if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
+ {
+ /* Make room for netmask */
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ l_addedNetmask = 1;
+ }
+ case IFA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ break;
+ case IFA_LABEL:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
+
+ l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_addr = l_name + l_nameSize;
+
+ l_entry->ifa_flags = l_info->ifa_flags;
+ if(l_interface)
+ {
+ l_entry->ifa_flags |= l_interface->ifa_flags;
+ }
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_BROADCAST:
+ case IFA_LOCAL:
+ {
+ size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
+ makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ if(l_info->ifa_family == AF_INET6)
+ {
+ if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
+ {
+ ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
+ }
+ }
+
+ /* Apparently in a point-to-point network IFA_ADDRESS contains
+ * the dest address and IFA_LOCAL contains the local address
+ */
+ if(l_rta->rta_type == IFA_ADDRESS)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ }
+ else if(l_rta->rta_type == IFA_LOCAL)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = l_entry->ifa_addr;
+ }
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFA_LABEL:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
+ {
+ unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
+ unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
+ char l_mask[16] = {0};
+ unsigned i;
+ for(i=0; i<(l_prefix/8); ++i)
+ {
+ l_mask[i] = 0xff;
+ }
+ if(l_prefix % 8)
+ {
+ l_mask[i] = 0xff << (8 - (l_prefix % 8));
+ }
+
+ makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
+ l_entry->ifa_netmask = (struct sockaddr *)l_addr;
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+{
+
+ int l_numLinks = 0;
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWLINK)
+ {
+ if(interpretLink(l_hdr, p_resultList) == -1)
+ {
+ return -1;
+ }
+ ++l_numLinks;
+ }
+ }
+ }
+ return l_numLinks;
+}
+
+static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWADDR)
+ {
+ if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+ int l_socket;
+ int l_result;
+ int l_numLinks;
+ NetlinkList *l_linkResults;
+ NetlinkList *l_addrResults;
+
+ if(!ifap)
+ {
+ return -1;
+ }
+ *ifap = NULL;
+
+ l_socket = netlink_socket();
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ l_linkResults = getResultList(l_socket, RTM_GETLINK);
+ if(!l_linkResults)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ l_addrResults = getResultList(l_socket, RTM_GETADDR);
+ if(!l_addrResults)
+ {
+ close(l_socket);
+ freeResultList(l_linkResults);
+ return -1;
+ }
+
+ l_result = 0;
+ l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+ {
+ l_result = -1;
+ }
+
+ freeResultList(l_linkResults);
+ freeResultList(l_addrResults);
+ close(l_socket);
+ return l_result;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+ struct ifaddrs *l_cur;
+ while(ifa)
+ {
+ l_cur = ifa;
+ ifa = ifa->ifa_next;
+ uv__free(l_cur);
+ }
+}
diff --git a/3rdparty/libuv/src/unix/async.c b/3rdparty/libuv/src/unix/async.c
new file mode 100644
index 00000000000..184b598126e
--- /dev/null
+++ b/3rdparty/libuv/src/unix/async.c
@@ -0,0 +1,290 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This file contains both the uv__async internal infrastructure and the
+ * user-facing uv_async_t functions.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "atomic-ops.h"
+
+#include <errno.h>
+#include <stdio.h> /* snprintf() */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+static int uv__async_eventfd(void);
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ int err;
+
+ err = uv__async_start(loop, &loop->async_watcher, uv__async_event);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
+ handle->async_cb = async_cb;
+ handle->pending = 0;
+
+ QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ /* Do a cheap read first. */
+ if (ACCESS_ONCE(int, handle->pending) != 0)
+ return 0;
+
+ if (cmpxchgi(&handle->pending, 0, 1) == 0)
+ uv__async_send(&handle->loop->async_watcher);
+
+ return 0;
+}
+
+
+void uv__async_close(uv_async_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+}
+
+
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents) {
+ QUEUE queue;
+ QUEUE* q;
+ uv_async_t* h;
+
+ QUEUE_MOVE(&loop->async_handles, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_async_t, queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->async_handles, q);
+
+ if (cmpxchgi(&h->pending, 1, 0) == 0)
+ continue;
+
+ if (h->async_cb == NULL)
+ continue;
+ h->async_cb(h);
+ }
+}
+
+
+static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ struct uv__async* wa;
+ char buf[1024];
+ unsigned n;
+ ssize_t r;
+
+ n = 0;
+ for (;;) {
+ r = read(w->fd, buf, sizeof(buf));
+
+ if (r > 0)
+ n += r;
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ wa = container_of(w, struct uv__async, io_watcher);
+
+#if defined(__linux__)
+ if (wa->wfd == -1) {
+ uint64_t val;
+ assert(n == sizeof(val));
+ memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */
+ wa->cb(loop, wa, val);
+ return;
+ }
+#endif
+
+ wa->cb(loop, wa, n);
+}
+
+
+void uv__async_send(struct uv__async* wa) {
+ const void* buf;
+ ssize_t len;
+ int fd;
+ int r;
+
+ buf = "";
+ len = 1;
+ fd = wa->wfd;
+
+#if defined(__linux__)
+ if (fd == -1) {
+ static const uint64_t val = 1;
+ buf = &val;
+ len = sizeof(val);
+ fd = wa->io_watcher.fd; /* eventfd */
+ }
+#endif
+
+ do
+ r = write(fd, buf, len);
+ while (r == -1 && errno == EINTR);
+
+ if (r == len)
+ return;
+
+ if (r == -1)
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+
+ abort();
+}
+
+
+void uv__async_init(struct uv__async* wa) {
+ wa->io_watcher.fd = -1;
+ wa->wfd = -1;
+}
+
+
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
+ int pipefd[2];
+ int err;
+
+ if (wa->io_watcher.fd != -1)
+ return 0;
+
+ err = uv__async_eventfd();
+ if (err >= 0) {
+ pipefd[0] = err;
+ pipefd[1] = -1;
+ }
+ else if (err == -ENOSYS) {
+ err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
+#if defined(__linux__)
+ /* Save a file descriptor by opening one of the pipe descriptors as
+ * read/write through the procfs. That file descriptor can then
+ * function as both ends of the pipe.
+ */
+ if (err == 0) {
+ char buf[32];
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
+ fd = uv__open_cloexec(buf, O_RDWR);
+ if (fd >= 0) {
+ uv__close(pipefd[0]);
+ uv__close(pipefd[1]);
+ pipefd[0] = fd;
+ pipefd[1] = fd;
+ }
+ }
+#endif
+ }
+
+ if (err < 0)
+ return err;
+
+ uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
+ uv__io_start(loop, &wa->io_watcher, UV__POLLIN);
+ wa->wfd = pipefd[1];
+ wa->cb = cb;
+
+ return 0;
+}
+
+
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
+ if (wa->io_watcher.fd == -1)
+ return;
+
+ if (wa->wfd != -1) {
+ if (wa->wfd != wa->io_watcher.fd)
+ uv__close(wa->wfd);
+ wa->wfd = -1;
+ }
+
+ uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
+ uv__close(wa->io_watcher.fd);
+ wa->io_watcher.fd = -1;
+}
+
+
+static int uv__async_eventfd() {
+#if defined(__linux__)
+ static int no_eventfd2;
+ static int no_eventfd;
+ int fd;
+
+ if (no_eventfd2)
+ goto skip_eventfd2;
+
+ fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd2 = 1;
+
+skip_eventfd2:
+
+ if (no_eventfd)
+ goto skip_eventfd;
+
+ fd = uv__eventfd(0);
+ if (fd != -1) {
+ uv__cloexec(fd, 1);
+ uv__nonblock(fd, 1);
+ return fd;
+ }
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd = 1;
+
+skip_eventfd:
+
+#endif
+
+ return -ENOSYS;
+}
diff --git a/3rdparty/libuv/src/unix/atomic-ops.h b/3rdparty/libuv/src/unix/atomic-ops.h
new file mode 100644
index 00000000000..84e471838be
--- /dev/null
+++ b/3rdparty/libuv/src/unix/atomic-ops.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_ATOMIC_OPS_H_
+#define UV_ATOMIC_OPS_H_
+
+#include "internal.h" /* UV_UNUSED */
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#include <atomic.h>
+#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
+#endif
+
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
+UV_UNUSED(static void cpu_relax(void));
+
+/* Prefer hand-rolled assembly over the gcc builtins because the latter also
+ * issue full memory barriers.
+ */
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ int out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile int*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const int out = (*(volatile int*) ptr);
+ __compare_and_swap(ptr, &oldval, newval);
+ return out;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ long out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile long*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const long out = (*(volatile int*) ptr);
+# if defined(__64BIT__)
+ __compare_and_swaplp(ptr, &oldval, newval);
+# else
+ __compare_and_swap(ptr, &oldval, newval);
+# endif /* if defined(__64BIT__) */
+ return out;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static void cpu_relax(void)) {
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
+#endif
+}
+
+#endif /* UV_ATOMIC_OPS_H_ */
diff --git a/3rdparty/libuv/src/unix/core.c b/3rdparty/libuv/src/unix/core.c
new file mode 100644
index 00000000000..cedd86ed34a
--- /dev/null
+++ b/3rdparty/libuv/src/unix/core.c
@@ -0,0 +1,1104 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* printf */
+#include <stdlib.h>
+#include <string.h> /* strerror */
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
+#include <sys/uio.h> /* writev */
+#include <sys/resource.h> /* getrusage */
+#include <pwd.h>
+
+#ifdef __linux__
+# include <sys/ioctl.h>
+#endif
+
+#ifdef __sun
+# include <sys/types.h>
+# include <sys/wait.h>
+#endif
+
+#ifdef __APPLE__
+# include <mach-o/dyld.h> /* _NSGetExecutablePath */
+# include <sys/filio.h>
+# include <sys/ioctl.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+# include <sys/sysctl.h>
+# include <sys/filio.h>
+# include <sys/ioctl.h>
+# include <sys/wait.h>
+# define UV__O_CLOEXEC O_CLOEXEC
+# if defined(__FreeBSD__) && __FreeBSD__ >= 10
+# define uv__accept4 accept4
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
+# endif
+# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
+# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
+# endif
+#endif
+
+#ifdef _AIX
+#include <sys/ioctl.h>
+#endif
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+# include <dlfcn.h> /* for dlsym */
+#endif
+
+static int uv__run_pending(uv_loop_t* loop);
+
+/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
+STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
+ sizeof(((struct iovec*) 0)->iov_base));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
+ sizeof(((struct iovec*) 0)->iov_len));
+STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
+STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
+
+
+uint64_t uv_hrtime(void) {
+ return uv__hrtime(UV_CLOCK_PRECISE);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ handle->flags |= UV_CLOSING;
+ handle->close_cb = close_cb;
+
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ uv__pipe_close((uv_pipe_t*)handle);
+ break;
+
+ case UV_TTY:
+ uv__stream_close((uv_stream_t*)handle);
+ break;
+
+ case UV_TCP:
+ uv__tcp_close((uv_tcp_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_close((uv_udp_t*)handle);
+ break;
+
+ case UV_PREPARE:
+ uv__prepare_close((uv_prepare_t*)handle);
+ break;
+
+ case UV_CHECK:
+ uv__check_close((uv_check_t*)handle);
+ break;
+
+ case UV_IDLE:
+ uv__idle_close((uv_idle_t*)handle);
+ break;
+
+ case UV_ASYNC:
+ uv__async_close((uv_async_t*)handle);
+ break;
+
+ case UV_TIMER:
+ uv__timer_close((uv_timer_t*)handle);
+ break;
+
+ case UV_PROCESS:
+ uv__process_close((uv_process_t*)handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv__fs_event_close((uv_fs_event_t*)handle);
+ break;
+
+ case UV_POLL:
+ uv__poll_close((uv_poll_t*)handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*)handle);
+ break;
+
+ case UV_SIGNAL:
+ uv__signal_close((uv_signal_t*) handle);
+ /* Signal handles may not be closed immediately. The signal code will */
+ /* itself close uv__make_close_pending whenever appropriate. */
+ return;
+
+ default:
+ assert(0);
+ }
+
+ uv__make_close_pending(handle);
+}
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int fd;
+ socklen_t len;
+
+ if (handle == NULL || value == NULL)
+ return -EINVAL;
+
+ if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
+ fd = uv__stream_fd((uv_stream_t*) handle);
+ else if (handle->type == UV_UDP)
+ fd = ((uv_udp_t *) handle)->io_watcher.fd;
+ else
+ return -ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
+ else
+ r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
+
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+void uv__make_close_pending(uv_handle_t* handle) {
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->next_closing = handle->loop->closing_handles;
+ handle->loop->closing_handles = handle;
+}
+
+int uv__getiovmax(void) {
+#if defined(IOV_MAX)
+ return IOV_MAX;
+#elif defined(_SC_IOV_MAX)
+ static int iovmax = -1;
+ if (iovmax == -1) {
+ iovmax = sysconf(_SC_IOV_MAX);
+ /* On some embedded devices (arm-linux-uclibc based ip camera),
+ * sysconf(_SC_IOV_MAX) can not get the correct value. The return
+ * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
+ */
+ if (iovmax == -1) iovmax = 1;
+ }
+ return iovmax;
+#else
+ return 1024;
+#endif
+}
+
+
+static void uv__finish_close(uv_handle_t* handle) {
+ /* Note: while the handle is in the UV_CLOSING state now, it's still possible
+ * for it to be active in the sense that uv__is_active() returns true.
+ * A good example is when the user calls uv_shutdown(), immediately followed
+ * by uv_close(). The handle is considered active at this point because the
+ * completion of the shutdown req is still pending.
+ */
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->flags |= UV_CLOSED;
+
+ switch (handle->type) {
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ case UV_ASYNC:
+ case UV_TIMER:
+ case UV_PROCESS:
+ case UV_FS_EVENT:
+ case UV_FS_POLL:
+ case UV_POLL:
+ case UV_SIGNAL:
+ break;
+
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ case UV_TTY:
+ uv__stream_destroy((uv_stream_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_finish_close((uv_udp_t*)handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ uv__handle_unref(handle);
+ QUEUE_REMOVE(&handle->handle_queue);
+
+ if (handle->close_cb) {
+ handle->close_cb(handle);
+ }
+}
+
+
+static void uv__run_closing_handles(uv_loop_t* loop) {
+ uv_handle_t* p;
+ uv_handle_t* q;
+
+ p = loop->closing_handles;
+ loop->closing_handles = NULL;
+
+ while (p) {
+ q = p->next_closing;
+ uv__finish_close(p);
+ p = q;
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return uv__is_closing(handle);
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return loop->backend_fd;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->idle_handles))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ if (loop->closing_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return uv__has_active_handles(loop) ||
+ uv__has_active_reqs(loop) ||
+ loop->closing_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+ int timeout;
+ int r;
+ int ran_pending;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv__update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ ran_pending = uv__run_pending(loop);
+ uv__run_idle(loop);
+ uv__run_prepare(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ uv__io_poll(loop, timeout);
+ uv__run_check(loop);
+ uv__run_closing_handles(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets gcc compile it to a conditional store. Avoids
+ * dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uv__update_time(loop);
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return uv__is_active(handle);
+}
+
+
+/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
+int uv__socket(int domain, int type, int protocol) {
+ int sockfd;
+ int err;
+
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
+ if (sockfd != -1)
+ return sockfd;
+
+ if (errno != EINVAL)
+ return -errno;
+#endif
+
+ sockfd = socket(domain, type, protocol);
+ if (sockfd == -1)
+ return -errno;
+
+ err = uv__nonblock(sockfd, 1);
+ if (err == 0)
+ err = uv__cloexec(sockfd, 1);
+
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+#if defined(SO_NOSIGPIPE)
+ {
+ int on = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
+ }
+#endif
+
+ return sockfd;
+}
+
+
+int uv__accept(int sockfd) {
+ int peerfd;
+ int err;
+
+ assert(sockfd >= 0);
+
+ while (1) {
+#if defined(__linux__) || __FreeBSD__ >= 10
+ static int no_accept4;
+
+ if (no_accept4)
+ goto skip;
+
+ peerfd = uv__accept4(sockfd,
+ NULL,
+ NULL,
+ UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
+ if (peerfd != -1)
+ return peerfd;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_accept4 = 1;
+skip:
+#endif
+
+ peerfd = accept(sockfd, NULL, NULL);
+ if (peerfd == -1) {
+ if (errno == EINTR)
+ continue;
+ return -errno;
+ }
+
+ err = uv__cloexec(peerfd, 1);
+ if (err == 0)
+ err = uv__nonblock(peerfd, 1);
+
+ if (err) {
+ uv__close(peerfd);
+ return err;
+ }
+
+ return peerfd;
+ }
+}
+
+
+int uv__close(int fd) {
+ int saved_errno;
+ int rc;
+
+ assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
+ assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
+
+ saved_errno = errno;
+ rc = close(fd);
+ if (rc == -1) {
+ rc = -errno;
+ if (rc == -EINTR)
+ rc = -EINPROGRESS; /* For platform/libc consistency. */
+ errno = saved_errno;
+ }
+
+ return rc;
+}
+
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__)
+
+int uv__nonblock(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, FIONBIO, &set);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__cloexec(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__)) */
+
+int uv__nonblock(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFL);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & O_NONBLOCK) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | O_NONBLOCK;
+ else
+ flags = r & ~O_NONBLOCK;
+
+ do
+ r = fcntl(fd, F_SETFL, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__cloexec(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFD);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & FD_CLOEXEC) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | FD_CLOEXEC;
+ else
+ flags = r & ~FD_CLOEXEC;
+
+ do
+ r = fcntl(fd, F_SETFD, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__) */
+
+
+/* This function is not execve-safe, there is a race window
+ * between the call to dup() and fcntl(FD_CLOEXEC).
+ */
+int uv__dup(int fd) {
+ int err;
+
+ fd = dup(fd);
+
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
+ struct cmsghdr* cmsg;
+ ssize_t rc;
+ int* pfd;
+ int* end;
+#if defined(__linux__)
+ static int no_msg_cmsg_cloexec;
+ if (no_msg_cmsg_cloexec == 0) {
+ rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
+ if (rc != -1)
+ return rc;
+ if (errno != EINVAL)
+ return -errno;
+ rc = recvmsg(fd, msg, flags);
+ if (rc == -1)
+ return -errno;
+ no_msg_cmsg_cloexec = 1;
+ } else {
+ rc = recvmsg(fd, msg, flags);
+ }
+#else
+ rc = recvmsg(fd, msg, flags);
+#endif
+ if (rc == -1)
+ return -errno;
+ if (msg->msg_controllen == 0)
+ return rc;
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
+ if (cmsg->cmsg_type == SCM_RIGHTS)
+ for (pfd = (int*) CMSG_DATA(cmsg),
+ end = (int*) ((char*) cmsg + cmsg->cmsg_len);
+ pfd < end;
+ pfd += 1)
+ uv__cloexec(*pfd, 1);
+ return rc;
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ if (buffer == NULL || size == NULL)
+ return -EINVAL;
+
+ if (getcwd(buffer, *size) == NULL)
+ return -errno;
+
+ *size = strlen(buffer);
+ if (*size > 1 && buffer[*size - 1] == '/') {
+ buffer[*size-1] = '\0';
+ (*size)--;
+ }
+
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ if (chdir(dir))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv_disable_stdio_inheritance(void) {
+ int fd;
+
+ /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
+ * first 16 file descriptors. After that, bail out after the first error.
+ */
+ for (fd = 0; ; fd++)
+ if (uv__cloexec(fd, 1) && fd > 15)
+ break;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ int fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ case UV_NAMED_PIPE:
+ case UV_TTY:
+ fd_out = uv__stream_fd((uv_stream_t*) handle);
+ break;
+
+ case UV_UDP:
+ fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
+ break;
+
+ case UV_POLL:
+ fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (uv__is_closing(handle) || fd_out == -1)
+ return -EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+static int uv__run_pending(uv_loop_t* loop) {
+ QUEUE* q;
+ QUEUE pq;
+ uv__io_t* w;
+
+ if (QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ QUEUE_MOVE(&loop->pending_queue, &pq);
+
+ while (!QUEUE_EMPTY(&pq)) {
+ q = QUEUE_HEAD(&pq);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+ w = QUEUE_DATA(q, uv__io_t, pending_queue);
+ w->cb(loop, w, UV__POLLOUT);
+ }
+
+ return 1;
+}
+
+
+static unsigned int next_power_of_two(unsigned int val) {
+ val -= 1;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val += 1;
+ return val;
+}
+
+static void maybe_resize(uv_loop_t* loop, unsigned int len) {
+ uv__io_t** watchers;
+ void* fake_watcher_list;
+ void* fake_watcher_count;
+ unsigned int nwatchers;
+ unsigned int i;
+
+ if (len <= loop->nwatchers)
+ return;
+
+ /* Preserve fake watcher list and count at the end of the watchers */
+ if (loop->watchers != NULL) {
+ fake_watcher_list = loop->watchers[loop->nwatchers];
+ fake_watcher_count = loop->watchers[loop->nwatchers + 1];
+ } else {
+ fake_watcher_list = NULL;
+ fake_watcher_count = NULL;
+ }
+
+ nwatchers = next_power_of_two(len + 2) - 2;
+ watchers = uv__realloc(loop->watchers,
+ (nwatchers + 2) * sizeof(loop->watchers[0]));
+
+ if (watchers == NULL)
+ abort();
+ for (i = loop->nwatchers; i < nwatchers; i++)
+ watchers[i] = NULL;
+ watchers[nwatchers] = fake_watcher_list;
+ watchers[nwatchers + 1] = fake_watcher_count;
+
+ loop->watchers = watchers;
+ loop->nwatchers = nwatchers;
+}
+
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
+ assert(cb != NULL);
+ assert(fd >= -1);
+ QUEUE_INIT(&w->pending_queue);
+ QUEUE_INIT(&w->watcher_queue);
+ w->cb = cb;
+ w->fd = fd;
+ w->events = 0;
+ w->pevents = 0;
+
+#if defined(UV_HAVE_KQUEUE)
+ w->rcount = 0;
+ w->wcount = 0;
+#endif /* defined(UV_HAVE_KQUEUE) */
+}
+
+
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+ assert(w->fd >= 0);
+ assert(w->fd < INT_MAX);
+
+ w->pevents |= events;
+ maybe_resize(loop, w->fd + 1);
+
+#if !defined(__sun)
+ /* The event ports backend needs to rearm all file descriptors on each and
+ * every tick of the event loop but the other backends allow us to
+ * short-circuit here if the event mask is unchanged.
+ */
+ if (w->events == w->pevents) {
+ if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) {
+ QUEUE_REMOVE(&w->watcher_queue);
+ QUEUE_INIT(&w->watcher_queue);
+ }
+ return;
+ }
+#endif
+
+ if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+
+ if (loop->watchers[w->fd] == NULL) {
+ loop->watchers[w->fd] = w;
+ loop->nfds++;
+ }
+}
+
+
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+
+ if (w->fd == -1)
+ return;
+
+ assert(w->fd >= 0);
+
+ /* Happens when uv__io_stop() is called on a handle that was never started. */
+ if ((unsigned) w->fd >= loop->nwatchers)
+ return;
+
+ w->pevents &= ~events;
+
+ if (w->pevents == 0) {
+ QUEUE_REMOVE(&w->watcher_queue);
+ QUEUE_INIT(&w->watcher_queue);
+
+ if (loop->watchers[w->fd] != NULL) {
+ assert(loop->watchers[w->fd] == w);
+ assert(loop->nfds > 0);
+ loop->watchers[w->fd] = NULL;
+ loop->nfds--;
+ w->events = 0;
+ }
+ }
+ else if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+}
+
+
+void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
+ uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
+ QUEUE_REMOVE(&w->pending_queue);
+
+ /* Remove stale events for this file descriptor */
+ uv__platform_invalidate_fd(loop, w->fd);
+}
+
+
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
+ if (QUEUE_EMPTY(&w->pending_queue))
+ QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
+}
+
+
+int uv__io_active(const uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+ return 0 != (w->pevents & events);
+}
+
+
+int uv_getrusage(uv_rusage_t* rusage) {
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage))
+ return -errno;
+
+ rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
+ rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
+
+ rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
+ rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
+
+ rusage->ru_maxrss = usage.ru_maxrss;
+ rusage->ru_ixrss = usage.ru_ixrss;
+ rusage->ru_idrss = usage.ru_idrss;
+ rusage->ru_isrss = usage.ru_isrss;
+ rusage->ru_minflt = usage.ru_minflt;
+ rusage->ru_majflt = usage.ru_majflt;
+ rusage->ru_nswap = usage.ru_nswap;
+ rusage->ru_inblock = usage.ru_inblock;
+ rusage->ru_oublock = usage.ru_oublock;
+ rusage->ru_msgsnd = usage.ru_msgsnd;
+ rusage->ru_msgrcv = usage.ru_msgrcv;
+ rusage->ru_nsignals = usage.ru_nsignals;
+ rusage->ru_nvcsw = usage.ru_nvcsw;
+ rusage->ru_nivcsw = usage.ru_nivcsw;
+
+ return 0;
+}
+
+
+int uv__open_cloexec(const char* path, int flags) {
+ int err;
+ int fd;
+
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \
+ defined(__DragonFly__)
+ static int no_cloexec;
+
+ if (!no_cloexec) {
+ fd = open(path, flags | UV__O_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != EINVAL)
+ return -errno;
+
+ /* O_CLOEXEC not supported. */
+ no_cloexec = 1;
+ }
+#endif
+
+ fd = open(path, flags);
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+int uv__dup2_cloexec(int oldfd, int newfd) {
+ int r;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+ r = dup3(oldfd, newfd, O_CLOEXEC);
+ if (r == -1)
+ return -errno;
+ return r;
+#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
+ r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
+ if (r != -1)
+ return r;
+ if (errno != EINVAL)
+ return -errno;
+ /* Fall through. */
+#elif defined(__linux__)
+ static int no_dup3;
+ if (!no_dup3) {
+ do
+ r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
+ while (r == -1 && errno == EBUSY);
+ if (r != -1)
+ return r;
+ if (errno != ENOSYS)
+ return -errno;
+ /* Fall through. */
+ no_dup3 = 1;
+ }
+#endif
+ {
+ int err;
+ do
+ r = dup2(oldfd, newfd);
+#if defined(__linux__)
+ while (r == -1 && errno == EBUSY);
+#else
+ while (0); /* Never retry. */
+#endif
+
+ if (r == -1)
+ return -errno;
+
+ err = uv__cloexec(newfd, 1);
+ if (err) {
+ uv__close(newfd);
+ return err;
+ }
+
+ return r;
+ }
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ struct passwd pw;
+ struct passwd* result;
+ char* buf;
+ uid_t uid;
+ size_t bufsize;
+ size_t len;
+ long initsize;
+ int r;
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
+#endif
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ /* Check if the HOME environment variable is set first */
+ buf = getenv("HOME");
+
+ if (buf != NULL) {
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len;
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ *size = len;
+
+ return 0;
+ }
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
+ if (getpwuid_r == NULL)
+ return -ENOSYS;
+#endif
+
+ /* HOME is not set, so call getpwuid() */
+ initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if (initsize <= 0)
+ bufsize = 4096;
+ else
+ bufsize = (size_t) initsize;
+
+ uid = getuid();
+ buf = NULL;
+
+ for (;;) {
+ uv__free(buf);
+ buf = uv__malloc(bufsize);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ r = getpwuid_r(uid, &pw, buf, bufsize, &result);
+
+ if (r != ERANGE)
+ break;
+
+ bufsize *= 2;
+ }
+
+ if (r != 0) {
+ uv__free(buf);
+ return -r;
+ }
+
+ if (result == NULL) {
+ uv__free(buf);
+ return -ENOENT;
+ }
+
+ len = strlen(pw.pw_dir);
+
+ if (len >= *size) {
+ *size = len;
+ uv__free(buf);
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, pw.pw_dir, len + 1);
+ *size = len;
+ uv__free(buf);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/darwin-proctitle.c b/3rdparty/libuv/src/unix/darwin-proctitle.c
new file mode 100644
index 00000000000..1142311609f
--- /dev/null
+++ b/3rdparty/libuv/src/unix/darwin-proctitle.c
@@ -0,0 +1,206 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <TargetConditionals.h>
+
+#if !TARGET_OS_IPHONE
+# include <CoreFoundation/CoreFoundation.h>
+# include <ApplicationServices/ApplicationServices.h>
+#endif
+
+
+static int uv__pthread_setname_np(const char* name) {
+ int (*dynamic_pthread_setname_np)(const char* name);
+ char namebuf[64]; /* MAXTHREADNAMESIZE */
+ int err;
+
+ /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
+ *(void **)(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+ if (dynamic_pthread_setname_np == NULL)
+ return -ENOSYS;
+
+ strncpy(namebuf, name, sizeof(namebuf) - 1);
+ namebuf[sizeof(namebuf) - 1] = '\0';
+
+ err = dynamic_pthread_setname_np(namebuf);
+ if (err)
+ return -err;
+
+ return 0;
+}
+
+
+int uv__set_process_title(const char* title) {
+#if TARGET_OS_IPHONE
+ return uv__pthread_setname_np(title);
+#else
+ CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
+ const char*,
+ CFStringEncoding);
+ CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
+ void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
+ void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
+ CFTypeRef (*pLSGetCurrentApplicationASN)(void);
+ OSStatus (*pLSSetApplicationInformationItem)(int,
+ CFTypeRef,
+ CFStringRef,
+ CFStringRef,
+ CFDictionaryRef*);
+ void* application_services_handle;
+ void* core_foundation_handle;
+ CFBundleRef launch_services_bundle;
+ CFStringRef* display_name_key;
+ CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
+ CFBundleRef (*pCFBundleGetMainBundle)(void);
+ CFBundleRef hi_services_bundle;
+ OSStatus (*pSetApplicationIsDaemon)(int);
+ CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
+ void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+ void*);
+ CFTypeRef asn;
+ int err;
+
+ err = -ENOENT;
+ application_services_handle = dlopen("/System/Library/Frameworks/"
+ "ApplicationServices.framework/"
+ "Versions/A/ApplicationServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+
+ if (application_services_handle == NULL || core_foundation_handle == NULL)
+ goto out;
+
+ *(void **)(&pCFStringCreateWithCString) =
+ dlsym(core_foundation_handle, "CFStringCreateWithCString");
+ *(void **)(&pCFBundleGetBundleWithIdentifier) =
+ dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
+ *(void **)(&pCFBundleGetDataPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
+ *(void **)(&pCFBundleGetFunctionPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
+
+ if (pCFStringCreateWithCString == NULL ||
+ pCFBundleGetBundleWithIdentifier == NULL ||
+ pCFBundleGetDataPointerForName == NULL ||
+ pCFBundleGetFunctionPointerForName == NULL) {
+ goto out;
+ }
+
+#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
+
+ launch_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
+
+ if (launch_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pLSGetCurrentApplicationASN) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSGetCurrentApplicationASN"));
+
+ if (pLSGetCurrentApplicationASN == NULL)
+ goto out;
+
+ *(void **)(&pLSSetApplicationInformationItem) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSSetApplicationInformationItem"));
+
+ if (pLSSetApplicationInformationItem == NULL)
+ goto out;
+
+ display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
+ S("_kLSDisplayNameKey"));
+
+ if (display_name_key == NULL || *display_name_key == NULL)
+ goto out;
+
+ *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
+ "CFBundleGetInfoDictionary");
+ *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
+ "CFBundleGetMainBundle");
+ if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
+ goto out;
+
+ /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
+ hi_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
+ err = -ENOENT;
+ if (hi_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
+ hi_services_bundle,
+ S("SetApplicationIsDaemon"));
+ *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSApplicationCheckIn"));
+ *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
+ pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
+ if (pSetApplicationIsDaemon == NULL ||
+ pLSApplicationCheckIn == NULL ||
+ pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
+ goto out;
+ }
+
+ if (pSetApplicationIsDaemon(1) != noErr)
+ goto out;
+
+ pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+ /* Check into process manager?! */
+ pLSApplicationCheckIn(-2,
+ pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
+
+ asn = pLSGetCurrentApplicationASN();
+
+ err = -EINVAL;
+ if (pLSSetApplicationInformationItem(-2, /* Magic value. */
+ asn,
+ *display_name_key,
+ S(title),
+ NULL) != noErr) {
+ goto out;
+ }
+
+ uv__pthread_setname_np(title); /* Don't care if it fails. */
+ err = 0;
+
+out:
+ if (core_foundation_handle != NULL)
+ dlclose(core_foundation_handle);
+
+ if (application_services_handle != NULL)
+ dlclose(application_services_handle);
+
+ return err;
+#endif /* !TARGET_OS_IPHONE */
+}
diff --git a/3rdparty/libuv/src/unix/darwin.c b/3rdparty/libuv/src/unix/darwin.c
new file mode 100644
index 00000000000..cf95da21693
--- /dev/null
+++ b/3rdparty/libuv/src/unix/darwin.c
@@ -0,0 +1,335 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h> /* _NSGetExecutablePath */
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <unistd.h> /* sysconf */
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->cf_state = NULL;
+
+ if (uv__kqueue_init(loop))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ uv__fsevents_loop_delete(loop);
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static mach_timebase_info_data_t info;
+
+ if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
+ ACCESS_ONCE(uint32_t, info.denom) == 0) &&
+ mach_timebase_info(&info) != KERN_SUCCESS)
+ abort();
+
+ return mach_absolute_time() * info.numer / info.denom;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
+ char abspath[PATH_MAX * 2 + 1];
+ char exepath[PATH_MAX + 1];
+ uint32_t exepath_size;
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ exepath_size = sizeof(exepath);
+ if (_NSGetExecutablePath(exepath, &exepath_size))
+ return -EIO;
+
+ if (realpath(exepath, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+ if (abspath_size == 0)
+ return -EIO;
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ vm_statistics_data_t info;
+ mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
+
+ if (host_statistics(mach_host_self(), HOST_VM_INFO,
+ (host_info_t)&info, &count) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_MEMSIZE};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ mach_msg_type_number_t count;
+ task_basic_info_data_t info;
+ kern_return_t err;
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(mach_task_self(),
+ TASK_BASIC_INFO,
+ (task_info_t) &info,
+ &count);
+ (void) &err;
+ /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
+ * KERN_SUCCESS implies a libuv bug.
+ */
+ assert(err == KERN_SUCCESS);
+ *rss = info.resident_size;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+ *uptime = now - info.tv_sec;
+
+ return 0;
+}
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks);
+ char model[512];
+ uint64_t cpuspeed;
+ size_t size;
+ unsigned int i;
+ natural_t numcpus;
+ mach_msg_type_number_t msg_type;
+ processor_cpu_load_info_data_t *info;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
+ return -errno;
+
+ if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
+ (processor_info_array_t*)&info,
+ &msg_type) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+ return -ENOMEM;
+ }
+
+ *count = numcpus;
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
+ cpu_info->cpu_times.irq = 0;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed/1000000;
+ }
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == AF_LINK)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On Mac OS X getifaddrs returns information related to Mac Addresses for
+ * various devices, such as firewire, etc. These are not relevant here.
+ */
+ if (ent->ifa_addr->sa_family == AF_LINK)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/dl.c b/3rdparty/libuv/src/unix/dl.c
new file mode 100644
index 00000000000..fc1c052bb81
--- /dev/null
+++ b/3rdparty/libuv/src/unix/dl.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+
+static int uv__dlerror(uv_lib_t* lib);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ dlerror(); /* Reset error status. */
+ lib->errmsg = NULL;
+ lib->handle = dlopen(filename, RTLD_LAZY);
+ return lib->handle ? 0 : uv__dlerror(lib);
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ uv__free(lib->errmsg);
+ lib->errmsg = NULL;
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ dlclose(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ dlerror(); /* Reset error status. */
+ *ptr = dlsym(lib->handle, name);
+ return uv__dlerror(lib);
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static int uv__dlerror(uv_lib_t* lib) {
+ const char* errmsg;
+
+ uv__free(lib->errmsg);
+
+ errmsg = dlerror();
+
+ if (errmsg) {
+ lib->errmsg = uv__strdup(errmsg);
+ return -1;
+ }
+ else {
+ lib->errmsg = NULL;
+ return 0;
+ }
+}
diff --git a/3rdparty/libuv/src/unix/freebsd.c b/3rdparty/libuv/src/unix/freebsd.c
new file mode 100644
index 00000000000..b747abdf5bc
--- /dev/null
+++ b/3rdparty/libuv/src/unix/freebsd.c
@@ -0,0 +1,450 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <sys/user.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h> /* VM_LOADAVG */
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h> /* sysconf */
+#include <fcntl.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+#ifndef CPUSTATES
+# define CPUSTATES 5U
+#endif
+#ifndef CP_USER
+# define CP_USER 0
+# define CP_NICE 1
+# define CP_SYS 2
+# define CP_IDLE 3
+# define CP_INTR 4
+#endif
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+#ifdef __DragonFly__
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ ssize_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
+ if (abspath_size < 0)
+ return -errno;
+
+ assert(abspath_size > 0);
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#else
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ int mib[4];
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ abspath_size = sizeof abspath;
+ if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
+ return -errno;
+
+ assert(abspath_size > 0);
+ abspath_size -= 1;
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#endif
+
+uint64_t uv_get_free_memory(void) {
+ int freecount;
+ size_t size = sizeof(freecount);
+
+ if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
+
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ unsigned long info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int oid[4];
+
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_PROC;
+ oid[2] = KERN_PROC_ARGS;
+ oid[3] = getpid();
+
+ sysctl(oid,
+ ARRAY_SIZE(oid),
+ NULL,
+ NULL,
+ process_title,
+ strlen(process_title) + 1);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ size_t page_size = getpagesize();
+
+ pid = getpid();
+
+ kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
+ if (kinfo == NULL) goto error;
+
+#ifdef __DragonFly__
+ *rss = kinfo->kp_vm_rssize * page_size;
+#else
+ *rss = kinfo->ki_rssize * page_size;
+#endif
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ int r;
+ struct timespec sp;
+ r = clock_gettime(CLOCK_MONOTONIC, &sp);
+ if (r)
+ return -errno;
+
+ *uptime = sp.tv_sec;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
+ cur = 0;
+ uv_cpu_info_t* cpu_info;
+ const char* maxcpus_key;
+ const char* cptimes_key;
+ char model[512];
+ long* cp_times;
+ int numcpus;
+ size_t size;
+ int i;
+
+#if defined(__DragonFly__)
+ /* This is not quite correct but DragonFlyBSD doesn't seem to have anything
+ * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
+ * not per CPU). At least this stops uv_cpu_info() from failing completely.
+ */
+ maxcpus_key = "hw.ncpu";
+ cptimes_key = "kern.cp_time";
+#else
+ maxcpus_key = "kern.smp.maxcpus";
+ cptimes_key = "kern.cp_times";
+#endif
+
+ size = sizeof(model);
+ if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+ return -errno;
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
+ * ncpu.
+ */
+ size = sizeof(maxcpus);
+ if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ size = maxcpus * CPUSTATES * sizeof(long);
+
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL) {
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(cp_times));
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+
+ cur+=CPUSTATES;
+ }
+
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == AF_LINK)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On FreeBSD getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information yet.
+ */
+ if (ent->ifa_addr->sa_family == AF_LINK)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/fs.c b/3rdparty/libuv/src/unix/fs.c
new file mode 100644
index 00000000000..57b65be25a8
--- /dev/null
+++ b/3rdparty/libuv/src/unix/fs.c
@@ -0,0 +1,1310 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Caveat emptor: this file deviates from the libuv convention of returning
+ * negated errno codes. Most uv_fs_*() functions map directly to the system
+ * call of the same name. For more complex wrappers, it's easier to just
+ * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
+ * getting the errno to the right place (req->result or as the return value.)
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <poll.h>
+
+#if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_PREADV 1
+#else
+# define HAVE_PREADV 0
+#endif
+
+#if defined(__linux__) || defined(__sun)
+# include <sys/sendfile.h>
+#endif
+
+#define INIT(subtype) \
+ do { \
+ req->type = UV_FS; \
+ if (cb != NULL) \
+ uv__req_init(loop, req, UV_FS); \
+ req->fs_type = UV_FS_ ## subtype; \
+ req->result = 0; \
+ req->ptr = NULL; \
+ req->loop = loop; \
+ req->path = NULL; \
+ req->new_path = NULL; \
+ req->cb = cb; \
+ } \
+ while (0)
+
+#define PATH \
+ do { \
+ assert(path != NULL); \
+ if (cb == NULL) { \
+ req->path = path; \
+ } else { \
+ req->path = uv__strdup(path); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ } \
+ } \
+ while (0)
+
+#define PATH2 \
+ do { \
+ if (cb == NULL) { \
+ req->path = path; \
+ req->new_path = new_path; \
+ } else { \
+ size_t path_len; \
+ size_t new_path_len; \
+ path_len = strlen(path) + 1; \
+ new_path_len = strlen(new_path) + 1; \
+ req->path = uv__malloc(path_len + new_path_len); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ req->new_path = req->path + path_len; \
+ memcpy((void*) req->path, path, path_len); \
+ memcpy((void*) req->new_path, new_path, new_path_len); \
+ } \
+ } \
+ while (0)
+
+#define POST \
+ do { \
+ if (cb != NULL) { \
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
+ return 0; \
+ } \
+ else { \
+ uv__fs_work(&req->work_req); \
+ return req->result; \
+ } \
+ } \
+ while (0)
+
+
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__) && defined(F_FULLFSYNC)
+ return fcntl(req->file, F_FULLFSYNC);
+#else
+ return fsync(req->file);
+#endif
+}
+
+
+static ssize_t uv__fs_futime(uv_fs_t* req) {
+#if defined(__linux__)
+ /* utimesat() has nanosecond resolution but we stick to microseconds
+ * for the sake of consistency with other platforms.
+ */
+ static int no_utimesat;
+ struct timespec ts[2];
+ struct timeval tv[2];
+ char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
+ int r;
+
+ if (no_utimesat)
+ goto skip;
+
+ ts[0].tv_sec = req->atime;
+ ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
+ ts[1].tv_sec = req->mtime;
+ ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
+
+ r = uv__utimesat(req->file, NULL, ts, 0);
+ if (r == 0)
+ return r;
+
+ if (errno != ENOSYS)
+ return r;
+
+ no_utimesat = 1;
+
+skip:
+
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
+
+ r = utimes(path, tv);
+ if (r == 0)
+ return r;
+
+ switch (errno) {
+ case ENOENT:
+ if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
+ break;
+ /* Fall through. */
+
+ case EACCES:
+ case ENOTDIR:
+ errno = ENOSYS;
+ break;
+ }
+
+ return r;
+
+#elif defined(__APPLE__) \
+ || defined(__DragonFly__) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__) \
+ || defined(__sun)
+ struct timeval tv[2];
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
+# if defined(__sun)
+ return futimesat(req->file, NULL, tv);
+# else
+ return futimes(req->file, tv);
+# endif
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+
+static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
+ return mkdtemp((char*) req->path) ? 0 : -1;
+}
+
+
+static ssize_t uv__fs_open(uv_fs_t* req) {
+ static int no_cloexec_support;
+ int r;
+
+ /* Try O_CLOEXEC before entering locks */
+ if (no_cloexec_support == 0) {
+#ifdef O_CLOEXEC
+ r = open(req->path, req->flags | O_CLOEXEC, req->mode);
+ if (r >= 0)
+ return r;
+ if (errno != EINVAL)
+ return r;
+ no_cloexec_support = 1;
+#endif /* O_CLOEXEC */
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdlock(&req->loop->cloexec_lock);
+
+ r = open(req->path, req->flags, req->mode);
+
+ /* In case of failure `uv__cloexec` will leave error in `errno`,
+ * so it is enough to just set `r` to `-1`.
+ */
+ if (r >= 0 && uv__cloexec(r, 1) != 0) {
+ r = uv__close(r);
+ if (r != 0 && r != -EINPROGRESS)
+ abort();
+ r = -1;
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdunlock(&req->loop->cloexec_lock);
+
+ return r;
+}
+
+
+static ssize_t uv__fs_read(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_preadv;
+#endif
+ ssize_t result;
+
+#if defined(_AIX)
+ struct stat buf;
+ if(fstat(req->file, &buf))
+ return -1;
+ if(S_ISDIR(buf.st_mode)) {
+ errno = EISDIR;
+ return -1;
+ }
+#endif /* defined(_AIX) */
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ result = read(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+
+#if HAVE_PREADV
+ result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_preadv) retry:
+# endif
+ {
+ off_t nread;
+ size_t index;
+
+ nread = 0;
+ index = 0;
+ result = 1;
+ do {
+ if (req->bufs[index].len > 0) {
+ result = pread(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + nread);
+ if (result > 0)
+ nread += result;
+ }
+ index++;
+ } while (index < req->nbufs && result > 0);
+ if (nread > 0)
+ result = nread;
+ }
+# if defined(__linux__)
+ else {
+ result = uv__preadv(req->file,
+ (struct iovec*)req->bufs,
+ req->nbufs,
+ req->off);
+ if (result == -1 && errno == ENOSYS) {
+ no_preadv = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+ return result;
+}
+
+
+#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
+static int uv__fs_scandir_filter(uv__dirent_t* dent) {
+#else
+static int uv__fs_scandir_filter(const uv__dirent_t* dent) {
+#endif
+ return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
+}
+
+
+static ssize_t uv__fs_scandir(uv_fs_t* req) {
+ uv__dirent_t **dents;
+ int saved_errno;
+ int n;
+
+ dents = NULL;
+ n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort);
+
+ /* NOTE: We will use nbufs as an index field */
+ req->nbufs = 0;
+
+ if (n == 0)
+ goto out; /* osx still needs to deallocate some memory */
+ else if (n == -1)
+ return n;
+
+ req->ptr = dents;
+
+ return n;
+
+out:
+ saved_errno = errno;
+ if (dents != NULL) {
+ int i;
+
+ for (i = 0; i < n; i++)
+ uv__free(dents[i]);
+ uv__free(dents);
+ }
+ errno = saved_errno;
+
+ req->ptr = NULL;
+
+ return n;
+}
+
+
+static ssize_t uv__fs_pathmax_size(const char* path) {
+ ssize_t pathmax;
+
+ pathmax = pathconf(path, _PC_PATH_MAX);
+
+ if (pathmax == -1) {
+#if defined(PATH_MAX)
+ return PATH_MAX;
+#else
+ return 4096;
+#endif
+ }
+
+ return pathmax;
+}
+
+static ssize_t uv__fs_readlink(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ len = readlink(req->path, buf, len);
+
+ if (len == -1) {
+ uv__free(buf);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_realpath(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (realpath(req->path, buf) == NULL) {
+ uv__free(buf);
+ return -1;
+ }
+
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
+ struct pollfd pfd;
+ int use_pread;
+ off_t offset;
+ ssize_t nsent;
+ ssize_t nread;
+ ssize_t nwritten;
+ size_t buflen;
+ size_t len;
+ ssize_t n;
+ int in_fd;
+ int out_fd;
+ char buf[8192];
+
+ len = req->bufsml[0].len;
+ in_fd = req->flags;
+ out_fd = req->file;
+ offset = req->off;
+ use_pread = 1;
+
+ /* Here are the rules regarding errors:
+ *
+ * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
+ * The user needs to know that some data has already been sent, to stop
+ * them from sending it twice.
+ *
+ * 2. Write errors are always reported. Write errors are bad because they
+ * mean data loss: we've read data but now we can't write it out.
+ *
+ * We try to use pread() and fall back to regular read() if the source fd
+ * doesn't support positional reads, for example when it's a pipe fd.
+ *
+ * If we get EAGAIN when writing to the target fd, we poll() on it until
+ * it becomes writable again.
+ *
+ * FIXME: If we get a write error when use_pread==1, it should be safe to
+ * return the number of sent bytes instead of an error because pread()
+ * is, in theory, idempotent. However, special files in /dev or /proc
+ * may support pread() but not necessarily return the same data on
+ * successive reads.
+ *
+ * FIXME: There is no way now to signal that we managed to send *some* data
+ * before a write error.
+ */
+ for (nsent = 0; (size_t) nsent < len; ) {
+ buflen = len - nsent;
+
+ if (buflen > sizeof(buf))
+ buflen = sizeof(buf);
+
+ do
+ if (use_pread)
+ nread = pread(in_fd, buf, buflen, offset);
+ else
+ nread = read(in_fd, buf, buflen);
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == 0)
+ goto out;
+
+ if (nread == -1) {
+ if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
+ use_pread = 0;
+ continue;
+ }
+
+ if (nsent == 0)
+ nsent = -1;
+
+ goto out;
+ }
+
+ for (nwritten = 0; nwritten < nread; ) {
+ do
+ n = write(out_fd, buf + nwritten, nread - nwritten);
+ while (n == -1 && errno == EINTR);
+
+ if (n != -1) {
+ nwritten += n;
+ continue;
+ }
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ nsent = -1;
+ goto out;
+ }
+
+ pfd.fd = out_fd;
+ pfd.events = POLLOUT;
+ pfd.revents = 0;
+
+ do
+ n = poll(&pfd, 1, -1);
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
+ errno = EIO;
+ nsent = -1;
+ goto out;
+ }
+ }
+
+ offset += nread;
+ nsent += nread;
+ }
+
+out:
+ if (nsent != -1)
+ req->off = offset;
+
+ return nsent;
+}
+
+
+static ssize_t uv__fs_sendfile(uv_fs_t* req) {
+ int in_fd;
+ int out_fd;
+
+ in_fd = req->flags;
+ out_fd = req->file;
+
+#if defined(__linux__) || defined(__sun)
+ {
+ off_t off;
+ ssize_t r;
+
+ off = req->off;
+ r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
+
+ /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
+ * it still writes out data. Fortunately, we can detect it by checking if
+ * the offset has been updated.
+ */
+ if (r != -1 || off > req->off) {
+ r = off - req->off;
+ req->off = off;
+ return r;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
+ {
+ off_t len;
+ ssize_t r;
+
+ /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
+ * non-blocking mode and not all data could be written. If a non-zero
+ * number of bytes have been sent, we don't consider it an error.
+ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ len = 0;
+ r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
+#else
+ /* The darwin sendfile takes len as an input for the length to send,
+ * so make sure to initialize it with the caller's value. */
+ len = req->bufsml[0].len;
+ r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
+#endif
+
+ /*
+ * The man page for sendfile(2) on DragonFly states that `len` contains
+ * a meaningful value ONLY in case of EAGAIN and EINTR.
+ * Nothing is said about it's value in case of other errors, so better
+ * not depend on the potential wrong assumption that is was not modified
+ * by the syscall.
+ */
+ if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
+ req->off += len;
+ return (ssize_t) len;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#else
+ /* Squelch compiler warnings. */
+ (void) &in_fd;
+ (void) &out_fd;
+
+ return uv__fs_sendfile_emul(req);
+#endif
+}
+
+
+static ssize_t uv__fs_utime(uv_fs_t* req) {
+ struct utimbuf buf;
+ buf.actime = req->atime;
+ buf.modtime = req->mtime;
+ return utime(req->path, &buf); /* TODO use utimes() where available */
+}
+
+
+static ssize_t uv__fs_write(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_pwritev;
+#endif
+ ssize_t r;
+
+ /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
+ * data loss. We can't use a per-file descriptor lock, the descriptor may be
+ * a dup().
+ */
+#if defined(__APPLE__)
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ if (pthread_mutex_lock(&lock))
+ abort();
+#endif
+
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ r = write(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+#if HAVE_PREADV
+ r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_pwritev) retry:
+# endif
+ {
+ off_t written;
+ size_t index;
+
+ written = 0;
+ index = 0;
+ r = 0;
+ do {
+ if (req->bufs[index].len > 0) {
+ r = pwrite(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + written);
+ if (r > 0)
+ written += r;
+ }
+ index++;
+ } while (index < req->nbufs && r >= 0);
+ if (written > 0)
+ r = written;
+ }
+# if defined(__linux__)
+ else {
+ r = uv__pwritev(req->file,
+ (struct iovec*) req->bufs,
+ req->nbufs,
+ req->off);
+ if (r == -1 && errno == ENOSYS) {
+ no_pwritev = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+#if defined(__APPLE__)
+ if (pthread_mutex_unlock(&lock))
+ abort();
+#endif
+
+ return r;
+}
+
+static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
+ dst->st_dev = src->st_dev;
+ dst->st_mode = src->st_mode;
+ dst->st_nlink = src->st_nlink;
+ dst->st_uid = src->st_uid;
+ dst->st_gid = src->st_gid;
+ dst->st_rdev = src->st_rdev;
+ dst->st_ino = src->st_ino;
+ dst->st_size = src->st_size;
+ dst->st_blksize = src->st_blksize;
+ dst->st_blocks = src->st_blocks;
+
+#if defined(__APPLE__)
+ dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
+ dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+#elif defined(__ANDROID__)
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = src->st_atime_nsec;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = src->st_mtime_nsec;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = src->st_ctime_nsec;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = src->st_ctime_nsec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#elif !defined(_AIX) && ( \
+ defined(_BSD_SOURCE) || \
+ defined(_SVID_SOURCE) || \
+ defined(_XOPEN_SOURCE) || \
+ defined(_DEFAULT_SOURCE))
+ dst->st_atim.tv_sec = src->st_atim.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
+# if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+ dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+# else
+ dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+# endif
+#else
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = 0;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = 0;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = 0;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = 0;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#endif
+}
+
+
+static int uv__fs_stat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = stat(path, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = lstat(path, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+static int uv__fs_fstat(int fd, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = fstat(fd, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
+static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
+ unsigned int iovmax;
+ unsigned int nbufs;
+ uv_buf_t* bufs;
+ ssize_t total;
+ ssize_t result;
+
+ iovmax = uv__getiovmax();
+ nbufs = req->nbufs;
+ bufs = req->bufs;
+ total = 0;
+
+ while (nbufs > 0) {
+ req->nbufs = nbufs;
+ if (req->nbufs > iovmax)
+ req->nbufs = iovmax;
+
+ result = process(req);
+ if (result <= 0) {
+ if (total == 0)
+ total = result;
+ break;
+ }
+
+ if (req->off >= 0)
+ req->off += result;
+
+ req->bufs += req->nbufs;
+ nbufs -= req->nbufs;
+ total += result;
+ }
+
+ if (bufs != req->bufsml)
+ uv__free(bufs);
+ req->bufs = NULL;
+
+ return total;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ int retry_on_eintr;
+ uv_fs_t* req;
+ ssize_t r;
+
+ req = container_of(w, uv_fs_t, work_req);
+ retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
+
+ do {
+ errno = 0;
+
+#define X(type, action) \
+ case UV_FS_ ## type: \
+ r = action; \
+ break;
+
+ switch (req->fs_type) {
+ X(ACCESS, access(req->path, req->flags));
+ X(CHMOD, chmod(req->path, req->mode));
+ X(CHOWN, chown(req->path, req->uid, req->gid));
+ X(CLOSE, close(req->file));
+ X(FCHMOD, fchmod(req->file, req->mode));
+ X(FCHOWN, fchown(req->file, req->uid, req->gid));
+ X(FDATASYNC, uv__fs_fdatasync(req));
+ X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
+ X(FSYNC, fsync(req->file));
+ X(FTRUNCATE, ftruncate(req->file, req->off));
+ X(FUTIME, uv__fs_futime(req));
+ X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
+ X(LINK, link(req->path, req->new_path));
+ X(MKDIR, mkdir(req->path, req->mode));
+ X(MKDTEMP, uv__fs_mkdtemp(req));
+ X(OPEN, uv__fs_open(req));
+ X(READ, uv__fs_buf_iter(req, uv__fs_read));
+ X(SCANDIR, uv__fs_scandir(req));
+ X(READLINK, uv__fs_readlink(req));
+ X(REALPATH, uv__fs_realpath(req));
+ X(RENAME, rename(req->path, req->new_path));
+ X(RMDIR, rmdir(req->path));
+ X(SENDFILE, uv__fs_sendfile(req));
+ X(STAT, uv__fs_stat(req->path, &req->statbuf));
+ X(SYMLINK, symlink(req->path, req->new_path));
+ X(UNLINK, unlink(req->path));
+ X(UTIME, uv__fs_utime(req));
+ X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
+ default: abort();
+ }
+#undef X
+ } while (r == -1 && errno == EINTR && retry_on_eintr);
+
+ if (r == -1)
+ req->result = -errno;
+ else
+ req->result = r;
+
+ if (r == 0 && (req->fs_type == UV_FS_STAT ||
+ req->fs_type == UV_FS_FSTAT ||
+ req->fs_type == UV_FS_LSTAT)) {
+ req->ptr = &req->statbuf;
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == -ECANCELED) {
+ assert(req->result == 0);
+ req->result = -ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(ACCESS);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(CHMOD);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(CHOWN);
+ PATH;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(CLOSE);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(FCHMOD);
+ req->file = file;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(FCHOWN);
+ req->file = file;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FDATASYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSTAT);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t off,
+ uv_fs_cb cb) {
+ INIT(FTRUNCATE);
+ req->file = file;
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(FUTIME);
+ req->file = file;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(LSTAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(LINK);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(MKDIR);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb) {
+ INIT(MKDTEMP);
+ req->path = uv__strdup(tpl);
+ if (req->path == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+ POST;
+}
+
+
+int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(OPEN);
+ PATH;
+ req->flags = flags;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(READ);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SCANDIR);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb) {
+ INIT(READLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char * path,
+ uv_fs_cb cb) {
+ INIT(REALPATH);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(RENAME);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(RMDIR);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t off,
+ size_t len,
+ uv_fs_cb cb) {
+ INIT(SENDFILE);
+ req->flags = in_fd; /* hack */
+ req->file = out_fd;
+ req->off = off;
+ req->bufsml[0].len = len;
+ POST;
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(STAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SYMLINK);
+ PATH2;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(UNLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(UTIME);
+ PATH;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(WRITE);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ /* Only necessary for asychronous requests, i.e., requests with a callback.
+ * Synchronous ones don't copy their arguments and have req->path and
+ * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
+ * exception to the rule, it always allocates memory.
+ */
+ if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
+ uv__free((void*) req->path); /* Memory is shared with req->new_path. */
+
+ req->path = NULL;
+ req->new_path = NULL;
+
+ if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
+ uv__fs_scandir_cleanup(req);
+
+ if (req->ptr != &req->statbuf)
+ uv__free(req->ptr);
+ req->ptr = NULL;
+}
diff --git a/3rdparty/libuv/src/unix/fsevents.c b/3rdparty/libuv/src/unix/fsevents.c
new file mode 100644
index 00000000000..d331a131726
--- /dev/null
+++ b/3rdparty/libuv/src/unix/fsevents.c
@@ -0,0 +1,904 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#if TARGET_OS_IPHONE
+
+/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
+
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+}
+
+#else /* TARGET_OS_IPHONE */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreServices/CoreServices.h>
+
+/* These are macros to avoid "initializer element is not constant" errors
+ * with old versions of gcc.
+ */
+#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
+ kFSEventStreamEventFlagItemModified | \
+ kFSEventStreamEventFlagItemInodeMetaMod | \
+ kFSEventStreamEventFlagItemChangeOwner | \
+ kFSEventStreamEventFlagItemXattrMod)
+
+#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
+ kFSEventStreamEventFlagItemRemoved | \
+ kFSEventStreamEventFlagItemRenamed)
+
+#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
+ kFSEventStreamEventFlagKernelDropped | \
+ kFSEventStreamEventFlagEventIdsWrapped | \
+ kFSEventStreamEventFlagHistoryDone | \
+ kFSEventStreamEventFlagMount | \
+ kFSEventStreamEventFlagUnmount | \
+ kFSEventStreamEventFlagRootChanged)
+
+typedef struct uv__fsevents_event_s uv__fsevents_event_t;
+typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
+typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
+
+enum uv__cf_loop_signal_type_e {
+ kUVCFLoopSignalRegular,
+ kUVCFLoopSignalClosing
+};
+typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
+
+struct uv__cf_loop_signal_s {
+ QUEUE member;
+ uv_fs_event_t* handle;
+ uv__cf_loop_signal_type_t type;
+};
+
+struct uv__fsevents_event_s {
+ QUEUE member;
+ int events;
+ char path[1];
+};
+
+struct uv__cf_loop_state_s {
+ CFRunLoopRef loop;
+ CFRunLoopSourceRef signal_source;
+ int fsevent_need_reschedule;
+ FSEventStreamRef fsevent_stream;
+ uv_sem_t fsevent_sem;
+ uv_mutex_t fsevent_mutex;
+ void* fsevent_handles[2];
+ unsigned int fsevent_handle_count;
+};
+
+/* Forward declarations */
+static void uv__cf_loop_cb(void* arg);
+static void* uv__cf_loop_runner(void* arg);
+static int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type);
+
+/* Lazy-loaded by uv__fsevents_global_init(). */
+static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
+ const void**,
+ CFIndex,
+ const CFArrayCallBacks*);
+static void (*pCFRelease)(CFTypeRef);
+static void (*pCFRunLoopAddSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
+static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static void (*pCFRunLoopRun)(void);
+static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
+ CFIndex,
+ CFRunLoopSourceContext*);
+static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
+static void (*pCFRunLoopStop)(CFRunLoopRef);
+static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
+static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
+ CFAllocatorRef,
+ const char*);
+static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
+static CFStringRef (*pkCFRunLoopDefaultMode);
+static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
+ FSEventStreamCallback,
+ FSEventStreamContext*,
+ CFArrayRef,
+ FSEventStreamEventId,
+ CFTimeInterval,
+ FSEventStreamCreateFlags);
+static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
+static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
+static void (*pFSEventStreamRelease)(FSEventStreamRef);
+static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
+ CFRunLoopRef,
+ CFStringRef);
+static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
+static void (*pFSEventStreamStop)(FSEventStreamRef);
+
+#define UV__FSEVENTS_PROCESS(handle, block) \
+ do { \
+ QUEUE events; \
+ QUEUE* q; \
+ uv__fsevents_event_t* event; \
+ int err; \
+ uv_mutex_lock(&(handle)->cf_mutex); \
+ /* Split-off all events and empty original queue */ \
+ QUEUE_MOVE(&(handle)->cf_events, &events); \
+ /* Get error (if any) and zero original one */ \
+ err = (handle)->cf_error; \
+ (handle)->cf_error = 0; \
+ uv_mutex_unlock(&(handle)->cf_mutex); \
+ /* Loop through events, deallocating each after processing */ \
+ while (!QUEUE_EMPTY(&events)) { \
+ q = QUEUE_HEAD(&events); \
+ event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
+ QUEUE_REMOVE(q); \
+ /* NOTE: Checking uv__is_active() is required here, because handle \
+ * callback may close handle and invoking it after it will lead to \
+ * incorrect behaviour */ \
+ if (!uv__is_closing((handle)) && uv__is_active((handle))) \
+ block \
+ /* Free allocated data */ \
+ uv__free(event); \
+ } \
+ if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
+ (handle)->cb((handle), NULL, 0, err); \
+ } while (0)
+
+
+/* Runs in UV loop's thread, when there're events to report to handle */
+static void uv__fsevents_cb(uv_async_t* cb) {
+ uv_fs_event_t* handle;
+
+ handle = cb->data;
+
+ UV__FSEVENTS_PROCESS(handle, {
+ handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
+ });
+}
+
+
+/* Runs in CF thread, pushed event into handle's event list */
+static void uv__fsevents_push_event(uv_fs_event_t* handle,
+ QUEUE* events,
+ int err) {
+ assert(events != NULL || err != 0);
+ uv_mutex_lock(&handle->cf_mutex);
+
+ /* Concatenate two queues */
+ if (events != NULL)
+ QUEUE_ADD(&handle->cf_events, events);
+
+ /* Propagate error */
+ if (err != 0)
+ handle->cf_error = err;
+ uv_mutex_unlock(&handle->cf_mutex);
+
+ uv_async_send(handle->cf_cb);
+}
+
+
+/* Runs in CF thread, when there're events in FSEventStream */
+static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
+ void* info,
+ size_t numEvents,
+ void* eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]) {
+ size_t i;
+ int len;
+ char** paths;
+ char* path;
+ char* pos;
+ uv_fs_event_t* handle;
+ QUEUE* q;
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ uv__fsevents_event_t* event;
+ QUEUE head;
+
+ loop = info;
+ state = loop->cf_state;
+ assert(state != NULL);
+ paths = eventPaths;
+
+ /* For each handle */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ QUEUE_INIT(&head);
+
+ /* Process and filter out events */
+ for (i = 0; i < numEvents; i++) {
+ /* Ignore system events */
+ if (eventFlags[i] & kFSEventsSystem)
+ continue;
+
+ path = paths[i];
+ len = strlen(path);
+
+ /* Filter out paths that are outside handle's request */
+ if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
+ continue;
+
+ if (handle->realpath_len > 1 || *handle->realpath != '/') {
+ path += handle->realpath_len;
+ len -= handle->realpath_len;
+
+ /* Skip forward slash */
+ if (*path != '\0') {
+ path++;
+ len--;
+ }
+ }
+
+#ifdef MAC_OS_X_VERSION_10_7
+ /* Ignore events with path equal to directory itself */
+ if (len == 0)
+ continue;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ /* Do not emit events from subdirectories (without option set) */
+ if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
+ pos = strchr(path + 1, '/');
+ if (pos != NULL)
+ continue;
+ }
+
+#ifndef MAC_OS_X_VERSION_10_7
+ path = "";
+ len = 0;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ event = uv__malloc(sizeof(*event) + len);
+ if (event == NULL)
+ break;
+
+ memset(event, 0, sizeof(*event));
+ memcpy(event->path, path, len + 1);
+
+ if ((eventFlags[i] & kFSEventsModified) != 0 &&
+ (eventFlags[i] & kFSEventsRenamed) == 0)
+ event->events = UV_CHANGE;
+ else
+ event->events = UV_RENAME;
+
+ QUEUE_INSERT_TAIL(&head, &event->member);
+ }
+
+ if (!QUEUE_EMPTY(&head))
+ uv__fsevents_push_event(handle, &head, 0);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+}
+
+
+/* Runs in CF thread */
+static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
+ uv__cf_loop_state_t* state;
+ FSEventStreamContext ctx;
+ FSEventStreamRef ref;
+ CFAbsoluteTime latency;
+ FSEventStreamCreateFlags flags;
+
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = loop;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ latency = 0.05;
+
+ /* Explanation of selected flags:
+ * 1. NoDefer - without this flag, events that are happening continuously
+ * (i.e. each event is happening after time interval less than `latency`,
+ * counted from previous event), will be deferred and passed to callback
+ * once they'll either fill whole OS buffer, or when this continuous stream
+ * will stop (i.e. there'll be delay between events, bigger than
+ * `latency`).
+ * Specifying this flag will invoke callback after `latency` time passed
+ * since event.
+ * 2. FileEvents - fire callback for file changes too (by default it is firing
+ * it only for directory changes).
+ */
+ flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
+
+ /*
+ * NOTE: It might sound like a good idea to remember last seen StreamEventId,
+ * but in reality one dir might have last StreamEventId less than, the other,
+ * that is being watched now. Which will cause FSEventStream API to report
+ * changes to files from the past.
+ */
+ ref = pFSEventStreamCreate(NULL,
+ &uv__fsevents_event_cb,
+ &ctx,
+ paths,
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ flags);
+ assert(ref != NULL);
+
+ state = loop->cf_state;
+ pFSEventStreamScheduleWithRunLoop(ref,
+ state->loop,
+ *pkCFRunLoopDefaultMode);
+ if (!pFSEventStreamStart(ref)) {
+ pFSEventStreamInvalidate(ref);
+ pFSEventStreamRelease(ref);
+ return -EMFILE;
+ }
+
+ state->fsevent_stream = ref;
+ return 0;
+}
+
+
+/* Runs in CF thread */
+static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
+ uv__cf_loop_state_t* state;
+
+ state = loop->cf_state;
+
+ if (state->fsevent_stream == NULL)
+ return;
+
+ /* Flush all accumulated events */
+ pFSEventStreamFlushSync(state->fsevent_stream);
+
+ /* Stop emitting events */
+ pFSEventStreamStop(state->fsevent_stream);
+
+ /* Release stream */
+ pFSEventStreamInvalidate(state->fsevent_stream);
+ pFSEventStreamRelease(state->fsevent_stream);
+ state->fsevent_stream = NULL;
+}
+
+
+/* Runs in CF thread, when there're new fsevent handles to add to stream */
+static void uv__fsevents_reschedule(uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+ uv_fs_event_t* curr;
+ CFArrayRef cf_paths;
+ CFStringRef* paths;
+ unsigned int i;
+ int err;
+ unsigned int path_count;
+
+ state = handle->loop->cf_state;
+ paths = NULL;
+ cf_paths = NULL;
+ err = 0;
+ /* NOTE: `i` is used in deallocation loop below */
+ i = 0;
+
+ /* Optimization to prevent O(n^2) time spent when starting to watch
+ * many files simultaneously
+ */
+ uv_mutex_lock(&state->fsevent_mutex);
+ if (state->fsevent_need_reschedule == 0) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ state->fsevent_need_reschedule = 0;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Destroy previous FSEventStream */
+ uv__fsevents_destroy_stream(handle->loop);
+
+ /* Any failure below will be a memory failure */
+ err = -ENOMEM;
+
+ /* Create list of all watched paths */
+ uv_mutex_lock(&state->fsevent_mutex);
+ path_count = state->fsevent_handle_count;
+ if (path_count != 0) {
+ paths = uv__malloc(sizeof(*paths) * path_count);
+ if (paths == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+
+ q = &state->fsevent_handles;
+ for (; i < path_count; i++) {
+ q = QUEUE_NEXT(q);
+ assert(q != &state->fsevent_handles);
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+
+ assert(curr->realpath != NULL);
+ paths[i] =
+ pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
+ if (paths[i] == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ }
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ err = 0;
+
+ if (path_count != 0) {
+ /* Create new FSEventStream */
+ cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
+ if (cf_paths == NULL) {
+ err = -ENOMEM;
+ goto final;
+ }
+ err = uv__fsevents_create_stream(handle->loop, cf_paths);
+ }
+
+final:
+ /* Deallocate all paths in case of failure */
+ if (err != 0) {
+ if (cf_paths == NULL) {
+ while (i != 0)
+ pCFRelease(paths[--i]);
+ uv__free(paths);
+ } else {
+ /* CFArray takes ownership of both strings and original C-array */
+ pCFRelease(cf_paths);
+ }
+
+ /* Broadcast error to all handles */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ uv__fsevents_push_event(curr, NULL, err);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ }
+
+ /*
+ * Main thread will block until the removal of handle from the list,
+ * we must tell it when we're ready.
+ *
+ * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
+ */
+ if (type == kUVCFLoopSignalClosing)
+ uv_sem_post(&state->fsevent_sem);
+}
+
+
+static int uv__fsevents_global_init(void) {
+ static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static void* core_foundation_handle;
+ static void* core_services_handle;
+ int err;
+
+ err = 0;
+ pthread_mutex_lock(&global_init_mutex);
+ if (core_foundation_handle != NULL)
+ goto out;
+
+ /* The libraries are never unloaded because we currently don't have a good
+ * mechanism for keeping a reference count. It's unlikely to be an issue
+ * but if it ever becomes one, we can turn the dynamic library handles into
+ * per-event loop properties and have the dynamic linker keep track for us.
+ */
+ err = -ENOSYS;
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_foundation_handle == NULL)
+ goto out;
+
+ core_services_handle = dlopen("/System/Library/Frameworks/"
+ "CoreServices.framework/"
+ "Versions/A/CoreServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_services_handle == NULL)
+ goto out;
+
+ err = -ENOENT;
+#define V(handle, symbol) \
+ do { \
+ *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
+ if (p ## symbol == NULL) \
+ goto out; \
+ } \
+ while (0)
+ V(core_foundation_handle, CFArrayCreate);
+ V(core_foundation_handle, CFRelease);
+ V(core_foundation_handle, CFRunLoopAddSource);
+ V(core_foundation_handle, CFRunLoopGetCurrent);
+ V(core_foundation_handle, CFRunLoopRemoveSource);
+ V(core_foundation_handle, CFRunLoopRun);
+ V(core_foundation_handle, CFRunLoopSourceCreate);
+ V(core_foundation_handle, CFRunLoopSourceSignal);
+ V(core_foundation_handle, CFRunLoopStop);
+ V(core_foundation_handle, CFRunLoopWakeUp);
+ V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
+ V(core_foundation_handle, CFStringGetSystemEncoding);
+ V(core_foundation_handle, kCFRunLoopDefaultMode);
+ V(core_services_handle, FSEventStreamCreate);
+ V(core_services_handle, FSEventStreamFlushSync);
+ V(core_services_handle, FSEventStreamInvalidate);
+ V(core_services_handle, FSEventStreamRelease);
+ V(core_services_handle, FSEventStreamScheduleWithRunLoop);
+ V(core_services_handle, FSEventStreamStart);
+ V(core_services_handle, FSEventStreamStop);
+#undef V
+ err = 0;
+
+out:
+ if (err && core_services_handle != NULL) {
+ dlclose(core_services_handle);
+ core_services_handle = NULL;
+ }
+
+ if (err && core_foundation_handle != NULL) {
+ dlclose(core_foundation_handle);
+ core_foundation_handle = NULL;
+ }
+
+ pthread_mutex_unlock(&global_init_mutex);
+ return err;
+}
+
+
+/* Runs in UV loop */
+static int uv__fsevents_loop_init(uv_loop_t* loop) {
+ CFRunLoopSourceContext ctx;
+ uv__cf_loop_state_t* state;
+ pthread_attr_t attr_storage;
+ pthread_attr_t* attr;
+ int err;
+
+ if (loop->cf_state != NULL)
+ return 0;
+
+ err = uv__fsevents_global_init();
+ if (err)
+ return err;
+
+ state = uv__calloc(1, sizeof(*state));
+ if (state == NULL)
+ return -ENOMEM;
+
+ err = uv_mutex_init(&loop->cf_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_sem_init(&loop->cf_sem, 0);
+ if (err)
+ goto fail_sem_init;
+
+ QUEUE_INIT(&loop->cf_signals);
+
+ err = uv_sem_init(&state->fsevent_sem, 0);
+ if (err)
+ goto fail_fsevent_sem_init;
+
+ err = uv_mutex_init(&state->fsevent_mutex);
+ if (err)
+ goto fail_fsevent_mutex_init;
+
+ QUEUE_INIT(&state->fsevent_handles);
+ state->fsevent_need_reschedule = 0;
+ state->fsevent_handle_count = 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.info = loop;
+ ctx.perform = uv__cf_loop_cb;
+ state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
+ if (state->signal_source == NULL) {
+ err = -ENOMEM;
+ goto fail_signal_source_create;
+ }
+
+ /* In the unlikely event that pthread_attr_init() fails, create the thread
+ * with the default stack size. We'll use a little more address space but
+ * that in itself is not a fatal error.
+ */
+ attr = &attr_storage;
+ if (pthread_attr_init(attr))
+ attr = NULL;
+
+ if (attr != NULL)
+ if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
+ abort();
+
+ loop->cf_state = state;
+
+ /* uv_thread_t is an alias for pthread_t. */
+ err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
+
+ if (attr != NULL)
+ pthread_attr_destroy(attr);
+
+ if (err)
+ goto fail_thread_create;
+
+ /* Synchronize threads */
+ uv_sem_wait(&loop->cf_sem);
+ return 0;
+
+fail_thread_create:
+ loop->cf_state = NULL;
+
+fail_signal_source_create:
+ uv_mutex_destroy(&state->fsevent_mutex);
+
+fail_fsevent_mutex_init:
+ uv_sem_destroy(&state->fsevent_sem);
+
+fail_fsevent_sem_init:
+ uv_sem_destroy(&loop->cf_sem);
+
+fail_sem_init:
+ uv_mutex_destroy(&loop->cf_mutex);
+
+fail_mutex_init:
+ uv__free(state);
+ return err;
+}
+
+
+/* Runs in UV loop */
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+ uv__cf_loop_signal_t* s;
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+
+ if (loop->cf_state == NULL)
+ return;
+
+ if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
+ abort();
+
+ uv_thread_join(&loop->cf_thread);
+ uv_sem_destroy(&loop->cf_sem);
+ uv_mutex_destroy(&loop->cf_mutex);
+
+ /* Free any remaining data */
+ while (!QUEUE_EMPTY(&loop->cf_signals)) {
+ q = QUEUE_HEAD(&loop->cf_signals);
+ s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
+ QUEUE_REMOVE(q);
+ uv__free(s);
+ }
+
+ /* Destroy state */
+ state = loop->cf_state;
+ uv_sem_destroy(&state->fsevent_sem);
+ uv_mutex_destroy(&state->fsevent_mutex);
+ pCFRelease(state->signal_source);
+ uv__free(state);
+ loop->cf_state = NULL;
+}
+
+
+/* Runs in CF thread. This is the CF loop's body */
+static void* uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+
+ loop = arg;
+ state = loop->cf_state;
+ state->loop = pCFRunLoopGetCurrent();
+
+ pCFRunLoopAddSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ uv_sem_post(&loop->cf_sem);
+
+ pCFRunLoopRun();
+ pCFRunLoopRemoveSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ return NULL;
+}
+
+
+/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
+static void uv__cf_loop_cb(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ QUEUE* item;
+ QUEUE split_head;
+ uv__cf_loop_signal_t* s;
+
+ loop = arg;
+ state = loop->cf_state;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_MOVE(&loop->cf_signals, &split_head);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ while (!QUEUE_EMPTY(&split_head)) {
+ item = QUEUE_HEAD(&split_head);
+ QUEUE_REMOVE(item);
+
+ s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
+
+ /* This was a termination signal */
+ if (s->handle == NULL)
+ pCFRunLoopStop(state->loop);
+ else
+ uv__fsevents_reschedule(s->handle, s->type);
+
+ uv__free(s);
+ }
+}
+
+
+/* Runs in UV loop to notify CF thread */
+int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_signal_t* item;
+ uv__cf_loop_state_t* state;
+
+ item = uv__malloc(sizeof(*item));
+ if (item == NULL)
+ return -ENOMEM;
+
+ item->handle = handle;
+ item->type = type;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ state = loop->cf_state;
+ assert(state != NULL);
+ pCFRunLoopSourceSignal(state->signal_source);
+ pCFRunLoopWakeUp(state->loop);
+
+ return 0;
+}
+
+
+/* Runs in UV loop to initialize handle */
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ err = uv__fsevents_loop_init(handle->loop);
+ if (err)
+ return err;
+
+ /* Get absolute path to file */
+ handle->realpath = realpath(handle->path, NULL);
+ if (handle->realpath == NULL)
+ return -errno;
+ handle->realpath_len = strlen(handle->realpath);
+
+ /* Initialize event queue */
+ QUEUE_INIT(&handle->cf_events);
+ handle->cf_error = 0;
+
+ /*
+ * Events will occur in other thread.
+ * Initialize callback for getting them back into event loop's thread
+ */
+ handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
+ if (handle->cf_cb == NULL) {
+ err = -ENOMEM;
+ goto fail_cf_cb_malloc;
+ }
+
+ handle->cf_cb->data = handle;
+ uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
+ handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
+ uv_unref((uv_handle_t*) handle->cf_cb);
+
+ err = uv_mutex_init(&handle->cf_mutex);
+ if (err)
+ goto fail_cf_mutex_init;
+
+ /* Insert handle into the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
+ state->fsevent_handle_count++;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
+ if (err)
+ goto fail_loop_signal;
+
+ return 0;
+
+fail_loop_signal:
+ uv_mutex_destroy(&handle->cf_mutex);
+
+fail_cf_mutex_init:
+ uv__free(handle->cf_cb);
+ handle->cf_cb = NULL;
+
+fail_cf_cb_malloc:
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return err;
+}
+
+
+/* Runs in UV loop to de-initialize handle */
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ if (handle->cf_cb == NULL)
+ return -EINVAL;
+
+ /* Remove handle from the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_REMOVE(&handle->cf_member);
+ state->fsevent_handle_count--;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
+ if (err)
+ return -err;
+
+ /* Wait for deinitialization */
+ uv_sem_wait(&state->fsevent_sem);
+
+ uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
+ handle->cf_cb = NULL;
+
+ /* Free data in queue */
+ UV__FSEVENTS_PROCESS(handle, {
+ /* NOP */
+ });
+
+ uv_mutex_destroy(&handle->cf_mutex);
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return 0;
+}
+
+#endif /* TARGET_OS_IPHONE */
diff --git a/3rdparty/libuv/src/unix/getaddrinfo.c b/3rdparty/libuv/src/unix/getaddrinfo.c
new file mode 100644
index 00000000000..2049aea2f38
--- /dev/null
+++ b/3rdparty/libuv/src/unix/getaddrinfo.c
@@ -0,0 +1,202 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
+ * include any headers.
+ */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h>
+#include <string.h>
+
+/* EAI_* constants. */
+#include <netdb.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
+#endif
+#if defined(EAI_AGAIN)
+ case EAI_AGAIN: return UV_EAI_AGAIN;
+#endif
+#if defined(EAI_BADFLAGS)
+ case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
+#endif
+#if defined(EAI_BADHINTS)
+ case EAI_BADHINTS: return UV_EAI_BADHINTS;
+#endif
+#if defined(EAI_CANCELED)
+ case EAI_CANCELED: return UV_EAI_CANCELED;
+#endif
+#if defined(EAI_FAIL)
+ case EAI_FAIL: return UV_EAI_FAIL;
+#endif
+#if defined(EAI_FAMILY)
+ case EAI_FAMILY: return UV_EAI_FAMILY;
+#endif
+#if defined(EAI_MEMORY)
+ case EAI_MEMORY: return UV_EAI_MEMORY;
+#endif
+#if defined(EAI_NODATA)
+ case EAI_NODATA: return UV_EAI_NODATA;
+#endif
+#if defined(EAI_NONAME)
+# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
+ case EAI_NONAME: return UV_EAI_NONAME;
+# endif
+#endif
+#if defined(EAI_OVERFLOW)
+ case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
+#endif
+#if defined(EAI_PROTOCOL)
+ case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
+#endif
+#if defined(EAI_SERVICE)
+ case EAI_SERVICE: return UV_EAI_SERVICE;
+#endif
+#if defined(EAI_SOCKTYPE)
+ case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
+#endif
+#if defined(EAI_SYSTEM)
+ case EAI_SYSTEM: return -errno;
+#endif
+ }
+ assert(!"unknown EAI_* error code");
+ abort();
+ return 0; /* Pacify compiler. */
+}
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ /* See initialization in uv_getaddrinfo(). */
+ if (req->hints)
+ uv__free(req->hints);
+ else if (req->service)
+ uv__free(req->service);
+ else if (req->hostname)
+ uv__free(req->hostname);
+ else
+ assert(0);
+
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ }
+
+ if (req->cb)
+ req->cb(req, req->retcode, req->addrinfo);
+}
+
+
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb cb,
+ const char* hostname,
+ const char* service,
+ const struct addrinfo* hints) {
+ size_t hostname_len;
+ size_t service_len;
+ size_t hints_len;
+ size_t len;
+ char* buf;
+
+ if (req == NULL || (hostname == NULL && service == NULL))
+ return -EINVAL;
+
+ hostname_len = hostname ? strlen(hostname) + 1 : 0;
+ service_len = service ? strlen(service) + 1 : 0;
+ hints_len = hints ? sizeof(*hints) : 0;
+ buf = uv__malloc(hostname_len + service_len + hints_len);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ uv__req_init(loop, req, UV_GETADDRINFO);
+ req->loop = loop;
+ req->cb = cb;
+ req->addrinfo = NULL;
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+ req->retcode = 0;
+
+ /* order matters, see uv_getaddrinfo_done() */
+ len = 0;
+
+ if (hints) {
+ req->hints = memcpy(buf + len, hints, sizeof(*hints));
+ len += sizeof(*hints);
+ }
+
+ if (service) {
+ req->service = memcpy(buf + len, service, service_len);
+ len += service_len;
+ }
+
+ if (hostname)
+ req->hostname = memcpy(buf + len, hostname, hostname_len);
+
+ if (cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ if (ai)
+ freeaddrinfo(ai);
+}
diff --git a/3rdparty/libuv/src/unix/getnameinfo.c b/3rdparty/libuv/src/unix/getnameinfo.c
new file mode 100644
index 00000000000..daa798a450e
--- /dev/null
+++ b/3rdparty/libuv/src/unix/getnameinfo.c
@@ -0,0 +1,120 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ int err;
+ socklen_t salen;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+
+ if (req->storage.ss_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ else if (req->storage.ss_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+ else
+ abort();
+
+ err = getnameinfo((struct sockaddr*) &req->storage,
+ salen,
+ req->host,
+ sizeof(req->host),
+ req->service,
+ sizeof(req->service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/3rdparty/libuv/src/unix/internal.h b/3rdparty/libuv/src/unix/internal.h
new file mode 100644
index 00000000000..741fa57d69c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/internal.h
@@ -0,0 +1,316 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_INTERNAL_H_
+#define UV_UNIX_INTERNAL_H_
+
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h> /* abort */
+#include <string.h> /* strrchr */
+#include <fcntl.h> /* O_CLOEXEC, may be */
+
+#if defined(__STRICT_ANSI__)
+# define inline __inline
+#endif
+
+#if defined(__linux__)
+# include "linux-syscalls.h"
+#endif /* __linux__ */
+
+#if defined(__sun)
+# include <sys/port.h>
+# include <port.h>
+#endif /* __sun */
+
+#if defined(_AIX)
+#define reqevents events
+#define rtnevents revents
+#include <sys/poll.h>
+#endif /* _AIX */
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <CoreServices/CoreServices.h>
+#endif
+
+#define ACCESS_ONCE(type, var) \
+ (*(volatile type*) &(var))
+
+#define ROUND_UP(a, b) \
+ ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
+
+#define UNREACHABLE() \
+ do { \
+ assert(0 && "unreachable code"); \
+ abort(); \
+ } \
+ while (0)
+
+#define SAVE_ERRNO(block) \
+ do { \
+ int _saved_errno = errno; \
+ do { block; } while (0); \
+ errno = _saved_errno; \
+ } \
+ while (0)
+
+/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
+ * define __GNUC__. They are here to convey to you, dear reader, that these
+ * macros are enabled when compiling with clang or icc.
+ */
+#if defined(__clang__) || \
+ defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || \
+ defined(__SUNPRO_C)
+# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
+# define UV_UNUSED(declaration) __attribute__((unused)) declaration
+#else
+# define UV_DESTRUCTOR(declaration) declaration
+# define UV_UNUSED(declaration) declaration
+#endif
+
+#if defined(__linux__)
+# define UV__POLLIN UV__EPOLLIN
+# define UV__POLLOUT UV__EPOLLOUT
+# define UV__POLLERR UV__EPOLLERR
+# define UV__POLLHUP UV__EPOLLHUP
+#endif
+
+#if defined(__sun) || defined(_AIX)
+# define UV__POLLIN POLLIN
+# define UV__POLLOUT POLLOUT
+# define UV__POLLERR POLLERR
+# define UV__POLLHUP POLLHUP
+#endif
+
+#ifndef UV__POLLIN
+# define UV__POLLIN 1
+#endif
+
+#ifndef UV__POLLOUT
+# define UV__POLLOUT 2
+#endif
+
+#ifndef UV__POLLERR
+# define UV__POLLERR 4
+#endif
+
+#ifndef UV__POLLHUP
+# define UV__POLLHUP 8
+#endif
+
+#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
+/*
+ * It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
+ * Try using fixed value const and give up, if it doesn't work
+ */
+# define O_CLOEXEC 0x00100000
+#endif
+
+typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
+
+/* handle flags */
+enum {
+ UV_CLOSING = 0x01, /* uv_close() called but not finished. */
+ UV_CLOSED = 0x02, /* close(2) finished. */
+ UV_STREAM_READING = 0x04, /* uv_read_start() called. */
+ UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
+ UV_STREAM_SHUT = 0x10, /* Write side closed. */
+ UV_STREAM_READABLE = 0x20, /* The stream is readable */
+ UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
+ UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
+ UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
+ UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
+ UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
+ UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
+ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
+ UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
+ UV_UDP_PROCESSING = 0x20000 /* Handle is running the send callback queue. */
+};
+
+/* loop flags */
+enum {
+ UV_LOOP_BLOCK_SIGPROF = 1
+};
+
+typedef enum {
+ UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
+ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
+} uv_clocktype_t;
+
+struct uv__stream_queued_fds_s {
+ unsigned int size;
+ unsigned int offset;
+ int fds[1];
+};
+
+
+/* core */
+int uv__nonblock(int fd, int set);
+int uv__close(int fd);
+int uv__cloexec(int fd, int set);
+int uv__socket(int domain, int type, int protocol);
+int uv__dup(int fd);
+ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
+void uv__make_close_pending(uv_handle_t* handle);
+int uv__getiovmax(void);
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_close(uv_loop_t* loop, uv__io_t* w);
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
+int uv__io_active(const uv__io_t* w, unsigned int events);
+void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
+
+/* async */
+void uv__async_send(struct uv__async* wa);
+void uv__async_init(struct uv__async* wa);
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
+
+/* loop */
+void uv__run_idle(uv_loop_t* loop);
+void uv__run_check(uv_loop_t* loop);
+void uv__run_prepare(uv_loop_t* loop);
+
+/* stream */
+void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
+ uv_handle_type type);
+int uv__stream_open(uv_stream_t*, int fd, int flags);
+void uv__stream_destroy(uv_stream_t* stream);
+#if defined(__APPLE__)
+int uv__stream_try_select(uv_stream_t* stream, int* fd);
+#endif /* defined(__APPLE__) */
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+int uv__accept(int sockfd);
+int uv__dup2_cloexec(int oldfd, int newfd);
+int uv__open_cloexec(const char* path, int flags);
+
+/* tcp */
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
+int uv__tcp_nodelay(int fd, int on);
+int uv__tcp_keepalive(int fd, int on, unsigned int delay);
+
+/* pipe */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+
+/* timer */
+void uv__run_timers(uv_loop_t* loop);
+int uv__next_timeout(const uv_loop_t* loop);
+
+/* signal */
+void uv__signal_close(uv_signal_t* handle);
+void uv__signal_global_once_init(void);
+void uv__signal_loop_cleanup(uv_loop_t* loop);
+
+/* platform specific */
+uint64_t uv__hrtime(uv_clocktype_t type);
+int uv__kqueue_init(uv_loop_t* loop);
+int uv__platform_loop_init(uv_loop_t* loop);
+void uv__platform_loop_delete(uv_loop_t* loop);
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
+
+/* various */
+void uv__async_close(uv_async_t* handle);
+void uv__check_close(uv_check_t* handle);
+void uv__fs_event_close(uv_fs_event_t* handle);
+void uv__idle_close(uv_idle_t* handle);
+void uv__pipe_close(uv_pipe_t* handle);
+void uv__poll_close(uv_poll_t* handle);
+void uv__prepare_close(uv_prepare_t* handle);
+void uv__process_close(uv_process_t* handle);
+void uv__stream_close(uv_stream_t* handle);
+void uv__tcp_close(uv_tcp_t* handle);
+void uv__timer_close(uv_timer_t* handle);
+void uv__udp_close(uv_udp_t* handle);
+void uv__udp_finish_close(uv_udp_t* handle);
+uv_handle_type uv__handle_type(int fd);
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle);
+#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
+#else
+#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
+#endif /* defined(__APPLE__) */
+
+#ifdef UV__O_NONBLOCK
+# define UV__F_NONBLOCK UV__O_NONBLOCK
+#else
+# define UV__F_NONBLOCK 1
+#endif
+
+int uv__make_socketpair(int fds[2], int flags);
+int uv__make_pipe(int fds[2], int flags);
+
+#if defined(__APPLE__)
+
+int uv__fsevents_init(uv_fs_event_t* handle);
+int uv__fsevents_close(uv_fs_event_t* handle);
+void uv__fsevents_loop_delete(uv_loop_t* loop);
+
+/* OSX < 10.7 has no file events, polyfill them */
+#ifndef MAC_OS_X_VERSION_10_7
+
+static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
+static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
+static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
+static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
+static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
+static const int kFSEventStreamEventFlagItemModified = 0x00001000;
+static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
+static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
+static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
+static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
+static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
+static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
+
+#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
+
+#endif /* defined(__APPLE__) */
+
+UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
+ uv_req_t* req,
+ uv_req_type type)) {
+ req->type = type;
+ uv__req_register(loop, req);
+}
+#define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+
+UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
+ /* Use a fast time source if available. We only need millisecond precision.
+ */
+ loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
+}
+
+UV_UNUSED(static char* uv__basename_r(const char* path)) {
+ char* s;
+
+ s = strrchr(path, '/');
+ if (s == NULL)
+ return (char*) path;
+
+ return s + 1;
+}
+
+#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/3rdparty/libuv/src/unix/kqueue.c b/3rdparty/libuv/src/unix/kqueue.c
new file mode 100644
index 00000000000..495f20d285f
--- /dev/null
+++ b/3rdparty/libuv/src/unix/kqueue.c
@@ -0,0 +1,426 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
+
+
+int uv__kqueue_init(uv_loop_t* loop) {
+ loop->backend_fd = kqueue();
+ if (loop->backend_fd == -1)
+ return -errno;
+
+ uv__cloexec(loop->backend_fd, 1);
+
+ return 0;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct kevent events[1024];
+ struct kevent* ev;
+ struct timespec spec;
+ unsigned int nevents;
+ unsigned int revents;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ int filter;
+ int fflags;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ nevents = 0;
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) {
+ filter = EVFILT_READ;
+ fflags = 0;
+ op = EV_ADD;
+
+ if (w->cb == uv__fs_event) {
+ filter = EVFILT_VNODE;
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+ op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
+ }
+
+ EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) {
+ EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;; nevents = 0) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ nfds = kevent(loop->backend_fd,
+ events,
+ nevents,
+ events,
+ ARRAY_SIZE(events),
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ ev = events + i;
+ fd = ev->ident;
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it. */
+ /* TODO batch up */
+ struct kevent events[1];
+
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != EBADF && errno != ENOENT)
+ abort();
+
+ continue;
+ }
+
+ if (ev->filter == EVFILT_VNODE) {
+ assert(w->events == UV__POLLIN);
+ assert(w->pevents == UV__POLLIN);
+ w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
+ nevents++;
+ continue;
+ }
+
+ revents = 0;
+
+ if (ev->filter == EVFILT_READ) {
+ if (w->pevents & UV__POLLIN) {
+ revents |= UV__POLLIN;
+ w->rcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->filter == EVFILT_WRITE) {
+ if (w->pevents & UV__POLLOUT) {
+ revents |= UV__POLLOUT;
+ w->wcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->flags & EV_ERROR)
+ revents |= UV__POLLERR;
+
+ if (revents == 0)
+ continue;
+
+ w->cb(loop, w, revents);
+ nevents++;
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct kevent* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct kevent*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].ident == fd)
+ events[i].ident = -1;
+}
+
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
+ uv_fs_event_t* handle;
+ struct kevent ev;
+ int events;
+ const char* path;
+#if defined(F_GETPATH)
+ /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
+ char pathbuf[MAXPATHLEN];
+#endif
+
+ handle = container_of(w, uv_fs_event_t, event_watcher);
+
+ if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
+ events = UV_CHANGE;
+ else
+ events = UV_RENAME;
+
+ path = NULL;
+#if defined(F_GETPATH)
+ /* Also works when the file has been unlinked from the file system. Passing
+ * in the path when the file has been deleted is arguably a little strange
+ * but it's consistent with what the inotify backend does.
+ */
+ if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
+ path = uv__basename_r(pathbuf);
+#endif
+ handle->cb(handle, path, events, 0);
+
+ if (handle->event_watcher.fd == -1)
+ return;
+
+ /* Watcher operates in one-shot mode, re-arm it. */
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+
+ EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
+
+ if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
+ abort();
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+#if defined(__APPLE__)
+ struct stat statbuf;
+#endif /* defined(__APPLE__) */
+ int fd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ /* TODO open asynchronously - but how do we report back errors? */
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__fs_event, fd);
+ handle->path = uv__strdup(path);
+ handle->cb = cb;
+
+#if defined(__APPLE__)
+ /* Nullify field to perform checks later */
+ handle->cf_cb = NULL;
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+ handle->cf_flags = flags;
+
+ if (fstat(fd, &statbuf))
+ goto fallback;
+ /* FSEvents works only with directories */
+ if (!(statbuf.st_mode & S_IFDIR))
+ goto fallback;
+
+ /* The fallback fd is no longer needed */
+ uv__close(fd);
+ handle->event_watcher.fd = -1;
+
+ return uv__fsevents_init(handle);
+
+fallback:
+#endif /* defined(__APPLE__) */
+
+ uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__handle_stop(handle);
+
+#if defined(__APPLE__)
+ if (uv__fsevents_close(handle))
+#endif /* defined(__APPLE__) */
+ {
+ uv__io_close(handle->loop, &handle->event_watcher);
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+
+ if (handle->event_watcher.fd != -1) {
+ /* When FSEvents is used, we don't use the event_watcher's fd under certain
+ * confitions. (see uv_fs_event_start) */
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+ }
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/linux-core.c b/3rdparty/libuv/src/unix/linux-core.c
new file mode 100644
index 00000000000..3ff6fb15e93
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-core.c
@@ -0,0 +1,899 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <net/if.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/sysinfo.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#define HAVE_IFADDRS_H 1
+
+#ifdef __UCLIBC__
+# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32
+# undef HAVE_IFADDRS_H
+# endif
+#endif
+
+#ifdef HAVE_IFADDRS_H
+# if defined(__ANDROID__)
+# include "android-ifaddrs.h"
+# else
+# include <ifaddrs.h>
+# endif
+# include <sys/socket.h>
+# include <net/ethernet.h>
+# include <linux/if_packet.h>
+#endif /* HAVE_IFADDRS_H */
+
+/* Available from 2.6.32 onwards. */
+#ifndef CLOCK_MONOTONIC_COARSE
+# define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
+ * include that file because it conflicts with <time.h>. We'll just have to
+ * define it ourselves.
+ */
+#ifndef CLOCK_BOOTTIME
+# define CLOCK_BOOTTIME 7
+#endif
+
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
+static int read_times(unsigned int numcpus, uv_cpu_info_t* ci);
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
+static unsigned long read_cpufreq(unsigned int cpunum);
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int fd;
+
+ fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
+
+ /* epoll_create1() can fail either because it's not implemented (old kernel)
+ * or because it doesn't understand the EPOLL_CLOEXEC flag.
+ */
+ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
+ fd = uv__epoll_create(256);
+
+ if (fd != -1)
+ uv__cloexec(fd, 1);
+ }
+
+ loop->backend_fd = fd;
+ loop->inotify_fd = -1;
+ loop->inotify_watchers = NULL;
+
+ if (fd == -1)
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->inotify_fd == -1) return;
+ uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN);
+ uv__close(loop->inotify_fd);
+ loop->inotify_fd = -1;
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct uv__epoll_event* events;
+ struct uv__epoll_event dummy;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].data == fd)
+ events[i].data = -1;
+
+ /* Remove the file descriptor from the epoll.
+ * This avoids a problem where the same file description remains open
+ * in another process, causing repeated junk epoll events.
+ *
+ * We pass in a dummy epoll_event, to work around a bug in old kernels.
+ */
+ if (loop->backend_fd >= 0) {
+ /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
+ * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
+ */
+ memset(&dummy, 0, sizeof(dummy));
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
+ }
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
+ * effectively infinite on 32 bits architectures. To avoid blocking
+ * indefinitely, we cap the timeout and poll again if necessary.
+ *
+ * Note that "30 minutes" is a simplification because it depends on
+ * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
+ * that being the largest value I have seen in the wild (and only once.)
+ */
+ static const int max_safe_timeout = 1789569;
+ static int no_epoll_pwait;
+ static int no_epoll_wait;
+ struct uv__epoll_event events[1024];
+ struct uv__epoll_event* pe;
+ struct uv__epoll_event e;
+ int real_timeout;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t sigset;
+ uint64_t sigmask;
+ uint64_t base;
+ int nevents;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ e.events = w->pevents;
+ e.data = w->fd;
+
+ if (w->events == 0)
+ op = UV__EPOLL_CTL_ADD;
+ else
+ op = UV__EPOLL_CTL_MOD;
+
+ /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+ * events, skip the syscall and squelch the events after epoll_wait().
+ */
+ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
+ if (errno != EEXIST)
+ abort();
+
+ assert(op == UV__EPOLL_CTL_ADD);
+
+ /* We've reactivated a file descriptor that's been watched before. */
+ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
+ abort();
+ }
+
+ w->events = w->pevents;
+ }
+
+ sigmask = 0;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPROF);
+ sigmask |= 1 << (SIGPROF - 1);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+ real_timeout = timeout;
+
+ for (;;) {
+ /* See the comment for max_safe_timeout for an explanation of why
+ * this is necessary. Executive summary: kernel bug workaround.
+ */
+ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+ timeout = max_safe_timeout;
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
+ abort();
+
+ if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
+ nfds = uv__epoll_pwait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout,
+ sigmask);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_pwait = 1;
+ } else {
+ nfds = uv__epoll_wait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_wait = 1;
+ }
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
+ abort();
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+
+ timeout = real_timeout - timeout;
+ if (timeout > 0)
+ continue;
+
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno == ENOSYS) {
+ /* epoll_wait() or epoll_pwait() failed, try the other system call. */
+ assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
+ continue;
+ }
+
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->data;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
+ continue;
+ }
+
+ /* Give users only events they're interested in. Prevents spurious
+ * callbacks when previous callback invocation in this loop has stopped
+ * the current watcher. Also, filters out events that users has not
+ * requested us to watch.
+ */
+ pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP;
+
+ /* Work around an epoll quirk where it sometimes reports just the
+ * EPOLLERR or EPOLLHUP event. In order to force the event loop to
+ * move forward, we merge in the read/write events that the watcher
+ * is interested in; uv__read() and uv__write() will then deal with
+ * the error or hangup in the usual fashion.
+ *
+ * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
+ * reads the available data, calls uv_read_stop(), then sometime later
+ * calls uv_read_start() again. By then, libuv has forgotten about the
+ * hangup and the kernel won't report EPOLLIN again because there's
+ * nothing left to read. If anything, libuv is to blame here. The
+ * current hack is just a quick bandaid; to properly fix it, libuv
+ * needs to remember the error/hangup event. We should get that for
+ * free when we switch over to edge-triggered I/O.
+ */
+ if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP)
+ pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT);
+
+ if (pe->events != 0) {
+ w->cb(loop, w, pe->events);
+ nevents++;
+ }
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ real_timeout -= (loop->time - base);
+ if (real_timeout <= 0)
+ return;
+
+ timeout = real_timeout;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static clock_t fast_clock_id = -1;
+ struct timespec t;
+ clock_t clock_id;
+
+ /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
+ * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
+ * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
+ * decide to make a costly system call.
+ */
+ /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
+ * when it has microsecond granularity or better (unlikely).
+ */
+ if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
+ if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
+ t.tv_nsec <= 1 * 1000 * 1000) {
+ fast_clock_id = CLOCK_MONOTONIC_COARSE;
+ } else {
+ fast_clock_id = CLOCK_MONOTONIC;
+ }
+ }
+
+ clock_id = CLOCK_MONOTONIC;
+ if (type == UV_CLOCK_FAST)
+ clock_id = fast_clock_id;
+
+ if (clock_gettime(clock_id, &t))
+ return 0; /* Not really possible. */
+
+ return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) < 0) return;
+
+ avg[0] = (double) info.loads[0] / 65536.0;
+ avg[1] = (double) info.loads[1] / 65536.0;
+ avg[2] = (double) info.loads[2] / 65536.0;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t n;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ n = *size - 1;
+ if (n > 0)
+ n = readlink("/proc/self/exe", buffer, n);
+
+ if (n == -1)
+ return -errno;
+
+ buffer[n] = '\0';
+ *size = n;
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char buf[1024];
+ const char* s;
+ ssize_t n;
+ long val;
+ int fd;
+ int i;
+
+ do
+ fd = open("/proc/self/stat", O_RDONLY);
+ while (fd == -1 && errno == EINTR);
+
+ if (fd == -1)
+ return -errno;
+
+ do
+ n = read(fd, buf, sizeof(buf) - 1);
+ while (n == -1 && errno == EINTR);
+
+ uv__close(fd);
+ if (n == -1)
+ return -errno;
+ buf[n] = '\0';
+
+ s = strchr(buf, ' ');
+ if (s == NULL)
+ goto err;
+
+ s += 1;
+ if (*s != '(')
+ goto err;
+
+ s = strchr(s, ')');
+ if (s == NULL)
+ goto err;
+
+ for (i = 1; i <= 22; i++) {
+ s = strchr(s + 1, ' ');
+ if (s == NULL)
+ goto err;
+ }
+
+ errno = 0;
+ val = strtol(s, NULL, 10);
+ if (errno != 0)
+ goto err;
+ if (val < 0)
+ goto err;
+
+ *rss = val * getpagesize();
+ return 0;
+
+err:
+ return -EINVAL;
+}
+
+
+int uv_uptime(double* uptime) {
+ static volatile int no_clock_boottime;
+ struct timespec now;
+ int r;
+
+ /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
+ * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
+ * is suspended.
+ */
+ if (no_clock_boottime) {
+ retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+ else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
+ no_clock_boottime = 1;
+ goto retry;
+ }
+
+ if (r)
+ return -errno;
+
+ *uptime = now.tv_sec;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int numcpus;
+ uv_cpu_info_t* ci;
+ int err;
+
+ *cpu_infos = NULL;
+ *count = 0;
+
+ numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+ assert(numcpus != (unsigned int) -1);
+ assert(numcpus != 0);
+
+ ci = uv__calloc(numcpus, sizeof(*ci));
+ if (ci == NULL)
+ return -ENOMEM;
+
+ err = read_models(numcpus, ci);
+ if (err == 0)
+ err = read_times(numcpus, ci);
+
+ if (err) {
+ uv_free_cpu_info(ci, numcpus);
+ return err;
+ }
+
+ /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
+ * We don't check for errors here. Worst case, the field is left zero.
+ */
+ if (ci[0].speed == 0)
+ read_speeds(numcpus, ci);
+
+ *cpu_infos = ci;
+ *count = numcpus;
+
+ return 0;
+}
+
+
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
+ unsigned int num;
+
+ for (num = 0; num < numcpus; num++)
+ ci[num].speed = read_cpufreq(num) / 1000;
+}
+
+
+/* Also reads the CPU frequency on x86. The other architectures only have
+ * a BogoMIPS field, which may not be very accurate.
+ *
+ * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
+ */
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
+ static const char model_marker[] = "model name\t: ";
+ static const char speed_marker[] = "cpu MHz\t\t: ";
+ const char* inferred_model;
+ unsigned int model_idx;
+ unsigned int speed_idx;
+ char buf[1024];
+ char* model;
+ FILE* fp;
+
+ /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
+ (void) &model_marker;
+ (void) &speed_marker;
+ (void) &speed_idx;
+ (void) &model;
+ (void) &buf;
+ (void) &fp;
+
+ model_idx = 0;
+ speed_idx = 0;
+
+#if defined(__arm__) || \
+ defined(__i386__) || \
+ defined(__mips__) || \
+ defined(__x86_64__)
+ fp = fopen("/proc/cpuinfo", "r");
+ if (fp == NULL)
+ return -errno;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (model_idx < numcpus) {
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#if defined(__arm__) || defined(__mips__)
+ if (model_idx < numcpus) {
+#if defined(__arm__)
+ /* Fallback for pre-3.8 kernels. */
+ static const char model_marker[] = "Processor\t: ";
+#else /* defined(__mips__) */
+ static const char model_marker[] = "cpu model\t\t: ";
+#endif
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#else /* !__arm__ && !__mips__ */
+ if (speed_idx < numcpus) {
+ if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
+ ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
+ continue;
+ }
+ }
+#endif /* __arm__ || __mips__ */
+ }
+
+ fclose(fp);
+#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
+
+ /* Now we want to make sure that all the models contain *something* because
+ * it's not safe to leave them as null. Copy the last entry unless there
+ * isn't one, in that case we simply put "unknown" into everything.
+ */
+ inferred_model = "unknown";
+ if (model_idx > 0)
+ inferred_model = ci[model_idx - 1].model;
+
+ while (model_idx < numcpus) {
+ model = uv__strndup(inferred_model, strlen(inferred_model));
+ if (model == NULL)
+ return -ENOMEM;
+ ci[model_idx++].model = model;
+ }
+
+ return 0;
+}
+
+
+static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
+ unsigned long clock_ticks;
+ struct uv_cpu_times_s ts;
+ unsigned long user;
+ unsigned long nice;
+ unsigned long sys;
+ unsigned long idle;
+ unsigned long dummy;
+ unsigned long irq;
+ unsigned int num;
+ unsigned int len;
+ char buf[1024];
+ FILE* fp;
+
+ clock_ticks = sysconf(_SC_CLK_TCK);
+ assert(clock_ticks != (unsigned long) -1);
+ assert(clock_ticks != 0);
+
+ fp = fopen("/proc/stat", "r");
+ if (fp == NULL)
+ return -errno;
+
+ if (!fgets(buf, sizeof(buf), fp))
+ abort();
+
+ num = 0;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (num >= numcpus)
+ break;
+
+ if (strncmp(buf, "cpu", 3))
+ break;
+
+ /* skip "cpu<num> " marker */
+ {
+ unsigned int n;
+ int r = sscanf(buf, "cpu%u ", &n);
+ assert(r == 1);
+ (void) r; /* silence build warning */
+ for (len = sizeof("cpu0"); n /= 10; len++);
+ }
+
+ /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
+ * guest, guest_nice but we're only interested in the first four + irq.
+ *
+ * Don't use %*s to skip fields or %ll to read straight into the uint64_t
+ * fields, they're not allowed in C89 mode.
+ */
+ if (6 != sscanf(buf + len,
+ "%lu %lu %lu %lu %lu %lu",
+ &user,
+ &nice,
+ &sys,
+ &idle,
+ &dummy,
+ &irq))
+ abort();
+
+ ts.user = clock_ticks * user;
+ ts.nice = clock_ticks * nice;
+ ts.sys = clock_ticks * sys;
+ ts.idle = clock_ticks * idle;
+ ts.irq = clock_ticks * irq;
+ ci[num++].cpu_times = ts;
+ }
+ fclose(fp);
+ assert(num == numcpus);
+
+ return 0;
+}
+
+
+static unsigned long read_cpufreq(unsigned int cpunum) {
+ unsigned long val;
+ char buf[1024];
+ FILE* fp;
+
+ snprintf(buf,
+ sizeof(buf),
+ "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
+ cpunum);
+
+ fp = fopen(buf, "r");
+ if (fp == NULL)
+ return 0;
+
+ if (fscanf(fp, "%lu", &val) != 1)
+ val = 0;
+
+ fclose(fp);
+
+ return val;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+#ifndef HAVE_IFADDRS_H
+ return -ENOSYS;
+#else
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_ll *sll;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+ *addresses = NULL;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == PF_PACKET)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ if (*count == 0)
+ return 0;
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On Linux getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information yet.
+ */
+ if (ent->ifa_addr->sa_family == PF_PACKET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_PACKET)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sll = (struct sockaddr_ll*)ent->ifa_addr;
+ memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+#endif
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+
+void uv__set_process_title(const char* title) {
+#if defined(PR_SET_NAME)
+ prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
+#endif
+}
diff --git a/3rdparty/libuv/src/unix/linux-inotify.c b/3rdparty/libuv/src/unix/linux-inotify.c
new file mode 100644
index 00000000000..282912115d8
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-inotify.c
@@ -0,0 +1,285 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+struct watcher_list {
+ RB_ENTRY(watcher_list) entry;
+ QUEUE watchers;
+ int iterating;
+ char* path;
+ int wd;
+};
+
+struct watcher_root {
+ struct watcher_list* rbh_root;
+};
+#define CAST(p) ((struct watcher_root*)(p))
+
+
+static int compare_watchers(const struct watcher_list* a,
+ const struct watcher_list* b) {
+ if (a->wd < b->wd) return -1;
+ if (a->wd > b->wd) return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
+
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents);
+
+
+static int new_inotify_fd(void) {
+ int err;
+ int fd;
+
+ fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ fd = uv__inotify_init();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err == 0)
+ err = uv__nonblock(fd, 1);
+
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+static int init_inotify(uv_loop_t* loop) {
+ int err;
+
+ if (loop->inotify_fd != -1)
+ return 0;
+
+ err = new_inotify_fd();
+ if (err < 0)
+ return err;
+
+ loop->inotify_fd = err;
+ uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
+ uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
+ struct watcher_list w;
+ w.wd = wd;
+ return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
+}
+
+static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
+ /* if the watcher_list->watchers is being iterated over, we can't free it. */
+ if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
+ /* No watchers left for this path. Clean up. */
+ RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
+ uv__inotify_rm_watch(loop->inotify_fd, w->wd);
+ uv__free(w);
+ }
+}
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* dummy,
+ unsigned int events) {
+ const struct uv__inotify_event* e;
+ struct watcher_list* w;
+ uv_fs_event_t* h;
+ QUEUE queue;
+ QUEUE* q;
+ const char* path;
+ ssize_t size;
+ const char *p;
+ /* needs to be large enough for sizeof(inotify_event) + strlen(path) */
+ char buf[4096];
+
+ while (1) {
+ do
+ size = read(loop->inotify_fd, buf, sizeof(buf));
+ while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ break;
+ }
+
+ assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
+
+ /* Now we have one or more inotify_event structs. */
+ for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
+ e = (const struct uv__inotify_event*)p;
+
+ events = 0;
+ if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_CHANGE;
+ if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_RENAME;
+
+ w = find_watcher(loop, e->wd);
+ if (w == NULL)
+ continue; /* Stale event, no watchers left. */
+
+ /* inotify does not return the filename when monitoring a single file
+ * for modifications. Repurpose the filename for API compatibility.
+ * I'm not convinced this is a good thing, maybe it should go.
+ */
+ path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
+
+ /* We're about to iterate over the queue and call user's callbacks.
+ * What can go wrong?
+ * A callback could call uv_fs_event_stop()
+ * and the queue can change under our feet.
+ * So, we use QUEUE_MOVE() trick to safely iterate over the queue.
+ * And we don't free the watcher_list until we're done iterating.
+ *
+ * First,
+ * tell uv_fs_event_stop() (that could be called from a user's callback)
+ * not to free watcher_list.
+ */
+ w->iterating = 1;
+ QUEUE_MOVE(&w->watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_fs_event_t, watchers);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&w->watchers, q);
+
+ h->cb(h, path, events, 0);
+ }
+ /* done iterating, time to (maybe) free empty watcher_list */
+ w->iterating = 0;
+ maybe_free_watcher_list(w, loop);
+ }
+ }
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ struct watcher_list* w;
+ int events;
+ int err;
+ int wd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ err = init_inotify(handle->loop);
+ if (err)
+ return err;
+
+ events = UV__IN_ATTRIB
+ | UV__IN_CREATE
+ | UV__IN_MODIFY
+ | UV__IN_DELETE
+ | UV__IN_DELETE_SELF
+ | UV__IN_MOVE_SELF
+ | UV__IN_MOVED_FROM
+ | UV__IN_MOVED_TO;
+
+ wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
+ if (wd == -1)
+ return -errno;
+
+ w = find_watcher(handle->loop, wd);
+ if (w)
+ goto no_insert;
+
+ w = uv__malloc(sizeof(*w) + strlen(path) + 1);
+ if (w == NULL)
+ return -ENOMEM;
+
+ w->wd = wd;
+ w->path = strcpy((char*)(w + 1), path);
+ QUEUE_INIT(&w->watchers);
+ w->iterating = 0;
+ RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
+
+no_insert:
+ uv__handle_start(handle);
+ QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
+ handle->path = w->path;
+ handle->cb = cb;
+ handle->wd = wd;
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ struct watcher_list* w;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ w = find_watcher(handle->loop, handle->wd);
+ assert(w != NULL);
+
+ handle->wd = -1;
+ handle->path = NULL;
+ uv__handle_stop(handle);
+ QUEUE_REMOVE(&handle->watchers);
+
+ maybe_free_watcher_list(w, handle->loop);
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/linux-syscalls.c b/3rdparty/libuv/src/unix/linux-syscalls.c
new file mode 100644
index 00000000000..89998ded26b
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-syscalls.c
@@ -0,0 +1,471 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "linux-syscalls.h"
+#include <unistd.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# define MSAN_ACTIVE 1
+# include <sanitizer/msan_interface.h>
+# endif
+#endif
+
+#if defined(__i386__)
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+#endif
+
+#if defined(__arm__)
+# if defined(__thumb__) || defined(__ARM_EABI__)
+# define UV_SYSCALL_BASE 0
+# else
+# define UV_SYSCALL_BASE 0x900000
+# endif
+#endif /* __arm__ */
+
+#ifndef __NR_accept4
+# if defined(__x86_64__)
+# define __NR_accept4 288
+# elif defined(__i386__)
+ /* Nothing. Handled through socketcall(). */
+# elif defined(__arm__)
+# define __NR_accept4 (UV_SYSCALL_BASE + 366)
+# endif
+#endif /* __NR_accept4 */
+
+#ifndef __NR_eventfd
+# if defined(__x86_64__)
+# define __NR_eventfd 284
+# elif defined(__i386__)
+# define __NR_eventfd 323
+# elif defined(__arm__)
+# define __NR_eventfd (UV_SYSCALL_BASE + 351)
+# endif
+#endif /* __NR_eventfd */
+
+#ifndef __NR_eventfd2
+# if defined(__x86_64__)
+# define __NR_eventfd2 290
+# elif defined(__i386__)
+# define __NR_eventfd2 328
+# elif defined(__arm__)
+# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
+# endif
+#endif /* __NR_eventfd2 */
+
+#ifndef __NR_epoll_create
+# if defined(__x86_64__)
+# define __NR_epoll_create 213
+# elif defined(__i386__)
+# define __NR_epoll_create 254
+# elif defined(__arm__)
+# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
+# endif
+#endif /* __NR_epoll_create */
+
+#ifndef __NR_epoll_create1
+# if defined(__x86_64__)
+# define __NR_epoll_create1 291
+# elif defined(__i386__)
+# define __NR_epoll_create1 329
+# elif defined(__arm__)
+# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
+# endif
+#endif /* __NR_epoll_create1 */
+
+#ifndef __NR_epoll_ctl
+# if defined(__x86_64__)
+# define __NR_epoll_ctl 233 /* used to be 214 */
+# elif defined(__i386__)
+# define __NR_epoll_ctl 255
+# elif defined(__arm__)
+# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
+# endif
+#endif /* __NR_epoll_ctl */
+
+#ifndef __NR_epoll_wait
+# if defined(__x86_64__)
+# define __NR_epoll_wait 232 /* used to be 215 */
+# elif defined(__i386__)
+# define __NR_epoll_wait 256
+# elif defined(__arm__)
+# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
+# endif
+#endif /* __NR_epoll_wait */
+
+#ifndef __NR_epoll_pwait
+# if defined(__x86_64__)
+# define __NR_epoll_pwait 281
+# elif defined(__i386__)
+# define __NR_epoll_pwait 319
+# elif defined(__arm__)
+# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
+# endif
+#endif /* __NR_epoll_pwait */
+
+#ifndef __NR_inotify_init
+# if defined(__x86_64__)
+# define __NR_inotify_init 253
+# elif defined(__i386__)
+# define __NR_inotify_init 291
+# elif defined(__arm__)
+# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
+# endif
+#endif /* __NR_inotify_init */
+
+#ifndef __NR_inotify_init1
+# if defined(__x86_64__)
+# define __NR_inotify_init1 294
+# elif defined(__i386__)
+# define __NR_inotify_init1 332
+# elif defined(__arm__)
+# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
+# endif
+#endif /* __NR_inotify_init1 */
+
+#ifndef __NR_inotify_add_watch
+# if defined(__x86_64__)
+# define __NR_inotify_add_watch 254
+# elif defined(__i386__)
+# define __NR_inotify_add_watch 292
+# elif defined(__arm__)
+# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
+# endif
+#endif /* __NR_inotify_add_watch */
+
+#ifndef __NR_inotify_rm_watch
+# if defined(__x86_64__)
+# define __NR_inotify_rm_watch 255
+# elif defined(__i386__)
+# define __NR_inotify_rm_watch 293
+# elif defined(__arm__)
+# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
+# endif
+#endif /* __NR_inotify_rm_watch */
+
+#ifndef __NR_pipe2
+# if defined(__x86_64__)
+# define __NR_pipe2 293
+# elif defined(__i386__)
+# define __NR_pipe2 331
+# elif defined(__arm__)
+# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
+# endif
+#endif /* __NR_pipe2 */
+
+#ifndef __NR_recvmmsg
+# if defined(__x86_64__)
+# define __NR_recvmmsg 299
+# elif defined(__i386__)
+# define __NR_recvmmsg 337
+# elif defined(__arm__)
+# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
+# endif
+#endif /* __NR_recvmsg */
+
+#ifndef __NR_sendmmsg
+# if defined(__x86_64__)
+# define __NR_sendmmsg 307
+# elif defined(__i386__)
+# define __NR_sendmmsg 345
+# elif defined(__arm__)
+# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
+# endif
+#endif /* __NR_sendmmsg */
+
+#ifndef __NR_utimensat
+# if defined(__x86_64__)
+# define __NR_utimensat 280
+# elif defined(__i386__)
+# define __NR_utimensat 320
+# elif defined(__arm__)
+# define __NR_utimensat (UV_SYSCALL_BASE + 348)
+# endif
+#endif /* __NR_utimensat */
+
+#ifndef __NR_preadv
+# if defined(__x86_64__)
+# define __NR_preadv 295
+# elif defined(__i386__)
+# define __NR_preadv 333
+# elif defined(__arm__)
+# define __NR_preadv (UV_SYSCALL_BASE + 361)
+# endif
+#endif /* __NR_preadv */
+
+#ifndef __NR_pwritev
+# if defined(__x86_64__)
+# define __NR_pwritev 296
+# elif defined(__i386__)
+# define __NR_pwritev 334
+# elif defined(__arm__)
+# define __NR_pwritev (UV_SYSCALL_BASE + 362)
+# endif
+#endif /* __NR_pwritev */
+
+#ifndef __NR_dup3
+# if defined(__x86_64__)
+# define __NR_dup3 292
+# elif defined(__i386__)
+# define __NR_dup3 330
+# elif defined(__arm__)
+# define __NR_dup3 (UV_SYSCALL_BASE + 358)
+# endif
+#endif /* __NR_pwritev */
+
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
+#if defined(__i386__)
+ unsigned long args[4];
+ int r;
+
+ args[0] = (unsigned long) fd;
+ args[1] = (unsigned long) addr;
+ args[2] = (unsigned long) addrlen;
+ args[3] = (unsigned long) flags;
+
+ r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
+
+ /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
+ * a bad flags argument. Try to distinguish between the two cases.
+ */
+ if (r == -1)
+ if (errno == EINVAL)
+ if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
+ errno = ENOSYS;
+
+ return r;
+#elif defined(__NR_accept4)
+ return syscall(__NR_accept4, fd, addr, addrlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd(unsigned int count) {
+#if defined(__NR_eventfd)
+ return syscall(__NR_eventfd, count);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd2(unsigned int count, int flags) {
+#if defined(__NR_eventfd2)
+ return syscall(__NR_eventfd2, count, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create(int size) {
+#if defined(__NR_epoll_create)
+ return syscall(__NR_epoll_create, size);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create1(int flags) {
+#if defined(__NR_epoll_create1)
+ return syscall(__NR_epoll_create1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
+#if defined(__NR_epoll_ctl)
+ return syscall(__NR_epoll_ctl, epfd, op, fd, events);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout) {
+#if defined(__NR_epoll_wait)
+ int result;
+ result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask) {
+#if defined(__NR_epoll_pwait)
+ int result;
+ result = syscall(__NR_epoll_pwait,
+ epfd,
+ events,
+ nevents,
+ timeout,
+ &sigmask,
+ sizeof(sigmask));
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init(void) {
+#if defined(__NR_inotify_init)
+ return syscall(__NR_inotify_init);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init1(int flags) {
+#if defined(__NR_inotify_init1)
+ return syscall(__NR_inotify_init1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
+#if defined(__NR_inotify_add_watch)
+ return syscall(__NR_inotify_add_watch, fd, path, mask);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_rm_watch(int fd, int32_t wd) {
+#if defined(__NR_inotify_rm_watch)
+ return syscall(__NR_inotify_rm_watch, fd, wd);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__pipe2(int pipefd[2], int flags) {
+#if defined(__NR_pipe2)
+ int result;
+ result = syscall(__NR_pipe2, pipefd, flags);
+#if MSAN_ACTIVE
+ if (!result)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags) {
+#if defined(__NR_sendmmsg)
+ return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout) {
+#if defined(__NR_recvmmsg)
+ return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags)
+{
+#if defined(__NR_utimensat)
+ return syscall(__NR_utimensat, dirfd, path, times, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_preadv)
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_pwritev)
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__dup3(int oldfd, int newfd, int flags) {
+#if defined(__NR_dup3)
+ return syscall(__NR_dup3, oldfd, newfd, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
diff --git a/3rdparty/libuv/src/unix/linux-syscalls.h b/3rdparty/libuv/src/unix/linux-syscalls.h
new file mode 100644
index 00000000000..96e79439cf0
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-syscalls.h
@@ -0,0 +1,158 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_SYSCALL_H_
+#define UV_LINUX_SYSCALL_H_
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#if defined(__alpha__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__hppa__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__sparc__)
+# define UV__O_CLOEXEC 0x400000
+#else
+# define UV__O_CLOEXEC 0x80000
+#endif
+
+#if defined(__alpha__)
+# define UV__O_NONBLOCK 0x4
+#elif defined(__hppa__)
+# define UV__O_NONBLOCK O_NONBLOCK
+#elif defined(__mips__)
+# define UV__O_NONBLOCK 0x80
+#elif defined(__sparc__)
+# define UV__O_NONBLOCK 0x4000
+#else
+# define UV__O_NONBLOCK 0x800
+#endif
+
+#define UV__EFD_CLOEXEC UV__O_CLOEXEC
+#define UV__EFD_NONBLOCK UV__O_NONBLOCK
+
+#define UV__IN_CLOEXEC UV__O_CLOEXEC
+#define UV__IN_NONBLOCK UV__O_NONBLOCK
+
+#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
+#if defined(SOCK_NONBLOCK)
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+#else
+# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+#endif
+
+/* epoll flags */
+#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
+#define UV__EPOLL_CTL_ADD 1
+#define UV__EPOLL_CTL_DEL 2
+#define UV__EPOLL_CTL_MOD 3
+
+#define UV__EPOLLIN 1
+#define UV__EPOLLOUT 4
+#define UV__EPOLLERR 8
+#define UV__EPOLLHUP 16
+#define UV__EPOLLONESHOT 0x40000000
+#define UV__EPOLLET 0x80000000
+
+/* inotify flags */
+#define UV__IN_ACCESS 0x001
+#define UV__IN_MODIFY 0x002
+#define UV__IN_ATTRIB 0x004
+#define UV__IN_CLOSE_WRITE 0x008
+#define UV__IN_CLOSE_NOWRITE 0x010
+#define UV__IN_OPEN 0x020
+#define UV__IN_MOVED_FROM 0x040
+#define UV__IN_MOVED_TO 0x080
+#define UV__IN_CREATE 0x100
+#define UV__IN_DELETE 0x200
+#define UV__IN_DELETE_SELF 0x400
+#define UV__IN_MOVE_SELF 0x800
+
+#if defined(__x86_64__)
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+} __attribute__((packed));
+#else
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+};
+#endif
+
+struct uv__inotify_event {
+ int32_t wd;
+ uint32_t mask;
+ uint32_t cookie;
+ uint32_t len;
+ /* char name[0]; */
+};
+
+struct uv__mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
+int uv__eventfd(unsigned int count);
+int uv__epoll_create(int size);
+int uv__epoll_create1(int flags);
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout);
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask);
+int uv__eventfd2(unsigned int count, int flags);
+int uv__inotify_init(void);
+int uv__inotify_init1(int flags);
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
+int uv__inotify_rm_watch(int fd, int32_t wd);
+int uv__pipe2(int pipefd[2], int flags);
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout);
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags);
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags);
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+int uv__dup3(int oldfd, int newfd, int flags);
+
+#endif /* UV_LINUX_SYSCALL_H_ */
diff --git a/3rdparty/libuv/src/unix/loop-watcher.c b/3rdparty/libuv/src/unix/loop-watcher.c
new file mode 100644
index 00000000000..340bb0dfa11
--- /dev/null
+++ b/3rdparty/libuv/src/unix/loop-watcher.c
@@ -0,0 +1,68 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#define UV_LOOP_WATCHER_DEFINE(name, type) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
+ handle->name##_cb = NULL; \
+ return 0; \
+ } \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ if (uv__is_active(handle)) return 0; \
+ if (cb == NULL) return -EINVAL; \
+ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ return 0; \
+ } \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ if (!uv__is_active(handle)) return 0; \
+ QUEUE_REMOVE(&handle->queue); \
+ uv__handle_stop(handle); \
+ return 0; \
+ } \
+ \
+ void uv__run_##name(uv_loop_t* loop) { \
+ uv_##name##_t* h; \
+ QUEUE queue; \
+ QUEUE* q; \
+ QUEUE_MOVE(&loop->name##_handles, &queue); \
+ while (!QUEUE_EMPTY(&queue)) { \
+ q = QUEUE_HEAD(&queue); \
+ h = QUEUE_DATA(q, uv_##name##_t, queue); \
+ QUEUE_REMOVE(q); \
+ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
+ h->name##_cb(h); \
+ } \
+ } \
+ \
+ void uv__##name##_close(uv_##name##_t* handle) { \
+ uv_##name##_stop(handle); \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/3rdparty/libuv/src/unix/loop.c b/3rdparty/libuv/src/unix/loop.c
new file mode 100644
index 00000000000..92e96f09ed0
--- /dev/null
+++ b/3rdparty/libuv/src/unix/loop.c
@@ -0,0 +1,155 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+#include "heap-inl.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ uv__signal_global_once_init();
+
+ memset(loop, 0, sizeof(*loop));
+ heap_init((struct heap*) &loop->timer_heap);
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->active_reqs);
+ QUEUE_INIT(&loop->idle_handles);
+ QUEUE_INIT(&loop->async_handles);
+ QUEUE_INIT(&loop->check_handles);
+ QUEUE_INIT(&loop->prepare_handles);
+ QUEUE_INIT(&loop->handle_queue);
+
+ loop->nfds = 0;
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+ QUEUE_INIT(&loop->pending_queue);
+ QUEUE_INIT(&loop->watcher_queue);
+
+ loop->closing_handles = NULL;
+ uv__update_time(loop);
+ uv__async_init(&loop->async_watcher);
+ loop->signal_pipefd[0] = -1;
+ loop->signal_pipefd[1] = -1;
+ loop->backend_fd = -1;
+ loop->emfile_fd = -1;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv__platform_loop_init(loop);
+ if (err)
+ return err;
+
+ err = uv_signal_init(loop, &loop->child_watcher);
+ if (err)
+ goto fail_signal_init;
+
+ uv__handle_unref(&loop->child_watcher);
+ loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
+ QUEUE_INIT(&loop->process_handles);
+
+ err = uv_rwlock_init(&loop->cloexec_lock);
+ if (err)
+ goto fail_rwlock_init;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+fail_rwlock_init:
+ uv__signal_loop_cleanup(loop);
+
+fail_signal_init:
+ uv__platform_loop_delete(loop);
+
+ return err;
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ uv__signal_loop_cleanup(loop);
+ uv__platform_loop_delete(loop);
+ uv__async_stop(loop, &loop->async_watcher);
+
+ if (loop->emfile_fd != -1) {
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ /*
+ * Note that all thread pool stuff is finished at this point and
+ * it is safe to just destroy rw lock
+ */
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+#if 0
+ assert(QUEUE_EMPTY(&loop->pending_queue));
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ assert(loop->nfds == 0);
+#endif
+
+ uv__free(loop->watchers);
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ if (option != UV_LOOP_BLOCK_SIGNAL)
+ return UV_ENOSYS;
+
+ if (va_arg(ap, int) != SIGPROF)
+ return UV_EINVAL;
+
+ loop->flags |= UV_LOOP_BLOCK_SIGPROF;
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/netbsd.c b/3rdparty/libuv/src/unix/netbsd.c
new file mode 100644
index 00000000000..ca48550f9d9
--- /dev/null
+++ b/3rdparty/libuv/src/unix/netbsd.c
@@ -0,0 +1,370 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <uvm/uvm_extern.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ size_t cb;
+ pid_t mypid;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+
+ cb = *size;
+ if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+ return -errno;
+ *size = strlen(buffer);
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+#if defined(HW_PHYSMEM64)
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+#else
+ unsigned int info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+#endif
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title) uv__free(process_title);
+
+ process_title = uv__strdup(title);
+ setproctitle("%s", title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc2 *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ int max_size = sizeof(struct kinfo_proc2);
+ int page_size;
+
+ page_size = getpagesize();
+ pid = getpid();
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
+ if (kinfo == NULL) goto error;
+
+ *rss = kinfo->p_vm_rssize * page_size;
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
+ unsigned int multiplier = ((uint64_t)1000L / ticks);
+ unsigned int cur = 0;
+ uv_cpu_info_t* cpu_info;
+ u_int64_t* cp_times;
+ char model[512];
+ u_int64_t cpuspeed;
+ int numcpus;
+ size_t size;
+ int i;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+ *count = numcpus;
+
+ /* Only i386 and amd64 have machdep.tsc_freq */
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
+ cpuspeed = 0;
+
+ size = numcpus * CPUSTATES * sizeof(*cp_times);
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL)
+ return -ENOMEM;
+
+ if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ uv__free(cp_times);
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
+ cur += CPUSTATES;
+ }
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_INET)) {
+ continue;
+ }
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ if (ent->ifa_addr->sa_family != PF_INET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/openbsd.c b/3rdparty/libuv/src/unix/openbsd.c
new file mode 100644
index 00000000000..6a3909a666c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/openbsd.c
@@ -0,0 +1,386 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/sched.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ char **argsbuf = NULL;
+ char **argsbuf_tmp;
+ size_t argsbuf_size = 100U;
+ size_t exepath_size;
+ pid_t mypid;
+ int err;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ for (;;) {
+ err = -ENOMEM;
+ argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
+ if (argsbuf_tmp == NULL)
+ goto out;
+ argsbuf = argsbuf_tmp;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+ if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
+ break;
+ }
+ if (errno != ENOMEM) {
+ err = -errno;
+ goto out;
+ }
+ argsbuf_size *= 2U;
+ }
+
+ if (argsbuf[0] == NULL) {
+ err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
+ goto out;
+ }
+
+ *size -= 1;
+ exepath_size = strlen(argsbuf[0]);
+ if (*size > exepath_size)
+ *size = exepath_size;
+
+ memcpy(buffer, argsbuf[0], *size);
+ buffer[*size] = '\0';
+ err = 0;
+
+out:
+ uv__free(argsbuf);
+
+ return err;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ setproctitle(title);
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ struct kinfo_proc kinfo;
+ size_t page_size = getpagesize();
+ size_t size = sizeof(struct kinfo_proc);
+ int mib[6];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+ mib[4] = sizeof(struct kinfo_proc);
+ mib[5] = 1;
+
+ if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
+ return -errno;
+
+ *rss = kinfo.p_vm_rssize * page_size;
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed;
+ uint64_t info[CPUSTATES];
+ char model[512];
+ int numcpus = 1;
+ int which[] = {CTL_HW,HW_MODEL,0};
+ size_t size;
+ int i;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctl(which, 2, &model, &size, NULL, 0))
+ return -errno;
+
+ which[1] = HW_NCPU;
+ size = sizeof(numcpus);
+ if (sysctl(which, 2, &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ which[1] = HW_CPUSPEED;
+ size = sizeof(cpuspeed);
+ if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ size = sizeof(info);
+ which[0] = CTL_KERN;
+ which[1] = KERN_CPTIME2;
+ for (i = 0; i < numcpus; i++) {
+ which[2] = i;
+ size = sizeof(info);
+ if (sysctl(which, 3, &info, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+ }
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs) != 0)
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_INET)) {
+ continue;
+ }
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ if (ent->ifa_addr->sa_family != PF_INET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/pipe.c b/3rdparty/libuv/src/unix/pipe.c
new file mode 100644
index 00000000000..7f87a713bf4
--- /dev/null
+++ b/3rdparty/libuv/src/unix/pipe.c
@@ -0,0 +1,288 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+ handle->shutdown_req = NULL;
+ handle->connect_req = NULL;
+ handle->pipe_fname = NULL;
+ handle->ipc = ipc;
+ return 0;
+}
+
+
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ struct sockaddr_un saddr;
+ const char* pipe_fname;
+ int sockfd;
+ int err;
+
+ pipe_fname = NULL;
+ sockfd = -1;
+
+ /* Already bound? */
+ if (uv__stream_fd(handle) >= 0)
+ return -EINVAL;
+
+ /* Make a copy of the file name, it outlives this function's scope. */
+ pipe_fname = uv__strdup(name);
+ if (pipe_fname == NULL)
+ return -ENOMEM;
+
+ /* We've got a copy, don't touch the original any more. */
+ name = NULL;
+
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto err_socket;
+ sockfd = err;
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
+ err = -errno;
+ /* Convert ENOENT to EACCES for compatibility with Windows. */
+ if (err == -ENOENT)
+ err = -EACCES;
+ goto err_bind;
+ }
+
+ /* Success. */
+ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
+ handle->io_watcher.fd = sockfd;
+ return 0;
+
+err_bind:
+ uv__close(sockfd);
+
+err_socket:
+ uv__free((void*)pipe_fname);
+ return err;
+}
+
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ if (uv__stream_fd(handle) == -1)
+ return -EINVAL;
+
+ if (listen(uv__stream_fd(handle), backlog))
+ return -errno;
+
+ handle->connection_cb = cb;
+ handle->io_watcher.cb = uv__server_io;
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
+ return 0;
+}
+
+
+void uv__pipe_close(uv_pipe_t* handle) {
+ if (handle->pipe_fname) {
+ /*
+ * Unlink the file system entity before closing the file descriptor.
+ * Doing it the other way around introduces a race where our process
+ * unlinks a socket with the same name that's just been created by
+ * another thread or process.
+ */
+ unlink(handle->pipe_fname);
+ uv__free((void*)handle->pipe_fname);
+ handle->pipe_fname = NULL;
+ }
+
+ uv__stream_close((uv_stream_t*)handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+ int err;
+
+ err = uv__nonblock(fd, 1);
+ if (err)
+ return err;
+
+#if defined(__APPLE__)
+ err = uv__stream_try_select((uv_stream_t*) handle, &fd);
+ if (err)
+ return err;
+#endif /* defined(__APPLE__) */
+
+ return uv__stream_open((uv_stream_t*)handle,
+ fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb) {
+ struct sockaddr_un saddr;
+ int new_sock;
+ int err;
+ int r;
+
+ new_sock = (uv__stream_fd(handle) == -1);
+
+ if (new_sock) {
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto out;
+ handle->io_watcher.fd = err;
+ }
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ do {
+ r = connect(uv__stream_fd(handle),
+ (struct sockaddr*)&saddr, sizeof saddr);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1 && errno != EINPROGRESS) {
+ err = -errno;
+ goto out;
+ }
+
+ err = 0;
+ if (new_sock) {
+ err = uv__stream_open((uv_stream_t*)handle,
+ uv__stream_fd(handle),
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ }
+
+ if (err == 0)
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
+
+out:
+ handle->delayed_error = err;
+ handle->connect_req = req;
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->handle = (uv_stream_t*)handle;
+ req->cb = cb;
+ QUEUE_INIT(&req->queue);
+
+ /* Force callback to run on next tick in case of error. */
+ if (err)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+ /* Mimic the Windows pipe implementation, always
+ * return 0 and let the callback handle errors.
+ */
+}
+
+
+typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
+
+
+static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
+ uv__peersockfunc func,
+ char* buffer,
+ size_t* size) {
+ struct sockaddr_un sa;
+ socklen_t addrlen;
+ int err;
+
+ addrlen = sizeof(sa);
+ memset(&sa, 0, addrlen);
+ err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
+ if (err < 0) {
+ *size = 0;
+ return -errno;
+ }
+
+#if defined(__linux__)
+ if (sa.sun_path[0] == 0)
+ /* Linux abstract namespace */
+ addrlen -= offsetof(struct sockaddr_un, sun_path);
+ else
+#endif
+ addrlen = strlen(sa.sun_path);
+
+
+ if (addrlen > *size) {
+ *size = addrlen;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, sa.sun_path, addrlen);
+ *size = addrlen;
+
+ return 0;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ if (!handle->ipc)
+ return 0;
+
+ if (handle->accepted_fd == -1)
+ return 0;
+
+ if (handle->queued_fds == NULL)
+ return 1;
+
+ queued_fds = handle->queued_fds;
+ return queued_fds->offset + 1;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+
+ if (handle->accepted_fd == -1)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return uv__handle_type(handle->accepted_fd);
+}
diff --git a/3rdparty/libuv/src/unix/poll.c b/3rdparty/libuv/src/unix/poll.c
new file mode 100644
index 00000000000..37da3b95851
--- /dev/null
+++ b/3rdparty/libuv/src/unix/poll.c
@@ -0,0 +1,113 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_poll_t* handle;
+ int pevents;
+
+ handle = container_of(w, uv_poll_t, io_watcher);
+
+ if (events & UV__POLLERR) {
+ uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
+ uv__handle_stop(handle);
+ handle->poll_cb(handle, -EBADF, 0);
+ return;
+ }
+
+ pevents = 0;
+ if (events & UV__POLLIN)
+ pevents |= UV_READABLE;
+ if (events & UV__POLLOUT)
+ pevents |= UV_WRITABLE;
+
+ handle->poll_cb(handle, 0, pevents);
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ int err;
+
+ err = uv__nonblock(fd, 1);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ uv__io_init(&handle->io_watcher, uv__poll_io, fd);
+ handle->poll_cb = NULL;
+ return 0;
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ return uv_poll_init(loop, handle, socket);
+}
+
+
+static void uv__poll_stop(uv_poll_t* handle) {
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
+ uv__handle_stop(handle);
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+ uv__poll_stop(handle);
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
+ int events;
+
+ assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0);
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ uv__poll_stop(handle);
+
+ if (pevents == 0)
+ return 0;
+
+ events = 0;
+ if (pevents & UV_READABLE)
+ events |= UV__POLLIN;
+ if (pevents & UV_WRITABLE)
+ events |= UV__POLLOUT;
+
+ uv__io_start(handle->loop, &handle->io_watcher, events);
+ uv__handle_start(handle);
+ handle->poll_cb = poll_cb;
+
+ return 0;
+}
+
+
+void uv__poll_close(uv_poll_t* handle) {
+ uv__poll_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/process.c b/3rdparty/libuv/src/unix/process.c
new file mode 100644
index 00000000000..571f8cd778c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/process.c
@@ -0,0 +1,563 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#else
+extern char **environ;
+#endif
+
+#ifdef __linux__
+# include <grp.h>
+#endif
+
+
+static void uv__chld(uv_signal_t* handle, int signum) {
+ uv_process_t* process;
+ uv_loop_t* loop;
+ int exit_status;
+ int term_signal;
+ int status;
+ pid_t pid;
+ QUEUE pending;
+ QUEUE* q;
+ QUEUE* h;
+
+ assert(signum == SIGCHLD);
+
+ QUEUE_INIT(&pending);
+ loop = handle->loop;
+
+ h = &loop->process_handles;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ do
+ pid = waitpid(process->pid, &status, WNOHANG);
+ while (pid == -1 && errno == EINTR);
+
+ if (pid == 0)
+ continue;
+
+ if (pid == -1) {
+ if (errno != ECHILD)
+ abort();
+ continue;
+ }
+
+ process->status = status;
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INSERT_TAIL(&pending, &process->queue);
+ }
+
+ h = &pending;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INIT(&process->queue);
+ uv__handle_stop(process);
+
+ if (process->exit_cb == NULL)
+ continue;
+
+ exit_status = 0;
+ if (WIFEXITED(process->status))
+ exit_status = WEXITSTATUS(process->status);
+
+ term_signal = 0;
+ if (WIFSIGNALED(process->status))
+ term_signal = WTERMSIG(process->status);
+
+ process->exit_cb(process, exit_status, term_signal);
+ }
+ assert(QUEUE_EMPTY(&pending));
+}
+
+
+int uv__make_socketpair(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_cloexec;
+
+ if (no_cloexec)
+ goto skip;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
+ return 0;
+
+ /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
+ * Anything else is a genuine error.
+ */
+ if (errno != EINVAL)
+ return -errno;
+
+ no_cloexec = 1;
+
+skip:
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+int uv__make_pipe(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_pipe2;
+
+ if (no_pipe2)
+ goto skip;
+
+ if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
+ return 0;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_pipe2 = 1;
+
+skip:
+#endif
+
+ if (pipe(fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Used for initializing stdio streams like options.stdin_stream. Returns
+ * zero on success. See also the cleanup section in uv_spawn().
+ */
+static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
+ int mask;
+ int fd;
+
+ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
+
+ switch (container->flags & mask) {
+ case UV_IGNORE:
+ return 0;
+
+ case UV_CREATE_PIPE:
+ assert(container->data.stream != NULL);
+ if (container->data.stream->type != UV_NAMED_PIPE)
+ return -EINVAL;
+ else
+ return uv__make_socketpair(fds, 0);
+
+ case UV_INHERIT_FD:
+ case UV_INHERIT_STREAM:
+ if (container->flags & UV_INHERIT_FD)
+ fd = container->data.fd;
+ else
+ fd = uv__stream_fd(container->data.stream);
+
+ if (fd == -1)
+ return -EINVAL;
+
+ fds[1] = fd;
+ return 0;
+
+ default:
+ assert(0 && "Unexpected flags");
+ return -EINVAL;
+ }
+}
+
+
+static int uv__process_open_stream(uv_stdio_container_t* container,
+ int pipefds[2],
+ int writable) {
+ int flags;
+ int err;
+
+ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
+ return 0;
+
+ err = uv__close(pipefds[1]);
+ if (err != 0 && err != -EINPROGRESS)
+ abort();
+
+ pipefds[1] = -1;
+ uv__nonblock(pipefds[0], 1);
+
+ if (container->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*)container->data.stream)->ipc)
+ flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
+ else if (writable)
+ flags = UV_STREAM_WRITABLE;
+ else
+ flags = UV_STREAM_READABLE;
+
+ return uv__stream_open(container->data.stream, pipefds[0], flags);
+}
+
+
+static void uv__process_close_stream(uv_stdio_container_t* container) {
+ if (!(container->flags & UV_CREATE_PIPE)) return;
+ uv__stream_close((uv_stream_t*)container->data.stream);
+}
+
+
+static void uv__write_int(int fd, int val) {
+ ssize_t n;
+
+ do
+ n = write(fd, &val, sizeof(val));
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 && errno == EPIPE)
+ return; /* parent process has quit */
+
+ assert(n == sizeof(val));
+}
+
+
+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
+/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
+ * avoided. Since this isn't called on those targets, the function
+ * doesn't even need to be defined for them.
+ */
+static void uv__process_child_init(const uv_process_options_t* options,
+ int stdio_count,
+ int (*pipes)[2],
+ int error_fd) {
+ int close_fd;
+ int use_fd;
+ int fd;
+
+ if (options->flags & UV_PROCESS_DETACHED)
+ setsid();
+
+ /* First duplicate low numbered fds, since it's not safe to duplicate them,
+ * they could get replaced. Example: swapping stdout and stderr; without
+ * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+ * stdout and stderr go to the same fd, which was not the intention. */
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+ if (use_fd < 0 || use_fd >= fd)
+ continue;
+ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+ if (pipes[fd][1] == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ close_fd = pipes[fd][0];
+ use_fd = pipes[fd][1];
+
+ if (use_fd < 0) {
+ if (fd >= 3)
+ continue;
+ else {
+ /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+ * set
+ */
+ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
+ close_fd = use_fd;
+
+ if (use_fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+ }
+
+ if (fd == use_fd)
+ uv__cloexec(use_fd, 0);
+ else
+ fd = dup2(use_fd, fd);
+
+ if (fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (fd <= 2)
+ uv__nonblock(fd, 0);
+
+ if (close_fd >= stdio_count)
+ uv__close(close_fd);
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+
+ if (use_fd >= stdio_count)
+ uv__close(use_fd);
+ }
+
+ if (options->cwd != NULL && chdir(options->cwd)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
+ /* When dropping privileges from root, the `setgroups` call will
+ * remove any extraneous groups. If we don't call this, then
+ * even though our uid has dropped, we may still have groups
+ * that enable us to do super-user things. This will fail if we
+ * aren't root, so don't bother checking the return value, this
+ * is just done as an optimistic privilege dropping function.
+ */
+ SAVE_ERRNO(setgroups(0, NULL));
+ }
+
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->env != NULL) {
+ environ = options->env;
+ }
+
+ execvp(options->file, options->args);
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+}
+#endif
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
+ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
+ return -ENOSYS;
+#else
+ int signal_pipe[2] = { -1, -1 };
+ int (*pipes)[2];
+ int stdio_count;
+ ssize_t r;
+ pid_t pid;
+ int err;
+ int exec_errorno;
+ int i;
+ int status;
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
+ QUEUE_INIT(&process->queue);
+
+ stdio_count = options->stdio_count;
+ if (stdio_count < 3)
+ stdio_count = 3;
+
+ err = -ENOMEM;
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ if (pipes == NULL)
+ goto error;
+
+ for (i = 0; i < stdio_count; i++) {
+ pipes[i][0] = -1;
+ pipes[i][1] = -1;
+ }
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_init_stdio(options->stdio + i, pipes[i]);
+ if (err)
+ goto error;
+ }
+
+ /* This pipe is used by the parent to wait until
+ * the child has called `execve()`. We need this
+ * to avoid the following race condition:
+ *
+ * if ((pid = fork()) > 0) {
+ * kill(pid, SIGTERM);
+ * }
+ * else if (pid == 0) {
+ * execve("/bin/cat", argp, envp);
+ * }
+ *
+ * The parent sends a signal immediately after forking.
+ * Since the child may not have called `execve()` yet,
+ * there is no telling what process receives the signal,
+ * our fork or /bin/cat.
+ *
+ * To avoid ambiguity, we create a pipe with both ends
+ * marked close-on-exec. Then, after the call to `fork()`,
+ * the parent polls the read end until it EOFs or errors with EPIPE.
+ */
+ err = uv__make_pipe(signal_pipe, 0);
+ if (err)
+ goto error;
+
+ uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
+
+ /* Acquire write lock to prevent opening new fds in worker threads */
+ uv_rwlock_wrlock(&loop->cloexec_lock);
+ pid = fork();
+
+ if (pid == -1) {
+ err = -errno;
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[0]);
+ uv__close(signal_pipe[1]);
+ goto error;
+ }
+
+ if (pid == 0) {
+ uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+ abort();
+ }
+
+ /* Release lock in parent process */
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[1]);
+
+ process->status = 0;
+ exec_errorno = 0;
+ do
+ r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
+ while (r == -1 && errno == EINTR);
+
+ if (r == 0)
+ ; /* okay, EOF */
+ else if (r == sizeof(exec_errorno)) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, read errorno */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else if (r == -1 && errno == EPIPE) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, got EPIPE */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else
+ abort();
+
+ uv__close(signal_pipe[0]);
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
+ if (err == 0)
+ continue;
+
+ while (i--)
+ uv__process_close_stream(options->stdio + i);
+
+ goto error;
+ }
+
+ /* Only activate this handle if exec() happened successfully */
+ if (exec_errorno == 0) {
+ QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
+ uv__handle_start(process);
+ }
+
+ process->pid = pid;
+ process->exit_cb = options->exit_cb;
+
+ uv__free(pipes);
+ return exec_errorno;
+
+error:
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options->stdio_count)
+ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ close(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ close(pipes[i][1]);
+ }
+ uv__free(pipes);
+ }
+
+ return err;
+#endif
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ return uv_kill(process->pid, signum);
+}
+
+
+int uv_kill(int pid, int signum) {
+ if (kill(pid, signum))
+ return -errno;
+ else
+ return 0;
+}
+
+
+void uv__process_close(uv_process_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+ if (QUEUE_EMPTY(&handle->loop->process_handles))
+ uv_signal_stop(&handle->loop->child_watcher);
+}
diff --git a/3rdparty/libuv/src/unix/proctitle.c b/3rdparty/libuv/src/unix/proctitle.c
new file mode 100644
index 00000000000..19214e5ec97
--- /dev/null
+++ b/3rdparty/libuv/src/unix/proctitle.c
@@ -0,0 +1,102 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+extern void uv__set_process_title(const char* title);
+
+static void* args_mem;
+
+static struct {
+ char* str;
+ size_t len;
+} process_title;
+
+
+char** uv_setup_args(int argc, char** argv) {
+ char** new_argv;
+ size_t size;
+ char* s;
+ int i;
+
+ if (argc <= 0)
+ return argv;
+
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
+
+ process_title.str = argv[0];
+ process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
+ assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
+
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
+
+ new_argv = uv__malloc(size);
+ if (new_argv == NULL)
+ return argv;
+ args_mem = new_argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
+ }
+ new_argv[i] = NULL;
+
+ return new_argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title.len == 0)
+ return 0;
+
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
+ uv__set_process_title(title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title.len > 0)
+ strncpy(buffer, process_title.str, size);
+ else if (size > 0)
+ buffer[0] = '\0';
+
+ return 0;
+}
+
+
+UV_DESTRUCTOR(static void free_args_mem(void)) {
+ uv__free(args_mem); /* Keep valgrind happy. */
+ args_mem = NULL;
+}
diff --git a/3rdparty/libuv/src/unix/pthread-fixes.c b/3rdparty/libuv/src/unix/pthread-fixes.c
new file mode 100644
index 00000000000..3a71eb5aae7
--- /dev/null
+++ b/3rdparty/libuv/src/unix/pthread-fixes.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2013, Sony Mobile Communications AB
+ * Copyright (c) 2012, Google Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Android versions < 4.1 have a broken pthread_sigmask.
+ * Note that this block of code must come before any inclusion of
+ * pthread-fixes.h so that the real pthread_sigmask can be referenced.
+ * */
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
+ static int workaround;
+
+ if (workaround) {
+ return sigprocmask(how, set, oset);
+ } else if (pthread_sigmask(how, set, oset)) {
+ if (errno == EINVAL && sigprocmask(how, set, oset) == 0) {
+ workaround = 1;
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+}
+
+/*Android doesn't provide pthread_barrier_t for now.*/
+#ifndef PTHREAD_BARRIER_SERIAL_THREAD
+
+#include "pthread-fixes.h"
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count) {
+ barrier->count = count;
+ pthread_mutex_init(&barrier->mutex, NULL);
+ pthread_cond_init(&barrier->cond, NULL);
+ return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ /* Lock the mutex*/
+ pthread_mutex_lock(&barrier->mutex);
+ /* Decrement the count. If this is the first thread to reach 0, wake up
+ waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/
+ if (--barrier->count == 0) {
+ /* First thread to reach the barrier */
+ pthread_cond_broadcast(&barrier->cond);
+ pthread_mutex_unlock(&barrier->mutex);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ /* Otherwise, wait for other threads until the count reaches 0, then
+ return 0 to indicate this is not the first thread.*/
+ do {
+ pthread_cond_wait(&barrier->cond, &barrier->mutex);
+ } while (barrier->count > 0);
+
+ pthread_mutex_unlock(&barrier->mutex);
+ return 0;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t *barrier) {
+ barrier->count = 0;
+ pthread_cond_destroy(&barrier->cond);
+ pthread_mutex_destroy(&barrier->mutex);
+ return 0;
+}
+
+#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
+
+int pthread_yield(void) {
+ sched_yield();
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/signal.c b/3rdparty/libuv/src/unix/signal.c
new file mode 100644
index 00000000000..edd9085d3f3
--- /dev/null
+++ b/3rdparty/libuv/src/unix/signal.c
@@ -0,0 +1,467 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+typedef struct {
+ uv_signal_t* handle;
+ int signum;
+} uv__signal_msg_t;
+
+RB_HEAD(uv__signal_tree_s, uv_signal_s);
+
+
+static int uv__signal_unlock(void);
+static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
+static void uv__signal_stop(uv_signal_t* handle);
+
+
+static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
+static struct uv__signal_tree_s uv__signal_tree =
+ RB_INITIALIZER(uv__signal_tree);
+static int uv__signal_lock_pipefd[2];
+
+
+RB_GENERATE_STATIC(uv__signal_tree_s,
+ uv_signal_s, tree_entry,
+ uv__signal_compare)
+
+
+static void uv__signal_global_init(void) {
+ if (uv__make_pipe(uv__signal_lock_pipefd, 0))
+ abort();
+
+ if (uv__signal_unlock())
+ abort();
+}
+
+
+void uv__signal_global_once_init(void) {
+ pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
+}
+
+
+
+static int uv__signal_lock(void) {
+ int r;
+ char data;
+
+ do {
+ r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static int uv__signal_unlock(void) {
+ int r;
+ char data = 42;
+
+ do {
+ r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
+ sigset_t new_mask;
+
+ if (sigfillset(&new_mask))
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
+ abort();
+
+ if (uv__signal_lock())
+ abort();
+}
+
+
+static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
+ if (uv__signal_unlock())
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
+ abort();
+}
+
+
+static uv_signal_t* uv__signal_first_handle(int signum) {
+ /* This function must be called with the signal lock held. */
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
+
+ if (handle != NULL && handle->signum == signum)
+ return handle;
+
+ return NULL;
+}
+
+
+static void uv__signal_handler(int signum) {
+ uv__signal_msg_t msg;
+ uv_signal_t* handle;
+ int saved_errno;
+
+ saved_errno = errno;
+ memset(&msg, 0, sizeof msg);
+
+ if (uv__signal_lock()) {
+ errno = saved_errno;
+ return;
+ }
+
+ for (handle = uv__signal_first_handle(signum);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
+ int r;
+
+ msg.signum = signum;
+ msg.handle = handle;
+
+ /* write() should be atomic for small data chunks, so the entire message
+ * should be written at once. In theory the pipe could become full, in
+ * which case the user is out of luck.
+ */
+ do {
+ r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
+ } while (r == -1 && errno == EINTR);
+
+ assert(r == sizeof msg ||
+ (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
+
+ if (r != -1)
+ handle->caught_signals++;
+ }
+
+ uv__signal_unlock();
+ errno = saved_errno;
+}
+
+
+static int uv__signal_register_handler(int signum) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ /* XXX use a separate signal stack? */
+ memset(&sa, 0, sizeof(sa));
+ if (sigfillset(&sa.sa_mask))
+ abort();
+ sa.sa_handler = uv__signal_handler;
+
+ /* XXX save old action so we can restore it later on? */
+ if (sigaction(signum, &sa, NULL))
+ return -errno;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_handler(int signum) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
+ * signal implies that it was successfully registered earlier, so EINVAL
+ * should never happen.
+ */
+ if (sigaction(signum, &sa, NULL))
+ abort();
+}
+
+
+static int uv__signal_loop_once_init(uv_loop_t* loop) {
+ int err;
+
+ /* Return if already initialized. */
+ if (loop->signal_pipefd[0] != -1)
+ return 0;
+
+ err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
+ if (err)
+ return err;
+
+ uv__io_init(&loop->signal_io_watcher,
+ uv__signal_event,
+ loop->signal_pipefd[0]);
+ uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+void uv__signal_loop_cleanup(uv_loop_t* loop) {
+ QUEUE* q;
+
+ /* Stop all the signal watchers that are still attached to this loop. This
+ * ensures that the (shared) signal tree doesn't contain any invalid entries
+ * entries, and that signal handlers are removed when appropriate.
+ * It's safe to use QUEUE_FOREACH here because the handles and the handle
+ * queue are not modified by uv__signal_stop().
+ */
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (handle->type == UV_SIGNAL)
+ uv__signal_stop((uv_signal_t*) handle);
+ }
+
+ if (loop->signal_pipefd[0] != -1) {
+ uv__close(loop->signal_pipefd[0]);
+ loop->signal_pipefd[0] = -1;
+ }
+
+ if (loop->signal_pipefd[1] != -1) {
+ uv__close(loop->signal_pipefd[1]);
+ loop->signal_pipefd[1] = -1;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ int err;
+
+ err = uv__signal_loop_once_init(loop);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->signum = 0;
+ handle->caught_signals = 0;
+ handle->dispatched_signals = 0;
+
+ return 0;
+}
+
+
+void uv__signal_close(uv_signal_t* handle) {
+
+ uv__signal_stop(handle);
+
+ /* If there are any caught signals "trapped" in the signal pipe, we can't
+ * call the close callback yet. Otherwise, add the handle to the finish_close
+ * queue.
+ */
+ if (handle->caught_signals == handle->dispatched_signals) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ sigset_t saved_sigmask;
+ int err;
+
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ /* If the user supplies signum == 0, then return an error already. If the
+ * signum is otherwise invalid then uv__signal_register will find out
+ * eventually.
+ */
+ if (signum == 0)
+ return -EINVAL;
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't
+ * go through the process of deregistering and registering the handler.
+ * Additionally, this avoids pending signals getting lost in the small time
+ * time frame that handle->signum == 0.
+ */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ uv__signal_stop(handle);
+ }
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ /* If at this point there are no active signal watchers for this signum (in
+ * any of the loops), it's time to try and register a handler for it here.
+ */
+ if (uv__signal_first_handle(signum) == NULL) {
+ err = uv__signal_register_handler(signum);
+ if (err) {
+ /* Registering the signal handler failed. Must be an invalid signal. */
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+ return err;
+ }
+ }
+
+ handle->signum = signum;
+ RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+static void uv__signal_event(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int events) {
+ uv__signal_msg_t* msg;
+ uv_signal_t* handle;
+ char buf[sizeof(uv__signal_msg_t) * 32];
+ size_t bytes, end, i;
+ int r;
+
+ bytes = 0;
+ end = 0;
+
+ do {
+ r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
+
+ if (r == -1 && errno == EINTR)
+ continue;
+
+ if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ /* If there are bytes in the buffer already (which really is extremely
+ * unlikely if possible at all) we can't exit the function here. We'll
+ * spin until more bytes are read instead.
+ */
+ if (bytes > 0)
+ continue;
+
+ /* Otherwise, there was nothing there. */
+ return;
+ }
+
+ /* Other errors really should never happen. */
+ if (r == -1)
+ abort();
+
+ bytes += r;
+
+ /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
+ end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
+
+ for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
+ msg = (uv__signal_msg_t*) (buf + i);
+ handle = msg->handle;
+
+ if (msg->signum == handle->signum) {
+ assert(!(handle->flags & UV_CLOSING));
+ handle->signal_cb(handle, handle->signum);
+ }
+
+ handle->dispatched_signals++;
+
+ /* If uv_close was called while there were caught signals that were not
+ * yet dispatched, the uv__finish_close was deferred. Make close pending
+ * now if this has happened.
+ */
+ if ((handle->flags & UV_CLOSING) &&
+ (handle->caught_signals == handle->dispatched_signals)) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+ }
+
+ bytes -= end;
+
+ /* If there are any "partial" messages left, move them to the start of the
+ * the buffer, and spin. This should not happen.
+ */
+ if (bytes) {
+ memmove(buf, buf + end, bytes);
+ continue;
+ }
+ } while (end == sizeof buf);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up
+ * adjacent.
+ */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after
+ * { .signum = x, .loop = NULL }.
+ */
+ if (w1->loop < w2->loop) return -1;
+ if (w1->loop > w2->loop) return 1;
+
+ if (w1 < w2) return -1;
+ if (w1 > w2) return 1;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+ uv__signal_stop(handle);
+ return 0;
+}
+
+
+static void uv__signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+ sigset_t saved_sigmask;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return;
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+ (void) removed_handle;
+
+ /* Check if there are other active signal watchers observing this signal. If
+ * not, unregister the signal handler.
+ */
+ if (uv__signal_first_handle(handle->signum) == NULL)
+ uv__signal_unregister_handler(handle->signum);
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/spinlock.h b/3rdparty/libuv/src/unix/spinlock.h
new file mode 100644
index 00000000000..a20c83cc601
--- /dev/null
+++ b/3rdparty/libuv/src/unix/spinlock.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SPINLOCK_H_
+#define UV_SPINLOCK_H_
+
+#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
+#include "atomic-ops.h"
+
+#define UV_SPINLOCK_INITIALIZER { 0 }
+
+typedef struct {
+ int lock;
+} uv_spinlock_t;
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
+ while (!uv_spinlock_trylock(spinlock)) cpu_relax();
+}
+
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
+ /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
+ * Not really critical until we have locks that are (frequently) contended
+ * for by several threads.
+ */
+ return 0 == cmpxchgi(&spinlock->lock, 0, 1);
+}
+
+#endif /* UV_SPINLOCK_H_ */
diff --git a/3rdparty/libuv/src/unix/stream.c b/3rdparty/libuv/src/unix/stream.c
new file mode 100644
index 00000000000..7d7ab2633b6
--- /dev/null
+++ b/3rdparty/libuv/src/unix/stream.c
@@ -0,0 +1,1615 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <limits.h> /* IOV_MAX */
+
+#if defined(__APPLE__)
+# include <sys/event.h>
+# include <sys/time.h>
+# include <sys/select.h>
+
+/* Forward declaration */
+typedef struct uv__stream_select_s uv__stream_select_t;
+
+struct uv__stream_select_s {
+ uv_stream_t* stream;
+ uv_thread_t thread;
+ uv_sem_t close_sem;
+ uv_sem_t async_sem;
+ uv_async_t async;
+ int events;
+ int fake_fd;
+ int int_fd;
+ int fd;
+ fd_set* sread;
+ size_t sread_sz;
+ fd_set* swrite;
+ size_t swrite_sz;
+};
+#endif /* defined(__APPLE__) */
+
+static void uv__stream_connect(uv_stream_t*);
+static void uv__write(uv_stream_t* stream);
+static void uv__read(uv_stream_t* stream);
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static void uv__write_callbacks(uv_stream_t* stream);
+static size_t uv__write_req_size(uv_write_t* req);
+
+
+void uv__stream_init(uv_loop_t* loop,
+ uv_stream_t* stream,
+ uv_handle_type type) {
+ int err;
+
+ uv__handle_init(loop, (uv_handle_t*)stream, type);
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ stream->close_cb = NULL;
+ stream->connection_cb = NULL;
+ stream->connect_req = NULL;
+ stream->shutdown_req = NULL;
+ stream->accepted_fd = -1;
+ stream->queued_fds = NULL;
+ stream->delayed_error = 0;
+ QUEUE_INIT(&stream->write_queue);
+ QUEUE_INIT(&stream->write_completed_queue);
+ stream->write_queue_size = 0;
+
+ if (loop->emfile_fd == -1) {
+ err = uv__open_cloexec("/dev/null", O_RDONLY);
+ if (err < 0)
+ /* In the rare case that "/dev/null" isn't mounted open "/"
+ * instead.
+ */
+ err = uv__open_cloexec("/", O_RDONLY);
+ if (err >= 0)
+ loop->emfile_fd = err;
+ }
+
+#if defined(__APPLE__)
+ stream->select = NULL;
+#endif /* defined(__APPLE_) */
+
+ uv__io_init(&stream->io_watcher, uv__stream_io, -1);
+}
+
+
+static void uv__stream_osx_interrupt_select(uv_stream_t* stream) {
+#if defined(__APPLE__)
+ /* Notify select() thread about state change */
+ uv__stream_select_t* s;
+ int r;
+
+ s = stream->select;
+ if (s == NULL)
+ return;
+
+ /* Interrupt select() loop
+ * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will
+ * emit read event on other side
+ */
+ do
+ r = write(s->fake_fd, "x", 1);
+ while (r == -1 && errno == EINTR);
+
+ assert(r == 1);
+#else /* !defined(__APPLE__) */
+ /* No-op on any other platform */
+#endif /* !defined(__APPLE__) */
+}
+
+
+#if defined(__APPLE__)
+static void uv__stream_osx_select(void* arg) {
+ uv_stream_t* stream;
+ uv__stream_select_t* s;
+ char buf[1024];
+ int events;
+ int fd;
+ int r;
+ int max_fd;
+
+ stream = arg;
+ s = stream->select;
+ fd = s->fd;
+
+ if (fd > s->int_fd)
+ max_fd = fd;
+ else
+ max_fd = s->int_fd;
+
+ while (1) {
+ /* Terminate on semaphore */
+ if (uv_sem_trywait(&s->close_sem) == 0)
+ break;
+
+ /* Watch fd using select(2) */
+ memset(s->sread, 0, s->sread_sz);
+ memset(s->swrite, 0, s->swrite_sz);
+
+ if (uv__io_active(&stream->io_watcher, UV__POLLIN))
+ FD_SET(fd, s->sread);
+ if (uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ FD_SET(fd, s->swrite);
+ FD_SET(s->int_fd, s->sread);
+
+ /* Wait indefinitely for fd events */
+ r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+
+ /* XXX: Possible?! */
+ abort();
+ }
+
+ /* Ignore timeouts */
+ if (r == 0)
+ continue;
+
+ /* Empty socketpair's buffer in case of interruption */
+ if (FD_ISSET(s->int_fd, s->sread))
+ while (1) {
+ r = read(s->int_fd, buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ /* Handle events */
+ events = 0;
+ if (FD_ISSET(fd, s->sread))
+ events |= UV__POLLIN;
+ if (FD_ISSET(fd, s->swrite))
+ events |= UV__POLLOUT;
+
+ assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
+ if (events != 0) {
+ ACCESS_ONCE(int, s->events) = events;
+
+ uv_async_send(&s->async);
+ uv_sem_wait(&s->async_sem);
+
+ /* Should be processed at this stage */
+ assert((s->events == 0) || (stream->flags & UV_CLOSING));
+ }
+ }
+}
+
+
+static void uv__stream_osx_select_cb(uv_async_t* handle) {
+ uv__stream_select_t* s;
+ uv_stream_t* stream;
+ int events;
+
+ s = container_of(handle, uv__stream_select_t, async);
+ stream = s->stream;
+
+ /* Get and reset stream's events */
+ events = s->events;
+ ACCESS_ONCE(int, s->events) = 0;
+
+ assert(events != 0);
+ assert(events == (events & (UV__POLLIN | UV__POLLOUT)));
+
+ /* Invoke callback on event-loop */
+ if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN))
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN);
+
+ if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT);
+
+ if (stream->flags & UV_CLOSING)
+ return;
+
+ /* NOTE: It is important to do it here, otherwise `select()` might be called
+ * before the actual `uv__read()`, leading to the blocking syscall
+ */
+ uv_sem_post(&s->async_sem);
+}
+
+
+static void uv__stream_osx_cb_close(uv_handle_t* async) {
+ uv__stream_select_t* s;
+
+ s = container_of(async, uv__stream_select_t, async);
+ uv__free(s);
+}
+
+
+int uv__stream_try_select(uv_stream_t* stream, int* fd) {
+ /*
+ * kqueue doesn't work with some files from /dev mount on osx.
+ * select(2) in separate thread for those fds
+ */
+
+ struct kevent filter[1];
+ struct kevent events[1];
+ struct timespec timeout;
+ uv__stream_select_t* s;
+ int fds[2];
+ int err;
+ int ret;
+ int kq;
+ int old_fd;
+ int max_fd;
+ size_t sread_sz;
+ size_t swrite_sz;
+
+ kq = kqueue();
+ if (kq == -1) {
+ perror("(libuv) kqueue()");
+ return -errno;
+ }
+
+ EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
+
+ /* Use small timeout, because we only want to capture EINVALs */
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1;
+
+ ret = kevent(kq, filter, 1, events, 1, &timeout);
+ uv__close(kq);
+
+ if (ret == -1)
+ return -errno;
+
+ if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL)
+ return 0;
+
+ /* At this point we definitely know that this fd won't work with kqueue */
+
+ /*
+ * Create fds for io watcher and to interrupt the select() loop.
+ * NOTE: do it ahead of malloc below to allocate enough space for fd_sets
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ max_fd = *fd;
+ if (fds[1] > max_fd)
+ max_fd = fds[1];
+
+ sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY;
+ swrite_sz = sread_sz;
+
+ s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz);
+ if (s == NULL) {
+ err = -ENOMEM;
+ goto failed_malloc;
+ }
+
+ s->events = 0;
+ s->fd = *fd;
+ s->sread = (fd_set*) ((char*) s + sizeof(*s));
+ s->sread_sz = sread_sz;
+ s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
+ s->swrite_sz = swrite_sz;
+
+ err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
+ if (err)
+ goto failed_async_init;
+
+ s->async.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&s->async);
+
+ err = uv_sem_init(&s->close_sem, 0);
+ if (err != 0)
+ goto failed_close_sem_init;
+
+ err = uv_sem_init(&s->async_sem, 0);
+ if (err != 0)
+ goto failed_async_sem_init;
+
+ s->fake_fd = fds[0];
+ s->int_fd = fds[1];
+
+ old_fd = *fd;
+ s->stream = stream;
+ stream->select = s;
+ *fd = s->fake_fd;
+
+ err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
+ if (err != 0)
+ goto failed_thread_create;
+
+ return 0;
+
+failed_thread_create:
+ s->stream = NULL;
+ stream->select = NULL;
+ *fd = old_fd;
+
+ uv_sem_destroy(&s->async_sem);
+
+failed_async_sem_init:
+ uv_sem_destroy(&s->close_sem);
+
+failed_close_sem_init:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+ return err;
+
+failed_async_init:
+ uv__free(s);
+
+failed_malloc:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+
+ return err;
+}
+#endif /* defined(__APPLE__) */
+
+
+int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
+#if defined(__APPLE__)
+ int enable;
+#endif
+
+ if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd))
+ return -EBUSY;
+
+ assert(fd >= 0);
+ stream->flags |= flags;
+
+ if (stream->type == UV_TCP) {
+ if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
+ return -errno;
+
+ /* TODO Use delay the user passed in. */
+ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
+ return -errno;
+ }
+
+#if defined(__APPLE__)
+ enable = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
+ errno != ENOTSOCK &&
+ errno != EINVAL) {
+ return -errno;
+ }
+#endif
+
+ stream->io_watcher.fd = fd;
+
+ return 0;
+}
+
+
+void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
+ uv_write_t* req;
+ QUEUE* q;
+ while (!QUEUE_EMPTY(&stream->write_queue)) {
+ q = QUEUE_HEAD(&stream->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ req->error = error;
+
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ }
+}
+
+
+void uv__stream_destroy(uv_stream_t* stream) {
+ assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT));
+ assert(stream->flags & UV_CLOSED);
+
+ if (stream->connect_req) {
+ uv__req_unregister(stream->loop, stream->connect_req);
+ stream->connect_req->cb(stream->connect_req, -ECANCELED);
+ stream->connect_req = NULL;
+ }
+
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+
+ if (stream->shutdown_req) {
+ /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
+ * fait accompli at this point. Maybe we should revisit this in v0.11.
+ * A possible reason for leaving it unchanged is that it informs the
+ * callee that the handle has been destroyed.
+ */
+ uv__req_unregister(stream->loop, stream->shutdown_req);
+ stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED);
+ stream->shutdown_req = NULL;
+ }
+
+ assert(stream->write_queue_size == 0);
+}
+
+
+/* Implements a best effort approach to mitigating accept() EMFILE errors.
+ * We have a spare file descriptor stashed away that we close to get below
+ * the EMFILE limit. Next, we accept all pending connections and close them
+ * immediately to signal the clients that we're overloaded - and we are, but
+ * we still keep on trucking.
+ *
+ * There is one caveat: it's not reliable in a multi-threaded environment.
+ * The file descriptor limit is per process. Our party trick fails if another
+ * thread opens a file or creates a socket in the time window between us
+ * calling close() and accept().
+ */
+static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
+ int err;
+ int emfile_fd;
+
+ if (loop->emfile_fd == -1)
+ return -EMFILE;
+
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+
+ do {
+ err = uv__accept(accept_fd);
+ if (err >= 0)
+ uv__close(err);
+ } while (err >= 0 || err == -EINTR);
+
+ emfile_fd = uv__open_cloexec("/", O_RDONLY);
+ if (emfile_fd >= 0)
+ loop->emfile_fd = emfile_fd;
+
+ return err;
+}
+
+
+#if defined(UV_HAVE_KQUEUE)
+# define UV_DEC_BACKLOG(w) w->rcount--;
+#else
+# define UV_DEC_BACKLOG(w) /* no-op */
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+ int err;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+ assert(events == UV__POLLIN);
+ assert(stream->accepted_fd == -1);
+ assert(!(stream->flags & UV_CLOSING));
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+
+ /* connection_cb can close the server socket while we're
+ * in the loop so check it on each iteration.
+ */
+ while (uv__stream_fd(stream) != -1) {
+ assert(stream->accepted_fd == -1);
+
+#if defined(UV_HAVE_KQUEUE)
+ if (w->rcount <= 0)
+ return;
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+ err = uv__accept(uv__stream_fd(stream));
+ if (err < 0) {
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ return; /* Not an error. */
+
+ if (err == -ECONNABORTED)
+ continue; /* Ignore. Nothing we can do about that. */
+
+ if (err == -EMFILE || err == -ENFILE) {
+ err = uv__emfile_trick(loop, uv__stream_fd(stream));
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ break;
+ }
+
+ stream->connection_cb(stream, err);
+ continue;
+ }
+
+ UV_DEC_BACKLOG(w)
+ stream->accepted_fd = err;
+ stream->connection_cb(stream, 0);
+
+ if (stream->accepted_fd != -1) {
+ /* The user hasn't yet accepted called uv_accept() */
+ uv__io_stop(loop, &stream->io_watcher, UV__POLLIN);
+ return;
+ }
+
+ if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
+ /* Give other processes a chance to accept connections. */
+ struct timespec timeout = { 0, 1 };
+ nanosleep(&timeout, NULL);
+ }
+ }
+}
+
+
+#undef UV_DEC_BACKLOG
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ /* TODO document this */
+ assert(server->loop == client->loop);
+
+ if (server->accepted_fd == -1)
+ return -EAGAIN;
+
+ switch (client->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ err = uv__stream_open(client,
+ server->accepted_fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err) {
+ /* TODO handle error */
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ case UV_UDP:
+ err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
+ if (err) {
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+done:
+ /* Process queued fds */
+ if (server->queued_fds != NULL) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ queued_fds = server->queued_fds;
+
+ /* Read first */
+ server->accepted_fd = queued_fds->fds[0];
+
+ /* All read, free */
+ assert(queued_fds->offset > 0);
+ if (--queued_fds->offset == 0) {
+ uv__free(queued_fds);
+ server->queued_fds = NULL;
+ } else {
+ /* Shift rest */
+ memmove(queued_fds->fds,
+ queued_fds->fds + 1,
+ queued_fds->offset * sizeof(*queued_fds->fds));
+ }
+ } else {
+ server->accepted_fd = -1;
+ if (err == 0)
+ uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
+ }
+ return err;
+}
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (err == 0)
+ uv__handle_start(stream);
+
+ return err;
+}
+
+
+static void uv__drain(uv_stream_t* stream) {
+ uv_shutdown_t* req;
+ int err;
+
+ assert(QUEUE_EMPTY(&stream->write_queue));
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ /* Shutdown? */
+ if ((stream->flags & UV_STREAM_SHUTTING) &&
+ !(stream->flags & UV_CLOSING) &&
+ !(stream->flags & UV_STREAM_SHUT)) {
+ assert(stream->shutdown_req);
+
+ req = stream->shutdown_req;
+ stream->shutdown_req = NULL;
+ stream->flags &= ~UV_STREAM_SHUTTING;
+ uv__req_unregister(stream->loop, req);
+
+ err = 0;
+ if (shutdown(uv__stream_fd(stream), SHUT_WR))
+ err = -errno;
+
+ if (err == 0)
+ stream->flags |= UV_STREAM_SHUT;
+
+ if (req->cb != NULL)
+ req->cb(req, err);
+ }
+}
+
+
+static size_t uv__write_req_size(uv_write_t* req) {
+ size_t size;
+
+ assert(req->bufs != NULL);
+ size = uv__count_bufs(req->bufs + req->write_index,
+ req->nbufs - req->write_index);
+ assert(req->handle->write_queue_size >= size);
+
+ return size;
+}
+
+
+static void uv__write_req_finish(uv_write_t* req) {
+ uv_stream_t* stream = req->handle;
+
+ /* Pop the req off tcp->write_queue. */
+ QUEUE_REMOVE(&req->queue);
+
+ /* Only free when there was no error. On error, we touch up write_queue_size
+ * right before making the callback. The reason we don't do that right away
+ * is that a write_queue_size > 0 is our only way to signal to the user that
+ * they should stop writing - which they should if we got an error. Something
+ * to revisit in future revisions of the libuv API.
+ */
+ if (req->error == 0) {
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* Add it to the write_completed_queue where it will have its
+ * callback called in the near future.
+ */
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ uv__io_feed(stream->loop, &stream->io_watcher);
+}
+
+
+static int uv__handle_fd(uv_handle_t* handle) {
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ return ((uv_stream_t*) handle)->io_watcher.fd;
+
+ case UV_UDP:
+ return ((uv_udp_t*) handle)->io_watcher.fd;
+
+ default:
+ return -1;
+ }
+}
+
+static void uv__write(uv_stream_t* stream) {
+ struct iovec* iov;
+ QUEUE* q;
+ uv_write_t* req;
+ int iovmax;
+ int iovcnt;
+ ssize_t n;
+
+start:
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (QUEUE_EMPTY(&stream->write_queue))
+ return;
+
+ q = QUEUE_HEAD(&stream->write_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ assert(req->handle == stream);
+
+ /*
+ * Cast to iovec. We had to have our own uv_buf_t instead of iovec
+ * because Windows's WSABUF is not an iovec.
+ */
+ assert(sizeof(uv_buf_t) == sizeof(struct iovec));
+ iov = (struct iovec*) &(req->bufs[req->write_index]);
+ iovcnt = req->nbufs - req->write_index;
+
+ iovmax = uv__getiovmax();
+
+ /* Limit iov count to avoid EINVALs from writev() */
+ if (iovcnt > iovmax)
+ iovcnt = iovmax;
+
+ /*
+ * Now do the actual writev. Note that we've been updating the pointers
+ * inside the iov each time we write. So there is no need to offset it.
+ */
+
+ if (req->send_handle) {
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+ char scratch[64] = {0};
+
+ assert(fd_to_send >= 0);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = iovcnt;
+ msg.msg_flags = 0;
+
+ msg.msg_control = (void*) scratch;
+ msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ *pi = fd_to_send;
+ }
+
+ do {
+ n = sendmsg(uv__stream_fd(stream), &msg, 0);
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ } else {
+ do {
+ if (iovcnt == 1) {
+ n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
+ } else {
+ n = writev(uv__stream_fd(stream), iov, iovcnt);
+ }
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ }
+
+ if (n < 0) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ /* Error */
+ req->error = -errno;
+ uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLIN))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ return;
+ } else if (stream->flags & UV_STREAM_BLOCKING) {
+ /* If this is a blocking stream, try again. */
+ goto start;
+ }
+ } else {
+ /* Successful write */
+
+ while (n >= 0) {
+ uv_buf_t* buf = &(req->bufs[req->write_index]);
+ size_t len = buf->len;
+
+ assert(req->write_index < req->nbufs);
+
+ if ((size_t)n < len) {
+ buf->base += n;
+ buf->len -= n;
+ stream->write_queue_size -= n;
+ n = 0;
+
+ /* There is more to write. */
+ if (stream->flags & UV_STREAM_BLOCKING) {
+ /*
+ * If we're blocking then we should not be enabling the write
+ * watcher - instead we need to try again.
+ */
+ goto start;
+ } else {
+ /* Break loop and ensure the watcher is pending. */
+ break;
+ }
+
+ } else {
+ /* Finished writing the buf at index req->write_index. */
+ req->write_index++;
+
+ assert((size_t)n >= len);
+ n -= len;
+
+ assert(stream->write_queue_size >= len);
+ stream->write_queue_size -= len;
+
+ if (req->write_index == req->nbufs) {
+ /* Then we're done! */
+ assert(n == 0);
+ uv__write_req_finish(req);
+ /* TODO: start trying to write the next request. */
+ return;
+ }
+ }
+ }
+ }
+
+ /* Either we've counted n down to zero or we've got EAGAIN. */
+ assert(n == 0 || n == -1);
+
+ /* Only non-blocking streams should use the write_watcher. */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+
+ /* We're not done. */
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+
+ /* Notify select() thread about state change */
+ uv__stream_osx_interrupt_select(stream);
+}
+
+
+static void uv__write_callbacks(uv_stream_t* stream) {
+ uv_write_t* req;
+ QUEUE* q;
+
+ while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
+ /* Pop a req off write_completed_queue. */
+ q = QUEUE_HEAD(&stream->write_completed_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ QUEUE_REMOVE(q);
+ uv__req_unregister(stream->loop, req);
+
+ if (req->bufs != NULL) {
+ stream->write_queue_size -= uv__write_req_size(req);
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* NOTE: call callback AFTER freeing the request data. */
+ if (req->cb)
+ req->cb(req, req->error);
+ }
+
+ assert(QUEUE_EMPTY(&stream->write_completed_queue));
+}
+
+
+uv_handle_type uv__handle_type(int fd) {
+ struct sockaddr_storage ss;
+ socklen_t len;
+ int type;
+
+ memset(&ss, 0, sizeof(ss));
+ len = sizeof(ss);
+
+ if (getsockname(fd, (struct sockaddr*)&ss, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof type;
+
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_STREAM) {
+ switch (ss.ss_family) {
+ case AF_UNIX:
+ return UV_NAMED_PIPE;
+ case AF_INET:
+ case AF_INET6:
+ return UV_TCP;
+ }
+ }
+
+ if (type == SOCK_DGRAM &&
+ (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
+ return UV_UDP;
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
+ stream->flags |= UV_STREAM_READ_EOF;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ stream->read_cb(stream, UV_EOF, buf);
+ stream->flags &= ~UV_STREAM_READING;
+}
+
+
+static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
+ uv__stream_queued_fds_t* queued_fds;
+ unsigned int queue_size;
+
+ queued_fds = stream->queued_fds;
+ if (queued_fds == NULL) {
+ queue_size = 8;
+ queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ queued_fds->offset = 0;
+ stream->queued_fds = queued_fds;
+
+ /* Grow */
+ } else if (queued_fds->size == queued_fds->offset) {
+ queue_size = queued_fds->size + 8;
+ queued_fds = uv__realloc(queued_fds,
+ (queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+
+ /*
+ * Allocation failure, report back.
+ * NOTE: if it is fatal - sockets will be closed in uv__stream_close
+ */
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ stream->queued_fds = queued_fds;
+ }
+
+ /* Put fd in a queue */
+ queued_fds->fds[queued_fds->offset++] = fd;
+
+ return 0;
+}
+
+
+#define UV__CMSG_FD_COUNT 64
+#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
+
+
+static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
+ struct cmsghdr* cmsg;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ char* start;
+ char* end;
+ int err;
+ void* pv;
+ int* pi;
+ unsigned int i;
+ unsigned int count;
+
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
+ cmsg->cmsg_type);
+ continue;
+ }
+
+ /* silence aliasing warning */
+ pv = CMSG_DATA(cmsg);
+ pi = pv;
+
+ /* Count available fds */
+ start = (char*) cmsg;
+ end = (char*) cmsg + cmsg->cmsg_len;
+ count = 0;
+ while (start + CMSG_LEN(count * sizeof(*pi)) < end)
+ count++;
+ assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
+
+ for (i = 0; i < count; i++) {
+ /* Already has accepted fd, queue now */
+ if (stream->accepted_fd != -1) {
+ err = uv__stream_queue_fd(stream, pi[i]);
+ if (err != 0) {
+ /* Close rest */
+ for (; i < count; i++)
+ uv__close(pi[i]);
+ return err;
+ }
+ } else {
+ stream->accepted_fd = pi[i];
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void uv__read(uv_stream_t* stream) {
+ uv_buf_t buf;
+ ssize_t nread;
+ struct msghdr msg;
+ char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
+ int count;
+ int err;
+ int is_ipc;
+
+ stream->flags &= ~UV_STREAM_READ_PARTIAL;
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
+
+ /* XXX: Maybe instead of having UV_STREAM_READING we just test if
+ * tcp->read_cb is NULL or not?
+ */
+ while (stream->read_cb
+ && (stream->flags & UV_STREAM_READING)
+ && (count-- > 0)) {
+ assert(stream->alloc_cb != NULL);
+
+ stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
+ if (buf.len == 0) {
+ /* User indicates it can't or won't handle the read. */
+ stream->read_cb(stream, UV_ENOBUFS, &buf);
+ return;
+ }
+
+ assert(buf.base != NULL);
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (!is_ipc) {
+ do {
+ nread = read(uv__stream_fd(stream), buf.base, buf.len);
+ }
+ while (nread < 0 && errno == EINTR);
+ } else {
+ /* ipc uses recvmsg */
+ msg.msg_flags = 0;
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ /* Set up to receive a descriptor even if one isn't in the message */
+ msg.msg_controllen = sizeof(cmsg_space);
+ msg.msg_control = cmsg_space;
+
+ do {
+ nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
+ }
+ while (nread < 0 && errno == EINTR);
+ }
+
+ if (nread < 0) {
+ /* Error */
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /* Wait for the next one. */
+ if (stream->flags & UV_STREAM_READING) {
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ stream->read_cb(stream, 0, &buf);
+ } else {
+ /* Error. User should call uv_close(). */
+ stream->read_cb(stream, -errno, &buf);
+ if (stream->flags & UV_STREAM_READING) {
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ }
+ return;
+ } else if (nread == 0) {
+ uv__stream_eof(stream, &buf);
+ return;
+ } else {
+ /* Successful read */
+ ssize_t buflen = buf.len;
+
+ if (is_ipc) {
+ err = uv__stream_recv_cmsg(stream, &msg);
+ if (err != 0) {
+ stream->read_cb(stream, err, &buf);
+ return;
+ }
+ }
+ stream->read_cb(stream, nread, &buf);
+
+ /* Return if we didn't fill the buffer, there is no more data to read. */
+ if (nread < buflen) {
+ stream->flags |= UV_STREAM_READ_PARTIAL;
+ return;
+ }
+ }
+ }
+}
+
+
+#undef UV__CMSG_FD_COUNT
+#undef UV__CMSG_FD_SIZE
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
+ assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
+ "uv_shutdown (unix) only supports uv_handle_t right now");
+
+ if (!(stream->flags & UV_STREAM_WRITABLE) ||
+ stream->flags & UV_STREAM_SHUT ||
+ stream->flags & UV_STREAM_SHUTTING ||
+ stream->flags & UV_CLOSED ||
+ stream->flags & UV_CLOSING) {
+ return -ENOTCONN;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Initialize request */
+ uv__req_init(stream->loop, req, UV_SHUTDOWN);
+ req->handle = stream;
+ req->cb = cb;
+ stream->shutdown_req = req;
+ stream->flags |= UV_STREAM_SHUTTING;
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+
+ assert(stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+ assert(!(stream->flags & UV_CLOSING));
+
+ if (stream->connect_req) {
+ uv__stream_connect(stream);
+ return;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
+ if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP))
+ uv__read(stream);
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ /* Short-circuit iff POLLHUP is set, the user is still interested in read
+ * events and uv__read() reported a partial read but not EOF. If the EOF
+ * flag is set, uv__read() called read_cb with err=UV_EOF and we don't
+ * have to do anything. If the partial read flag is not set, we can't
+ * report the EOF yet because there is still data to read.
+ */
+ if ((events & UV__POLLHUP) &&
+ (stream->flags & UV_STREAM_READING) &&
+ (stream->flags & UV_STREAM_READ_PARTIAL) &&
+ !(stream->flags & UV_STREAM_READ_EOF)) {
+ uv_buf_t buf = { NULL, 0 };
+ uv__stream_eof(stream, &buf);
+ }
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) {
+ uv__write(stream);
+ uv__write_callbacks(stream);
+
+ /* Write queue drained. */
+ if (QUEUE_EMPTY(&stream->write_queue))
+ uv__drain(stream);
+ }
+}
+
+
+/**
+ * We get called here from directly following a call to connect(2).
+ * In order to determine if we've errored out or succeeded must call
+ * getsockopt.
+ */
+static void uv__stream_connect(uv_stream_t* stream) {
+ int error;
+ uv_connect_t* req = stream->connect_req;
+ socklen_t errorsize = sizeof(int);
+
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE);
+ assert(req);
+
+ if (stream->delayed_error) {
+ /* To smooth over the differences between unixes errors that
+ * were reported synchronously on the first connect can be delayed
+ * until the next tick--which is now.
+ */
+ error = stream->delayed_error;
+ stream->delayed_error = 0;
+ } else {
+ /* Normal situation: we need to get the socket error from the kernel. */
+ assert(uv__stream_fd(stream) >= 0);
+ getsockopt(uv__stream_fd(stream),
+ SOL_SOCKET,
+ SO_ERROR,
+ &error,
+ &errorsize);
+ error = -error;
+ }
+
+ if (error == -EINPROGRESS)
+ return;
+
+ stream->connect_req = NULL;
+ uv__req_unregister(stream->loop, req);
+
+ if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ }
+
+ if (req->cb)
+ req->cb(req, error);
+
+ if (uv__stream_fd(stream) == -1)
+ return;
+
+ if (error < 0) {
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+ }
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int empty_queue;
+
+ assert(nbufs > 0);
+ assert((stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY) &&
+ "uv_write (unix) does not yet support other types of streams");
+
+ if (uv__stream_fd(stream) < 0)
+ return -EBADF;
+
+ if (send_handle) {
+ if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
+ return -EINVAL;
+
+ /* XXX We abuse uv_write2() to send over UDP handles to child processes.
+ * Don't call uv__stream_fd() on those handles, it's a macro that on OS X
+ * evaluates to a function that operates on a uv_stream_t with a couple of
+ * OS X specific fields. On other Unices it does (handle)->io_watcher.fd,
+ * which works but only by accident.
+ */
+ if (uv__handle_fd((uv_handle_t*) send_handle) < 0)
+ return -EBADF;
+ }
+
+ /* It's legal for write_queue_size > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up write_queue_size later, see also uv__write_req_finish().
+ * We could check that write_queue is empty instead but that implies making
+ * a write() syscall when we know that the handle is in error mode.
+ */
+ empty_queue = (stream->write_queue_size == 0);
+
+ /* Initialize the req */
+ uv__req_init(stream->loop, req, UV_WRITE);
+ req->cb = cb;
+ req->handle = stream;
+ req->error = 0;
+ req->send_handle = send_handle;
+ QUEUE_INIT(&req->queue);
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL)
+ return -ENOMEM;
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ req->nbufs = nbufs;
+ req->write_index = 0;
+ stream->write_queue_size += uv__count_bufs(bufs, nbufs);
+
+ /* Append the request to write_queue. */
+ QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
+
+ /* If the queue was empty when this function began, we should attempt to
+ * do the write immediately. Otherwise start the write_watcher and wait
+ * for the fd to become writable.
+ */
+ if (stream->connect_req) {
+ /* Still connecting, do nothing. */
+ }
+ else if (empty_queue) {
+ uv__write(stream);
+ }
+ else {
+ /*
+ * blocking streams should never have anything in the queue.
+ * if this assert fires then somehow the blocking stream isn't being
+ * sufficiently flushed in uv__write.
+ */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ return 0;
+}
+
+
+/* The buffers to be written must remain valid until the callback is called.
+ * This is not required for the uv_buf_t array.
+ */
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_write2(req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+void uv_try_write_cb(uv_write_t* req, int status) {
+ /* Should not be called */
+ abort();
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int r;
+ int has_pollout;
+ size_t written;
+ size_t req_size;
+ uv_write_t req;
+
+ /* Connecting or already writing some data */
+ if (stream->connect_req != NULL || stream->write_queue_size != 0)
+ return -EAGAIN;
+
+ has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT);
+
+ r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
+ if (r != 0)
+ return r;
+
+ /* Remove not written bytes from write queue size */
+ written = uv__count_bufs(bufs, nbufs);
+ if (req.bufs != NULL)
+ req_size = uv__write_req_size(&req);
+ else
+ req_size = 0;
+ written -= req_size;
+ stream->write_queue_size -= req_size;
+
+ /* Unqueue request, regardless of immediateness */
+ QUEUE_REMOVE(&req.queue);
+ uv__req_unregister(stream->loop, &req);
+ if (req.bufs != req.bufsml)
+ uv__free(req.bufs);
+ req.bufs = NULL;
+
+ /* Do not poll for writable, if we wasn't before calling this */
+ if (!has_pollout) {
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ if (written == 0 && req_size != 0)
+ return -EAGAIN;
+ else
+ return written;
+}
+
+
+int uv_read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+
+ if (stream->flags & UV_CLOSING)
+ return -EINVAL;
+
+ /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
+ * expresses the desired state of the user.
+ */
+ stream->flags |= UV_STREAM_READING;
+
+ /* TODO: try to do the read inline? */
+ /* TODO: keep track of tcp state. If we've gotten a EOF then we should
+ * not start the IO watcher.
+ */
+ assert(uv__stream_fd(stream) >= 0);
+ assert(alloc_cb);
+
+ stream->read_cb = read_cb;
+ stream->alloc_cb = alloc_cb;
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+ uv__handle_start(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+int uv_read_stop(uv_stream_t* stream) {
+ if (!(stream->flags & UV_STREAM_READING))
+ return 0;
+
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_WRITABLE);
+}
+
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle) {
+ const uv__stream_select_t* s;
+
+ assert(handle->type == UV_TCP ||
+ handle->type == UV_TTY ||
+ handle->type == UV_NAMED_PIPE);
+
+ s = handle->select;
+ if (s != NULL)
+ return s->fd;
+
+ return handle->io_watcher.fd;
+}
+#endif /* defined(__APPLE__) */
+
+
+void uv__stream_close(uv_stream_t* handle) {
+ unsigned int i;
+ uv__stream_queued_fds_t* queued_fds;
+
+#if defined(__APPLE__)
+ /* Terminate select loop first */
+ if (handle->select != NULL) {
+ uv__stream_select_t* s;
+
+ s = handle->select;
+
+ uv_sem_post(&s->close_sem);
+ uv_sem_post(&s->async_sem);
+ uv__stream_osx_interrupt_select(handle);
+ uv_thread_join(&s->thread);
+ uv_sem_destroy(&s->close_sem);
+ uv_sem_destroy(&s->async_sem);
+ uv__close(s->fake_fd);
+ uv__close(s->int_fd);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+
+ handle->select = NULL;
+ }
+#endif /* defined(__APPLE__) */
+
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv_read_stop(handle);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ /* Don't close stdio file descriptors. Nothing good comes from it. */
+ if (handle->io_watcher.fd > STDERR_FILENO)
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+
+ if (handle->accepted_fd != -1) {
+ uv__close(handle->accepted_fd);
+ handle->accepted_fd = -1;
+ }
+
+ /* Close all queued fds */
+ if (handle->queued_fds != NULL) {
+ queued_fds = handle->queued_fds;
+ for (i = 0; i < queued_fds->offset; i++)
+ uv__close(queued_fds->fds[i]);
+ uv__free(handle->queued_fds);
+ handle->queued_fds = NULL;
+ }
+
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ /* Don't need to check the file descriptor, uv__nonblock()
+ * will fail with EBADF if it's not valid.
+ */
+ return uv__nonblock(uv__stream_fd(handle), !blocking);
+}
diff --git a/3rdparty/libuv/src/unix/sunos.c b/3rdparty/libuv/src/unix/sunos.c
new file mode 100644
index 00000000000..0c46817b446
--- /dev/null
+++ b/3rdparty/libuv/src/unix/sunos.c
@@ -0,0 +1,765 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#ifndef SUNOS_NO_IFADDRS
+# include <ifaddrs.h>
+#endif
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <sys/loadavg.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+
+#include <sys/port.h>
+#include <port.h>
+
+#define PORT_FIRED 0x69
+#define PORT_UNUSED 0x0
+#define PORT_LOADED 0x99
+#define PORT_DELETED -1
+
+#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
+#define PROCFS_FILE_OFFSET_BITS_HACK 1
+#undef _FILE_OFFSET_BITS
+#else
+#define PROCFS_FILE_OFFSET_BITS_HACK 0
+#endif
+
+#include <procfs.h>
+
+#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int err;
+ int fd;
+
+ loop->fs_fd = -1;
+ loop->backend_fd = -1;
+
+ fd = port_create();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+ loop->backend_fd = fd;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct port_event* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct port_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].portev_object == fd)
+ events[i].portev_object = -1;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct port_event events[1024];
+ struct port_event* pe;
+ struct timespec spec;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ unsigned int nfds;
+ unsigned int i;
+ int saved_errno;
+ int nevents;
+ int count;
+ int err;
+ int fd;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+
+ if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
+ abort();
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ /* Work around a kernel bug where nfds is not updated. */
+ events[0].portev_source = 0;
+
+ nfds = 1;
+ saved_errno = 0;
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ err = port_getn(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ &nfds,
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ if (err) {
+ /* Work around another kernel bug: port_getn() may return events even
+ * on error.
+ */
+ if (errno == EINTR || errno == ETIME)
+ saved_errno = errno;
+ else
+ abort();
+ }
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (events[0].portev_source == 0) {
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ goto update_timeout;
+ }
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->portev_object;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ /* File descriptor that we've stopped watching, ignore. */
+ if (w == NULL)
+ continue;
+
+ w->cb(loop, w, pe->portev_events);
+ nevents++;
+
+ if (w != loop->watchers[fd])
+ continue; /* Disabled by callback. */
+
+ /* Events Ports operates in oneshot mode, rearm timer on next run. */
+ if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (saved_errno == ETIME) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ return gethrtime();
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t res;
+ char buf[128];
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
+
+ res = *size - 1;
+ if (res > 0)
+ res = readlink(buf, buffer, res);
+
+ if (res == -1)
+ return -errno;
+
+ buffer[res] = '\0';
+ *size = res;
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ (void) getloadavg(avg, 3);
+}
+
+
+#if defined(PORT_SOURCE_FILE)
+
+static int uv__fs_event_rearm(uv_fs_event_t *handle) {
+ if (handle->fd == -1)
+ return -EBADF;
+
+ if (port_associate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo,
+ FILE_ATTRIB | FILE_MODIFIED,
+ handle) == -1) {
+ return -errno;
+ }
+ handle->fd = PORT_LOADED;
+
+ return 0;
+}
+
+
+static void uv__fs_event_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents) {
+ uv_fs_event_t *handle = NULL;
+ timespec_t timeout;
+ port_event_t pe;
+ int events;
+ int r;
+
+ (void) w;
+ (void) revents;
+
+ do {
+ uint_t n = 1;
+
+ /*
+ * Note that our use of port_getn() here (and not port_get()) is deliberate:
+ * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
+ * causes port_get() to return success instead of ETIME when there aren't
+ * actually any events (!); by using port_getn() in lieu of port_get(),
+ * we can at least workaround the bug by checking for zero returned events
+ * and treating it as we would ETIME.
+ */
+ do {
+ memset(&timeout, 0, sizeof timeout);
+ r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if ((r == -1 && errno == ETIME) || n == 0)
+ break;
+
+ handle = (uv_fs_event_t*) pe.portev_user;
+ assert((r == 0) && "unexpected port_get() error");
+
+ events = 0;
+ if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_CHANGE;
+ if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_RENAME;
+ assert(events != 0);
+ handle->fd = PORT_FIRED;
+ handle->cb(handle, NULL, events, 0);
+
+ if (handle->fd != PORT_DELETED) {
+ r = uv__fs_event_rearm(handle);
+ if (r != 0)
+ handle->cb(handle, NULL, 0, r);
+ }
+ }
+ while (handle->fd != PORT_DELETED);
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int portfd;
+ int first_run;
+ int err;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ first_run = 0;
+ if (handle->loop->fs_fd == -1) {
+ portfd = port_create();
+ if (portfd == -1)
+ return -errno;
+ handle->loop->fs_fd = portfd;
+ first_run = 1;
+ }
+
+ uv__handle_start(handle);
+ handle->path = uv__strdup(path);
+ handle->fd = PORT_UNUSED;
+ handle->cb = cb;
+
+ memset(&handle->fo, 0, sizeof handle->fo);
+ handle->fo.fo_name = handle->path;
+ err = uv__fs_event_rearm(handle);
+ if (err != 0)
+ return err;
+
+ if (first_run) {
+ uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
+ uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN);
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
+ port_dissociate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo);
+ }
+
+ handle->fd = PORT_DELETED;
+ uv__free(handle->path);
+ handle->path = NULL;
+ handle->fo.fo_name = NULL;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
+
+#else /* !defined(PORT_SOURCE_FILE) */
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ UNREACHABLE();
+}
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ fd = open("/proc/self/psinfo", O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+
+ long hz = sysconf(_SC_CLK_TCK);
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ *uptime = -1;
+ } else {
+ knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
+ *uptime = knp->value.ul / hz;
+ }
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ int lookup_instance;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ uv_cpu_info_t* cpu_info;
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ /* Get count of cpus */
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ lookup_instance++;
+ }
+
+ *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ kstat_close(kc);
+ return -ENOMEM;
+ }
+
+ *count = lookup_instance;
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->speed = 0;
+ cpu_info->model = NULL;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
+ assert(knp->data_type == KSTAT_DATA_INT32 ||
+ knp->data_type == KSTAT_DATA_INT64);
+ cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
+ : knp->value.i64;
+
+ knp = kstat_data_lookup(ksp, (char*) "brand");
+ assert(knp->data_type == KSTAT_DATA_STRING);
+ cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ for (;;) {
+ ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
+
+ if (ksp == NULL)
+ break;
+
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->cpu_times.user = 0;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.user = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.sys = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.idle = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "intr");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.irq = knp->value.ui64;
+ cpu_info->cpu_times.nice = 0;
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+#ifdef SUNOS_NO_IFADDRS
+ return -ENOSYS;
+#else
+ uv_interface_address_t* address;
+ struct sockaddr_dl* sa_addr;
+ struct ifaddrs* addrs;
+ struct ifaddrs* ent;
+ int i;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == PF_PACKET)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
+ (ent->ifa_flags & IFF_LOOPBACK));
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+#endif /* SUNOS_NO_IFADDRS */
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/tcp.c b/3rdparty/libuv/src/unix/tcp.c
new file mode 100644
index 00000000000..6d213a49778
--- /dev/null
+++ b/3rdparty/libuv/src/unix/tcp.c
@@ -0,0 +1,362 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+ int sockfd;
+ int err;
+
+ if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ err = uv__socket(domain, SOCK_STREAM, 0);
+ if (err < 0)
+ return err;
+ sockfd = err;
+
+ err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ int err = maybe_new_socket(tcp, domain, 0);
+ if (err) {
+ QUEUE_REMOVE(&tcp->handle_queue);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
+ return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
+}
+
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int on;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ err = maybe_new_socket(tcp,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ on = 1;
+ if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
+ return -errno;
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+ if (setsockopt(tcp->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ &on,
+ sizeof on) == -1) {
+ return -errno;
+ }
+ }
+#endif
+
+ errno = 0;
+ if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ return -EINVAL;
+ return -errno;
+ }
+ tcp->delayed_error = -errno;
+
+ if (addr->sa_family == AF_INET6)
+ tcp->flags |= UV_HANDLE_IPV6;
+
+ return 0;
+}
+
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+ int r;
+
+ assert(handle->type == UV_TCP);
+
+ if (handle->connect_req != NULL)
+ return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
+
+ err = maybe_new_socket(handle,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ handle->delayed_error = 0;
+
+ do
+ r = connect(uv__stream_fd(handle), addr, addrlen);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1) {
+ if (errno == EINPROGRESS)
+ ; /* not an error */
+ else if (errno == ECONNREFUSED)
+ /* If we get a ECONNREFUSED wait until the next tick to report the
+ * error. Solaris wants to report immediately--other unixes want to
+ * wait.
+ */
+ handle->delayed_error = -errno;
+ else
+ return -errno;
+ }
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->cb = cb;
+ req->handle = (uv_stream_t*) handle;
+ QUEUE_INIT(&req->queue);
+ handle->connect_req = req;
+
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
+
+ if (handle->delayed_error)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+ return 0;
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ return uv__stream_open((uv_stream_t*)handle,
+ sock,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getpeername(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
+ static int single_accept = -1;
+ int err;
+
+ if (tcp->delayed_error)
+ return tcp->delayed_error;
+
+ if (single_accept == -1) {
+ const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
+ single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
+ }
+
+ if (single_accept)
+ tcp->flags |= UV_TCP_SINGLE_ACCEPT;
+
+ err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
+ if (err)
+ return err;
+
+ if (listen(tcp->io_watcher.fd, backlog))
+ return -errno;
+
+ tcp->connection_cb = cb;
+
+ /* Start listening for connections. */
+ tcp->io_watcher.cb = uv__server_io;
+ uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+int uv__tcp_nodelay(int fd, int on) {
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
+ return -errno;
+ return 0;
+}
+
+
+int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
+ return -errno;
+
+#ifdef TCP_KEEPIDLE
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ /* Solaris/SmartOS, if you don't support keep-alive,
+ * then don't advertise it in your system headers...
+ */
+ /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
+#if defined(TCP_KEEPALIVE) && !defined(__sun)
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err = uv__tcp_nodelay(uv__stream_fd(handle), on);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_NODELAY;
+ else
+ handle->flags &= ~UV_TCP_NODELAY;
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_KEEPALIVE;
+ else
+ handle->flags &= ~UV_TCP_KEEPALIVE;
+
+ /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
+ * uv_tcp_t with an int that's almost never used...
+ */
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (enable)
+ handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
+ else
+ handle->flags |= UV_TCP_SINGLE_ACCEPT;
+ return 0;
+}
+
+
+void uv__tcp_close(uv_tcp_t* handle) {
+ uv__stream_close((uv_stream_t*)handle);
+}
diff --git a/3rdparty/libuv/src/unix/thread.c b/3rdparty/libuv/src/unix/thread.c
new file mode 100644
index 00000000000..c56a3170259
--- /dev/null
+++ b/3rdparty/libuv/src/unix/thread.c
@@ -0,0 +1,525 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+};
+
+
+static void* uv__thread_start(void *arg)
+{
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ err = pthread_create(tid, NULL, uv__thread_start, ctx);
+
+ if (err)
+ uv__free(ctx);
+
+ return -err;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ return pthread_self();
+}
+
+int uv_thread_join(uv_thread_t *tid) {
+ return -pthread_join(*tid, NULL);
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return pthread_equal(*t1, *t2);
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
+ return -pthread_mutex_init(mutex, NULL);
+#else
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
+ abort();
+
+ err = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return -err;
+#endif
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ if (pthread_mutex_destroy(mutex))
+ abort();
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ if (pthread_mutex_lock(mutex))
+ abort();
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ int err;
+
+ err = pthread_mutex_trylock(mutex);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ if (pthread_mutex_unlock(mutex))
+ abort();
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ return -pthread_rwlock_init(rwlock, NULL);
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_destroy(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_rdlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_tryrdlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_wrlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_trywrlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ if (pthread_once(guard, callback))
+ abort();
+}
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ kern_return_t err;
+
+ err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_INVALID_ARGUMENT)
+ return -EINVAL;
+ if (err == KERN_RESOURCE_SHORTAGE)
+ return -ENOMEM;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (semaphore_destroy(mach_task_self(), *sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (semaphore_signal(*sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = semaphore_wait(*sem);
+ while (r == KERN_ABORTED);
+
+ if (r != KERN_SUCCESS)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ mach_timespec_t interval;
+ kern_return_t err;
+
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+
+ err = semaphore_timedwait(*sem, interval);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_OPERATION_TIMED_OUT)
+ return -EAGAIN;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ if (sem_init(sem, 0, value))
+ return -errno;
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (sem_destroy(sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (sem_post(sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_wait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_trywait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r) {
+ if (errno == EAGAIN)
+ return -EAGAIN;
+ abort();
+ }
+
+ return 0;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_cond_init(uv_cond_t* cond) {
+ return -pthread_cond_init(cond, NULL);
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_cond_init(uv_cond_t* cond) {
+ pthread_condattr_t attr;
+ int err;
+
+ err = pthread_condattr_init(&attr);
+ if (err)
+ return -err;
+
+#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ if (err)
+ goto error2;
+#endif
+
+ err = pthread_cond_init(cond, &attr);
+ if (err)
+ goto error2;
+
+ err = pthread_condattr_destroy(&attr);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ pthread_cond_destroy(cond);
+error2:
+ pthread_condattr_destroy(&attr);
+ return -err;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (pthread_cond_destroy(cond))
+ abort();
+}
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (pthread_cond_signal(cond))
+ abort();
+}
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (pthread_cond_broadcast(cond))
+ abort();
+}
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (pthread_cond_wait(cond, mutex))
+ abort();
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
+ int r;
+ struct timespec ts;
+
+#if defined(__APPLE__) && defined(__MACH__)
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+ r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
+#else
+ timeout += uv__hrtime(UV_CLOCK_PRECISE);
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ /*
+ * The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
+ * but has this alternative function instead.
+ */
+ r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
+#else
+ r = pthread_cond_timedwait(cond, mutex, &ts);
+#endif /* __ANDROID__ */
+#endif
+
+
+ if (r == 0)
+ return 0;
+
+ if (r == ETIMEDOUT)
+ return -ETIMEDOUT;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return -err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return -err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ return -pthread_barrier_init(barrier, NULL, count);
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ if (pthread_barrier_destroy(barrier))
+ abort();
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int r = pthread_barrier_wait(barrier);
+ if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+int uv_key_create(uv_key_t* key) {
+ return -pthread_key_create(key, NULL);
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (pthread_key_delete(*key))
+ abort();
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ return pthread_getspecific(*key);
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (pthread_setspecific(*key, value))
+ abort();
+}
diff --git a/3rdparty/libuv/src/unix/timer.c b/3rdparty/libuv/src/unix/timer.c
new file mode 100644
index 00000000000..ca3ec3db957
--- /dev/null
+++ b/3rdparty/libuv/src/unix/timer.c
@@ -0,0 +1,172 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "heap-inl.h"
+
+#include <assert.h>
+#include <limits.h>
+
+
+static int timer_less_than(const struct heap_node* ha,
+ const struct heap_node* hb) {
+ const uv_timer_t* a;
+ const uv_timer_t* b;
+
+ a = container_of(ha, const uv_timer_t, heap_node);
+ b = container_of(hb, const uv_timer_t, heap_node);
+
+ if (a->timeout < b->timeout)
+ return 1;
+ if (b->timeout < a->timeout)
+ return 0;
+
+ /* Compare start_id when both have the same timeout. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return 1;
+ if (b->start_id < a->start_id)
+ return 0;
+
+ return 0;
+}
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+ return 0;
+}
+
+
+int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat) {
+ uint64_t clamped_timeout;
+
+ if (cb == NULL)
+ return -EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ clamped_timeout = handle->loop->time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ handle->timer_cb = cb;
+ handle->timeout = clamped_timeout;
+ handle->repeat = repeat;
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ heap_insert((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ heap_remove((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ if (handle->timer_cb == NULL)
+ return -EINVAL;
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ return handle->repeat;
+}
+
+
+int uv__next_timeout(const uv_loop_t* loop) {
+ const struct heap_node* heap_node;
+ const uv_timer_t* handle;
+ uint64_t diff;
+
+ heap_node = heap_min((const struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ return -1; /* block indefinitely */
+
+ handle = container_of(heap_node, const uv_timer_t, heap_node);
+ if (handle->timeout <= loop->time)
+ return 0;
+
+ diff = handle->timeout - loop->time;
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ return diff;
+}
+
+
+void uv__run_timers(uv_loop_t* loop) {
+ struct heap_node* heap_node;
+ uv_timer_t* handle;
+
+ for (;;) {
+ heap_node = heap_min((struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ break;
+
+ handle = container_of(heap_node, uv_timer_t, heap_node);
+ if (handle->timeout > loop->time)
+ break;
+
+ uv_timer_stop(handle);
+ uv_timer_again(handle);
+ handle->timer_cb(handle);
+ }
+}
+
+
+void uv__timer_close(uv_timer_t* handle) {
+ uv_timer_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/tty.c b/3rdparty/libuv/src/unix/tty.c
new file mode 100644
index 00000000000..7cc5b714ed3
--- /dev/null
+++ b/3rdparty/libuv/src/unix/tty.c
@@ -0,0 +1,279 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "spinlock.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+static int orig_termios_fd = -1;
+static struct termios orig_termios;
+static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
+ uv_handle_type type;
+ int flags;
+ int newfd;
+ int r;
+
+ /* File descriptors that refer to files cannot be monitored with epoll.
+ * That restriction also applies to character devices like /dev/random
+ * (but obviously not /dev/tty.)
+ */
+ type = uv_guess_handle(fd);
+ if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
+ return -EINVAL;
+
+ flags = 0;
+ newfd = -1;
+
+ /* Reopen the file descriptor when it refers to a tty. This lets us put the
+ * tty in non-blocking mode without affecting other processes that share it
+ * with us.
+ *
+ * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
+ * affects fd 1 of `cat` because both file descriptors refer to the same
+ * struct file in the kernel. When we reopen our fd 0, it points to a
+ * different struct file, hence changing its properties doesn't affect
+ * other processes.
+ */
+ if (type == UV_TTY) {
+ r = uv__open_cloexec("/dev/tty", O_RDWR);
+
+ if (r < 0) {
+ /* fallback to using blocking writes */
+ if (!readable)
+ flags |= UV_STREAM_BLOCKING;
+ goto skip;
+ }
+
+ newfd = r;
+
+ r = uv__dup2_cloexec(newfd, fd);
+ if (r < 0 && r != -EINVAL) {
+ /* EINVAL means newfd == fd which could conceivably happen if another
+ * thread called close(fd) between our calls to isatty() and open().
+ * That's a rather unlikely event but let's handle it anyway.
+ */
+ uv__close(newfd);
+ return r;
+ }
+
+ fd = newfd;
+ }
+
+skip:
+ uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+#if defined(__APPLE__)
+ r = uv__stream_try_select((uv_stream_t*) tty, &fd);
+ if (r) {
+ if (newfd != -1)
+ uv__close(newfd);
+ QUEUE_REMOVE(&tty->handle_queue);
+ return r;
+ }
+#endif
+
+ if (readable)
+ flags |= UV_STREAM_READABLE;
+ else
+ flags |= UV_STREAM_WRITABLE;
+
+ if (!(flags & UV_STREAM_BLOCKING))
+ uv__nonblock(fd, 1);
+
+ uv__stream_open((uv_stream_t*) tty, fd, flags);
+ tty->mode = UV_TTY_MODE_NORMAL;
+
+ return 0;
+}
+
+static void uv__tty_make_raw(struct termios* tio) {
+ assert(tio != NULL);
+
+#ifdef __sun
+ /*
+ * This implementation of cfmakeraw for Solaris and derivatives is taken from
+ * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
+ */
+ tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
+ IGNCR | ICRNL | IXON);
+ tio->c_oflag &= ~OPOST;
+ tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ tio->c_cflag &= ~(CSIZE | PARENB);
+ tio->c_cflag |= CS8;
+#else
+ cfmakeraw(tio);
+#endif /* #ifdef __sun */
+}
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ struct termios tmp;
+ int fd;
+
+ if (tty->mode == (int) mode)
+ return 0;
+
+ fd = uv__stream_fd(tty);
+ if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
+ if (tcgetattr(fd, &tty->orig_termios))
+ return -errno;
+
+ /* This is used for uv_tty_reset_mode() */
+ uv_spinlock_lock(&termios_spinlock);
+ if (orig_termios_fd == -1) {
+ orig_termios = tty->orig_termios;
+ orig_termios_fd = fd;
+ }
+ uv_spinlock_unlock(&termios_spinlock);
+ }
+
+ tmp = tty->orig_termios;
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ break;
+ case UV_TTY_MODE_RAW:
+ tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ tmp.c_oflag |= (ONLCR);
+ tmp.c_cflag |= (CS8);
+ tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ tmp.c_cc[VMIN] = 1;
+ tmp.c_cc[VTIME] = 0;
+ break;
+ case UV_TTY_MODE_IO:
+ uv__tty_make_raw(&tmp);
+ break;
+ }
+
+ /* Apply changes after draining */
+ if (tcsetattr(fd, TCSADRAIN, &tmp))
+ return -errno;
+
+ tty->mode = mode;
+ return 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ struct winsize ws;
+
+ if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws))
+ return -errno;
+
+ *width = ws.ws_col;
+ *height = ws.ws_row;
+
+ return 0;
+}
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ struct sockaddr sa;
+ struct stat s;
+ socklen_t len;
+ int type;
+
+ if (file < 0)
+ return UV_UNKNOWN_HANDLE;
+
+ if (isatty(file))
+ return UV_TTY;
+
+ if (fstat(file, &s))
+ return UV_UNKNOWN_HANDLE;
+
+ if (S_ISREG(s.st_mode))
+ return UV_FILE;
+
+ if (S_ISCHR(s.st_mode))
+ return UV_FILE; /* XXX UV_NAMED_PIPE? */
+
+ if (S_ISFIFO(s.st_mode))
+ return UV_NAMED_PIPE;
+
+ if (!S_ISSOCK(s.st_mode))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(type);
+ if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(sa);
+ if (getsockname(file, &sa, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_DGRAM)
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_UDP;
+
+ if (type == SOCK_STREAM) {
+#if defined(_AIX)
+ /* on AIX the getsockname call returns an empty sa structure
+ * for sockets of type AF_UNIX. For all other types it will
+ * return a properly filled in structure.
+ */
+ if (len == 0)
+ return UV_NAMED_PIPE;
+#endif /* defined(_AIX) */
+
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_TCP;
+ if (sa.sa_family == AF_UNIX)
+ return UV_NAMED_PIPE;
+ }
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+/* This function is async signal-safe, meaning that it's safe to call from
+ * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
+ * critical section when the signal was raised.
+ */
+int uv_tty_reset_mode(void) {
+ int saved_errno;
+ int err;
+
+ saved_errno = errno;
+ if (!uv_spinlock_trylock(&termios_spinlock))
+ return -EBUSY; /* In uv_tty_set_mode(). */
+
+ err = 0;
+ if (orig_termios_fd != -1)
+ if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
+ err = -errno;
+
+ uv_spinlock_unlock(&termios_spinlock);
+ errno = saved_errno;
+
+ return err;
+}
diff --git a/3rdparty/libuv/src/unix/udp.c b/3rdparty/libuv/src/unix/udp.c
new file mode 100644
index 00000000000..39ade8de338
--- /dev/null
+++ b/3rdparty/libuv/src/unix/udp.c
@@ -0,0 +1,873 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
+# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+
+#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
+# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+
+
+static void uv__udp_run_completed(uv_udp_t* handle);
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
+static void uv__udp_recvmsg(uv_udp_t* handle);
+static void uv__udp_sendmsg(uv_udp_t* handle);
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags);
+
+
+void uv__udp_close(uv_udp_t* handle) {
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+}
+
+
+void uv__udp_finish_close(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
+ assert(handle->io_watcher.fd == -1);
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ req->status = -ECANCELED;
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ }
+
+ uv__udp_run_completed(handle);
+
+ assert(handle->send_queue_size == 0);
+ assert(handle->send_queue_count == 0);
+
+ /* Now tear down the handle. */
+ handle->recv_cb = NULL;
+ handle->alloc_cb = NULL;
+ /* but _do not_ touch close_cb */
+}
+
+
+static void uv__udp_run_completed(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!(handle->flags & UV_UDP_PROCESSING));
+ handle->flags |= UV_UDP_PROCESSING;
+
+ while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
+ q = QUEUE_HEAD(&handle->write_completed_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ uv__req_unregister(handle->loop, req);
+
+ handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count--;
+
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+
+ if (req->send_cb == NULL)
+ continue;
+
+ /* req->status >= 0 == bytes written
+ * req->status < 0 == errno
+ */
+ if (req->status >= 0)
+ req->send_cb(req, 0);
+ else
+ req->send_cb(req, req->status);
+ }
+
+ if (QUEUE_EMPTY(&handle->write_queue)) {
+ /* Pending queue and completion queue empty, stop watcher. */
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT);
+ if (!uv__io_active(&handle->io_watcher, UV__POLLIN))
+ uv__handle_stop(handle);
+ }
+
+ handle->flags &= ~UV_UDP_PROCESSING;
+}
+
+
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
+ uv_udp_t* handle;
+
+ handle = container_of(w, uv_udp_t, io_watcher);
+ assert(handle->type == UV_UDP);
+
+ if (revents & UV__POLLIN)
+ uv__udp_recvmsg(handle);
+
+ if (revents & UV__POLLOUT) {
+ uv__udp_sendmsg(handle);
+ uv__udp_run_completed(handle);
+ }
+}
+
+
+static void uv__udp_recvmsg(uv_udp_t* handle) {
+ struct sockaddr_storage peer;
+ struct msghdr h;
+ ssize_t nread;
+ uv_buf_t buf;
+ int flags;
+ int count;
+
+ assert(handle->recv_cb != NULL);
+ assert(handle->alloc_cb != NULL);
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ memset(&h, 0, sizeof(h));
+ h.msg_name = &peer;
+
+ do {
+ handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
+ if (buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ return;
+ }
+ assert(buf.base != NULL);
+
+ h.msg_namelen = sizeof(peer);
+ h.msg_iov = (void*) &buf;
+ h.msg_iovlen = 1;
+
+ do {
+ nread = recvmsg(handle->io_watcher.fd, &h, 0);
+ }
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ else
+ handle->recv_cb(handle, -errno, &buf, NULL, 0);
+ }
+ else {
+ const struct sockaddr *addr;
+ if (h.msg_namelen == 0)
+ addr = NULL;
+ else
+ addr = (const struct sockaddr*) &peer;
+
+ flags = 0;
+ if (h.msg_flags & MSG_TRUNC)
+ flags |= UV_UDP_PARTIAL;
+
+ handle->recv_cb(handle, nread, &buf, addr, flags);
+ }
+ }
+ /* recv_cb callback may decide to pause or close the handle */
+ while (nread != -1
+ && count-- > 0
+ && handle->io_watcher.fd != -1
+ && handle->recv_cb != NULL);
+}
+
+
+static void uv__udp_sendmsg(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+ struct msghdr h;
+ ssize_t size;
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ assert(q != NULL);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ assert(req != NULL);
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = &req->addr;
+ h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
+ h.msg_iov = (struct iovec*) req->bufs;
+ h.msg_iovlen = req->nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ break;
+
+ req->status = (size == -1 ? -errno : size);
+
+ /* Sending a datagram is an atomic operation: either all data
+ * is written or nothing is (and EMSGSIZE is raised). That is
+ * why we don't handle partial writes. Just pop the request
+ * off the write queue and onto the completed queue, done.
+ */
+ QUEUE_REMOVE(&req->queue);
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ uv__io_feed(handle->loop, &handle->io_watcher);
+ }
+}
+
+
+/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
+ * refinements for programs that use multicast.
+ *
+ * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
+ * are different from the BSDs: it _shares_ the port rather than steal it
+ * from the current listener. While useful, it's not something we can emulate
+ * on other platforms so we don't enable it.
+ */
+static int uv__set_reuse(int fd) {
+ int yes;
+
+#if defined(SO_REUSEPORT) && !defined(__linux__)
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
+ return -errno;
+#else
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int yes;
+ int fd;
+
+ /* Check for bad flags. */
+ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
+ return -EINVAL;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ fd = handle->io_watcher.fd;
+ if (fd == -1) {
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ handle->io_watcher.fd = fd;
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ err = uv__set_reuse(fd);
+ if (err)
+ goto out;
+ }
+
+ if (flags & UV_UDP_IPV6ONLY) {
+#ifdef IPV6_V6ONLY
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
+ err = -errno;
+ goto out;
+ }
+#else
+ err = -ENOTSUP;
+ goto out;
+#endif
+ }
+
+ if (bind(fd, addr, addrlen)) {
+ err = -errno;
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ return 0;
+
+out:
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ return err;
+}
+
+
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags) {
+ unsigned char taddr[sizeof(struct sockaddr_in6)];
+ socklen_t addrlen;
+
+ if (handle->io_watcher.fd != -1)
+ return 0;
+
+ switch (domain) {
+ case AF_INET:
+ {
+ struct sockaddr_in* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+ addrlen = sizeof *addr;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin6_family = AF_INET6;
+ addr->sin6_addr = in6addr_any;
+ addrlen = sizeof *addr;
+ break;
+ }
+ default:
+ assert(0 && "unsupported address family");
+ abort();
+ }
+
+ return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags);
+}
+
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ int err;
+ int empty_queue;
+
+ assert(nbufs > 0);
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ /* It's legal for send_queue_count > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up send_queue_size/count later.
+ */
+ empty_queue = (handle->send_queue_count == 0);
+
+ uv__req_init(handle->loop, req, UV_UDP_SEND);
+ assert(addrlen <= sizeof(req->addr));
+ memcpy(&req->addr, addr, addrlen);
+ req->send_cb = send_cb;
+ req->handle = handle;
+ req->nbufs = nbufs;
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL) {
+ uv__req_unregister(handle->loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count++;
+ QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
+ uv__handle_start(handle);
+
+ if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
+ uv__udp_sendmsg(handle);
+ } else {
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
+ }
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ int err;
+ struct msghdr h;
+ ssize_t size;
+
+ assert(nbufs > 0);
+
+ /* already sending a message */
+ if (handle->send_queue_count != 0)
+ return -EAGAIN;
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = (struct sockaddr*) addr;
+ h.msg_namelen = addrlen;
+ h.msg_iov = (struct iovec*) bufs;
+ h.msg_iovlen = nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return -EAGAIN;
+ else
+ return -errno;
+ }
+
+ return size;
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct ip_mreq mreq;
+ int optname;
+ int err;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+static int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return -EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+ int err;
+ int fd;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ if (domain != AF_UNSPEC) {
+ err = uv__socket(domain, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ } else {
+ fd = -1;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv__io_init(&handle->io_watcher, uv__udp_io, fd);
+ QUEUE_INIT(&handle->write_queue);
+ QUEUE_INIT(&handle->write_completed_queue);
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ /* Check for already active socket. */
+ if (handle->io_watcher.fd != -1)
+ return -EBUSY;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ err = uv__set_reuse(sock);
+ if (err)
+ return err;
+
+ handle->io_watcher.fd = sock;
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ } else {
+ return -EINVAL;
+ }
+}
+
+static int uv__setsockopt(uv_udp_t* handle,
+ int option4,
+ int option6,
+ const void* val,
+ size_t size) {
+ int r;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ option6,
+ val,
+ size);
+ else
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ option4,
+ val,
+ size);
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+static int uv__setsockopt_maybe_char(uv_udp_t* handle,
+ int option4,
+ int option6,
+ int val) {
+#if defined(__sun) || defined(_AIX)
+ char arg = val;
+#elif defined(__OpenBSD__)
+ unsigned char arg = val;
+#else
+ int arg = val;
+#endif
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
+ if (setsockopt(handle->io_watcher.fd,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ &on,
+ sizeof(on))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
+ if (ttl < 1 || ttl > 255)
+ return -EINVAL;
+
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
+ * so hardcode the size of these options on this platform,
+ * and use the general uv__setsockopt_maybe_char call on other platforms.
+ */
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__)
+ return uv__setsockopt(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
+ * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
+ * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ &on,
+ sizeof(on));
+#endif /* defined(__sun) || defined(_AIX) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ on);
+}
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return -EINVAL;
+ }
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (void*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == -1) {
+ return -errno;
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == -1) {
+ return -errno;
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->io_watcher.fd == -1)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(handle->io_watcher.fd, name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ int err;
+
+ if (alloc_cb == NULL || recv_cb == NULL)
+ return -EINVAL;
+
+ if (uv__io_active(&handle->io_watcher, UV__POLLIN))
+ return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
+
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
+ if (err)
+ return err;
+
+ handle->alloc_cb = alloc_cb;
+ handle->recv_cb = recv_cb;
+
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN);
+
+ if (!uv__io_active(&handle->io_watcher, UV__POLLOUT))
+ uv__handle_stop(handle);
+
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/uv-common.c b/3rdparty/libuv/src/uv-common.c
new file mode 100644
index 00000000000..40ed28fec5a
--- /dev/null
+++ b/3rdparty/libuv/src/uv-common.c
@@ -0,0 +1,627 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+#if defined(_WIN32)
+# include <malloc.h> /* malloc */
+#else
+# include <net/if.h> /* if_nametoindex */
+#endif
+
+
+typedef struct {
+ uv_malloc_func local_malloc;
+ uv_realloc_func local_realloc;
+ uv_calloc_func local_calloc;
+ uv_free_func local_free;
+} uv__allocator_t;
+
+static uv__allocator_t uv__allocator = {
+ malloc,
+ realloc,
+ calloc,
+ free,
+};
+
+char* uv__strdup(const char* s) {
+ size_t len = strlen(s) + 1;
+ char* m = uv__malloc(len);
+ if (m == NULL)
+ return NULL;
+ return memcpy(m, s, len);
+}
+
+char* uv__strndup(const char* s, size_t n) {
+ char* m;
+ size_t len = strlen(s);
+ if (n < len)
+ len = n;
+ m = uv__malloc(len + 1);
+ if (m == NULL)
+ return NULL;
+ m[len] = '\0';
+ return memcpy(m, s, len);
+}
+
+void* uv__malloc(size_t size) {
+ return uv__allocator.local_malloc(size);
+}
+
+void uv__free(void* ptr) {
+ uv__allocator.local_free(ptr);
+}
+
+void* uv__calloc(size_t count, size_t size) {
+ return uv__allocator.local_calloc(count, size);
+}
+
+void* uv__realloc(void* ptr, size_t size) {
+ return uv__allocator.local_realloc(ptr, size);
+}
+
+int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func) {
+ if (malloc_func == NULL || realloc_func == NULL ||
+ calloc_func == NULL || free_func == NULL) {
+ return UV_EINVAL;
+ }
+
+ uv__allocator.local_malloc = malloc_func;
+ uv__allocator.local_realloc = realloc_func;
+ uv__allocator.local_calloc = calloc_func;
+ uv__allocator.local_free = free_func;
+
+ return 0;
+}
+
+#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
+
+size_t uv_handle_size(uv_handle_type type) {
+ switch (type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+size_t uv_req_size(uv_req_type type) {
+ switch(type) {
+ UV_REQ_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+#undef XX
+
+
+size_t uv_loop_size(void) {
+ return sizeof(uv_loop_t);
+}
+
+
+uv_buf_t uv_buf_init(char* base, unsigned int len) {
+ uv_buf_t buf;
+ buf.base = base;
+ buf.len = len;
+ return buf;
+}
+
+
+static const char* uv__unknown_err_code(int err) {
+ char buf[32];
+ char* copy;
+
+ snprintf(buf, sizeof(buf), "Unknown system error %d", err);
+ copy = uv__strdup(buf);
+
+ return copy != NULL ? copy : "Unknown system error";
+}
+
+
+#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
+const char* uv_err_name(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_ERR_NAME_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_ERR_NAME_GEN
+
+
+#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
+const char* uv_strerror(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_STRERROR_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_STRERROR_GEN
+
+
+int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
+}
+
+
+int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
+ char address_part[40];
+ size_t address_part_size;
+ const char* zone_index;
+
+ memset(addr, 0, sizeof(*addr));
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons(port);
+
+ zone_index = strchr(ip, '%');
+ if (zone_index != NULL) {
+ address_part_size = zone_index - ip;
+ if (address_part_size >= sizeof(address_part))
+ address_part_size = sizeof(address_part) - 1;
+
+ memcpy(address_part, ip, address_part_size);
+ address_part[address_part_size] = '\0';
+ ip = address_part;
+
+ zone_index++; /* skip '%' */
+ /* NOTE: unknown interface (id=0) is silently ignored */
+#ifdef _WIN32
+ addr->sin6_scope_id = atoi(zone_index);
+#else
+ addr->sin6_scope_id = if_nametoindex(zone_index);
+#endif
+ }
+
+ return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
+}
+
+
+int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
+}
+
+
+int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
+}
+
+
+int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_connect(req, handle, addr, addrlen, cb);
+}
+
+
+int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+}
+
+
+int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_start(handle, alloc_cb, recv_cb);
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_stop(handle);
+}
+
+
+void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
+ QUEUE queue;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ QUEUE_MOVE(&loop->handle_queue, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->handle_queue, q);
+
+ if (h->flags & UV__HANDLE_INTERNAL) continue;
+ walk_cb(h, arg);
+ }
+}
+
+
+static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
+ const char* type;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ if (loop == NULL)
+ loop = uv_default_loop();
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (only_active && !uv__is_active(h))
+ continue;
+
+ switch (h->type) {
+#define X(uc, lc) case UV_##uc: type = #lc; break;
+ UV_HANDLE_TYPE_MAP(X)
+#undef X
+ default: type = "<unknown>";
+ }
+
+ fprintf(stream,
+ "[%c%c%c] %-8s %p\n",
+ "R-"[!(h->flags & UV__HANDLE_REF)],
+ "A-"[!(h->flags & UV__HANDLE_ACTIVE)],
+ "I-"[!(h->flags & UV__HANDLE_INTERNAL)],
+ type,
+ (void*)h);
+ }
+}
+
+
+void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 0, stream);
+}
+
+
+void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 1, stream);
+}
+
+
+void uv_ref(uv_handle_t* handle) {
+ uv__handle_ref(handle);
+}
+
+
+void uv_unref(uv_handle_t* handle) {
+ uv__handle_unref(handle);
+}
+
+
+int uv_has_ref(const uv_handle_t* handle) {
+ return uv__has_ref(handle);
+}
+
+
+void uv_stop(uv_loop_t* loop) {
+ loop->stop_flag = 1;
+}
+
+
+uint64_t uv_now(const uv_loop_t* loop) {
+ return loop->time;
+}
+
+
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
+ unsigned int i;
+ size_t bytes;
+
+ bytes = 0;
+ for (i = 0; i < nbufs; i++)
+ bytes += (size_t) bufs[i].len;
+
+ return bytes;
+}
+
+int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
+ return uv__socket_sockopt(handle, SO_RCVBUF, value);
+}
+
+int uv_send_buffer_size(uv_handle_t* handle, int *value) {
+ return uv__socket_sockopt(handle, SO_SNDBUF, value);
+}
+
+int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ required_len = strlen(handle->path);
+ if (required_len > *size) {
+ *size = required_len;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, handle->path, required_len);
+ *size = required_len;
+
+ return 0;
+}
+
+/* The windows implementation does not have the same structure layout as
+ * the unix implementation (nbufs is not directly inside req but is
+ * contained in a nested union/struct) so this function locates it.
+*/
+static unsigned int* uv__get_nbufs(uv_fs_t* req) {
+#ifdef _WIN32
+ return &req->fs.info.nbufs;
+#else
+ return &req->nbufs;
+#endif
+}
+
+void uv__fs_scandir_cleanup(uv_fs_t* req) {
+ uv__dirent_t** dents;
+
+ unsigned int* nbufs = uv__get_nbufs(req);
+
+ dents = req->ptr;
+ if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
+ (*nbufs)--;
+ for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
+ uv__free(dents[*nbufs]);
+}
+
+
+int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
+ uv__dirent_t** dents;
+ uv__dirent_t* dent;
+
+ unsigned int* nbufs = uv__get_nbufs(req);
+
+ dents = req->ptr;
+
+ /* Free previous entity */
+ if (*nbufs > 0)
+ uv__free(dents[*nbufs - 1]);
+
+ /* End was already reached */
+ if (*nbufs == (unsigned int) req->result) {
+ uv__free(dents);
+ req->ptr = NULL;
+ return UV_EOF;
+ }
+
+ dent = dents[(*nbufs)++];
+
+ ent->name = dent->d_name;
+#ifdef HAVE_DIRENT_TYPES
+ switch (dent->d_type) {
+ case UV__DT_DIR:
+ ent->type = UV_DIRENT_DIR;
+ break;
+ case UV__DT_FILE:
+ ent->type = UV_DIRENT_FILE;
+ break;
+ case UV__DT_LINK:
+ ent->type = UV_DIRENT_LINK;
+ break;
+ case UV__DT_FIFO:
+ ent->type = UV_DIRENT_FIFO;
+ break;
+ case UV__DT_SOCKET:
+ ent->type = UV_DIRENT_SOCKET;
+ break;
+ case UV__DT_CHAR:
+ ent->type = UV_DIRENT_CHAR;
+ break;
+ case UV__DT_BLOCK:
+ ent->type = UV_DIRENT_BLOCK;
+ break;
+ default:
+ ent->type = UV_DIRENT_UNKNOWN;
+ }
+#else
+ ent->type = UV_DIRENT_UNKNOWN;
+#endif
+
+ return 0;
+}
+
+
+int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
+ va_list ap;
+ int err;
+
+ va_start(ap, option);
+ /* Any platform-agnostic options should be handled here. */
+ err = uv__loop_configure(loop, option, ap);
+ va_end(ap);
+
+ return err;
+}
+
+
+static uv_loop_t default_loop_struct;
+static uv_loop_t* default_loop_ptr;
+
+
+uv_loop_t* uv_default_loop(void) {
+ if (default_loop_ptr != NULL)
+ return default_loop_ptr;
+
+ if (uv_loop_init(&default_loop_struct))
+ return NULL;
+
+ default_loop_ptr = &default_loop_struct;
+ return default_loop_ptr;
+}
+
+
+uv_loop_t* uv_loop_new(void) {
+ uv_loop_t* loop;
+
+ loop = uv__malloc(sizeof(*loop));
+ if (loop == NULL)
+ return NULL;
+
+ if (uv_loop_init(loop)) {
+ uv__free(loop);
+ return NULL;
+ }
+
+ return loop;
+}
+
+
+int uv_loop_close(uv_loop_t* loop) {
+ QUEUE* q;
+ uv_handle_t* h;
+
+ if (!QUEUE_EMPTY(&(loop)->active_reqs))
+ return UV_EBUSY;
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+ if (!(h->flags & UV__HANDLE_INTERNAL))
+ return UV_EBUSY;
+ }
+
+ uv__loop_close(loop);
+
+#ifndef NDEBUG
+ memset(loop, -1, sizeof(*loop));
+#endif
+ if (loop == default_loop_ptr)
+ default_loop_ptr = NULL;
+
+ return 0;
+}
+
+
+void uv_loop_delete(uv_loop_t* loop) {
+ uv_loop_t* default_loop;
+ int err;
+
+ default_loop = default_loop_ptr;
+
+ err = uv_loop_close(loop);
+ (void) err; /* Squelch compiler warnings. */
+ assert(err == 0);
+ if (loop != default_loop)
+ uv__free(loop);
+}
diff --git a/3rdparty/libuv/src/uv-common.h b/3rdparty/libuv/src/uv-common.h
new file mode 100644
index 00000000000..27902fdf864
--- /dev/null
+++ b/3rdparty/libuv/src/uv-common.h
@@ -0,0 +1,227 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_COMMON_H_
+#define UV_COMMON_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "uv.h"
+#include "tree.h"
+#include "queue.h"
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#define STATIC_ASSERT(expr) \
+ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
+
+#ifndef _WIN32
+enum {
+ UV__HANDLE_INTERNAL = 0x8000,
+ UV__HANDLE_ACTIVE = 0x4000,
+ UV__HANDLE_REF = 0x2000,
+ UV__HANDLE_CLOSING = 0 /* no-op on unix */
+};
+#else
+# define UV__HANDLE_INTERNAL 0x80
+# define UV__HANDLE_ACTIVE 0x40
+# define UV__HANDLE_REF 0x20
+# define UV__HANDLE_CLOSING 0x01
+#endif
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
+
+void uv__loop_close(uv_loop_t* loop);
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb);
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb);
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen);
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
+ uv_udp_recv_cb recv_cb);
+
+int uv__udp_recv_stop(uv_udp_t* handle);
+
+void uv__fs_poll_close(uv_fs_poll_t* handle);
+
+int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work *w,
+ void (*work)(struct uv__work *w),
+ void (*done)(struct uv__work *w, int status));
+
+void uv__work_done(uv_async_t* handle);
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
+
+void uv__fs_scandir_cleanup(uv_fs_t* req);
+
+#define uv__has_active_reqs(loop) \
+ (QUEUE_EMPTY(&(loop)->active_reqs) == 0)
+
+#define uv__req_register(loop, req) \
+ do { \
+ QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__req_unregister(loop, req) \
+ do { \
+ assert(uv__has_active_reqs(loop)); \
+ QUEUE_REMOVE(&(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__has_active_handles(loop) \
+ ((loop)->active_handles > 0)
+
+#define uv__active_handle_add(h) \
+ do { \
+ (h)->loop->active_handles++; \
+ } \
+ while (0)
+
+#define uv__active_handle_rm(h) \
+ do { \
+ (h)->loop->active_handles--; \
+ } \
+ while (0)
+
+#define uv__is_active(h) \
+ (((h)->flags & UV__HANDLE_ACTIVE) != 0)
+
+#define uv__is_closing(h) \
+ (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
+
+#define uv__handle_start(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
+ (h)->flags |= UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_stop(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__handle_ref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) != 0) break; \
+ (h)->flags |= UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_unref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__has_ref(h) \
+ (((h)->flags & UV__HANDLE_REF) != 0)
+
+#if defined(_WIN32)
+# define uv__handle_platform_init(h) ((h)->u.fd = -1)
+#else
+# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
+#endif
+
+#define uv__handle_init(loop_, h, type_) \
+ do { \
+ (h)->loop = (loop_); \
+ (h)->type = (type_); \
+ (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
+ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
+ uv__handle_platform_init(h); \
+ } \
+ while (0)
+
+
+/* Allocator prototypes */
+void *uv__calloc(size_t count, size_t size);
+char *uv__strdup(const char* s);
+char *uv__strndup(const char* s, size_t n);
+void* uv__malloc(size_t size);
+void uv__free(void* ptr);
+void* uv__realloc(void* ptr, size_t size);
+
+#endif /* UV_COMMON_H_ */
diff --git a/3rdparty/libuv/src/version.c b/3rdparty/libuv/src/version.c
new file mode 100644
index 00000000000..686dedd98d6
--- /dev/null
+++ b/3rdparty/libuv/src/version.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+
+#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
+#define UV_STRINGIFY_HELPER(v) #v
+
+#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
+ UV_STRINGIFY(UV_VERSION_MINOR) "." \
+ UV_STRINGIFY(UV_VERSION_PATCH)
+
+#if UV_VERSION_IS_RELEASE
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE
+#else
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
+#endif
+
+
+unsigned int uv_version(void) {
+ return UV_VERSION_HEX;
+}
+
+
+const char* uv_version_string(void) {
+ return UV_VERSION_STRING;
+}
diff --git a/3rdparty/libuv/src/win/async.c b/3rdparty/libuv/src/win/async.c
new file mode 100644
index 00000000000..ad240ab8972
--- /dev/null
+++ b/3rdparty/libuv/src/win/async.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "atomicops-inl.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ !handle->async_sent) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
+ handle->async_sent = 0;
+ handle->async_cb = async_cb;
+
+ req = &handle->async_req;
+ uv_req_init(loop, req);
+ req->type = UV_WAKEUP;
+ req->data = handle;
+
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+ if (!((uv_async_t*)handle)->async_sent) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ uv__handle_closing(handle);
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->type != UV_ASYNC) {
+ /* Can't set errno because that's not thread-safe. */
+ return -1;
+ }
+
+ /* The user should make sure never to call uv_async_send to a closing */
+ /* or closed handle. */
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+
+ if (!uv__atomic_exchange_set(&handle->async_sent)) {
+ POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
+ }
+
+ return 0;
+}
+
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_ASYNC);
+ assert(req->type == UV_WAKEUP);
+
+ handle->async_sent = 0;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ } else if (handle->async_cb != NULL) {
+ handle->async_cb(handle);
+ }
+}
diff --git a/3rdparty/libuv/src/win/atomicops-inl.h b/3rdparty/libuv/src/win/atomicops-inl.h
new file mode 100644
index 00000000000..61e006026c1
--- /dev/null
+++ b/3rdparty/libuv/src/win/atomicops-inl.h
@@ -0,0 +1,56 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_ATOMICOPS_INL_H_
+#define UV_WIN_ATOMICOPS_INL_H_
+
+#include "uv.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
+ return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv__atomic_exchange_set(char volatile* target) {
+ const char one = 1;
+ char old_value;
+ __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+ : "=r"(old_value), "=m"(*target)
+ : "0"(one), "m"(*target)
+ : "memory");
+ return old_value;
+}
+
+#endif
+
+#endif /* UV_WIN_ATOMICOPS_INL_H_ */
diff --git a/3rdparty/libuv/src/win/core.c b/3rdparty/libuv/src/win/core.c
new file mode 100644
index 00000000000..de0483e1023
--- /dev/null
+++ b/3rdparty/libuv/src/win/core.c
@@ -0,0 +1,457 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+#include <crtdbg.h>
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static uv_loop_t default_loop_struct;
+static uv_loop_t* default_loop_ptr;
+
+/* uv_once initialization guards */
+static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
+
+
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+/* Our crt debug report handler allows us to temporarily disable asserts
+ * just for the current thread.
+ */
+
+UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
+
+static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
+ if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
+ return FALSE;
+
+ if (ret_val) {
+ /* Set ret_val to 0 to continue with normal execution.
+ * Set ret_val to 1 to trigger a breakpoint.
+ */
+
+ if(IsDebuggerPresent())
+ *ret_val = 1;
+ else
+ *ret_val = 0;
+ }
+
+ /* Don't call _CrtDbgReport. */
+ return TRUE;
+}
+#else
+UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
+#endif
+
+
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
+ const wchar_t* function, const wchar_t * file, unsigned int line,
+ uintptr_t reserved) {
+ /* No-op. */
+}
+#endif
+
+
+static void uv_init(void) {
+ /* Tell Windows that we will handle critical errors. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+
+ /* Tell the CRT to not exit the application when an invalid parameter is
+ * passed. The main issue is that invalid FDs will trigger this behavior.
+ */
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+ _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
+#endif
+
+ /* We also need to setup our debug report handler because some CRT
+ * functions (eg _get_osfhandle) raise an assert when called with invalid
+ * FDs even though they return the proper error code in the release build.
+ */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+ _CrtSetReportHook(uv__crt_dbg_report_handler);
+#endif
+
+ /* Fetch winapi function pointers. This must be done first because other
+ * initialization code might need these function pointers to be loaded.
+ */
+ uv_winapi_init();
+
+ /* Initialize winsock */
+ uv_winsock_init();
+
+ /* Initialize FS */
+ uv_fs_init();
+
+ /* Initialize signal stuff */
+ uv_signals_init();
+
+ /* Initialize console */
+ uv_console_init();
+
+ /* Initialize utilities */
+ uv__util_init();
+}
+
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ /* Initialize libuv itself first */
+ uv__once_init();
+
+ /* Create an I/O completion port */
+ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+ if (loop->iocp == NULL)
+ return uv_translate_sys_error(GetLastError());
+
+ /* To prevent uninitialized memory access, loop->time must be initialized
+ * to zero before calling uv_update_time for the first time.
+ */
+ loop->time = 0;
+ uv_update_time(loop);
+
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->handle_queue);
+ QUEUE_INIT(&loop->active_reqs);
+ loop->active_handles = 0;
+
+ loop->pending_reqs_tail = NULL;
+
+ loop->endgame_handles = NULL;
+
+ RB_INIT(&loop->timers);
+
+ loop->check_handles = NULL;
+ loop->prepare_handles = NULL;
+ loop->idle_handles = NULL;
+
+ loop->next_prepare_handle = NULL;
+ loop->next_check_handle = NULL;
+ loop->next_idle_handle = NULL;
+
+ memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
+
+ loop->active_tcp_streams = 0;
+ loop->active_udp_streams = 0;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ CloseHandle(loop->iocp);
+ loop->iocp = INVALID_HANDLE_VALUE;
+
+ return err;
+}
+
+
+void uv__once_init(void) {
+ uv_once(&uv_init_guard_, uv_init);
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ size_t i;
+
+ /* close the async handle without needing an extra loop iteration */
+ assert(!loop->wq_async.async_sent);
+ loop->wq_async.close_cb = NULL;
+ uv__handle_closing(&loop->wq_async);
+ uv__handle_close(&loop->wq_async);
+
+ for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+ SOCKET sock = loop->poll_peer_sockets[i];
+ if (sock != 0 && sock != INVALID_SOCKET)
+ closesocket(sock);
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ CloseHandle(loop->iocp);
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ return UV_ENOSYS;
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return -1;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (loop->pending_reqs_tail)
+ return 0;
+
+ if (loop->endgame_handles)
+ return 0;
+
+ if (loop->idle_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+ DWORD bytes;
+ ULONG_PTR key;
+ OVERLAPPED* overlapped;
+ uv_req_t* req;
+
+ GetQueuedCompletionStatus(loop->iocp,
+ &bytes,
+ &key,
+ &overlapped,
+ timeout);
+
+ if (overlapped) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlapped);
+ uv_insert_pending_req(loop, req);
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout is reflected in the loop time.
+ */
+ uv__time_forward(loop, timeout);
+ }
+}
+
+
+static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
+ BOOL success;
+ uv_req_t* req;
+ OVERLAPPED_ENTRY overlappeds[128];
+ ULONG count;
+ ULONG i;
+
+ success = pGetQueuedCompletionStatusEx(loop->iocp,
+ overlappeds,
+ ARRAY_SIZE(overlappeds),
+ &count,
+ timeout,
+ FALSE);
+
+ if (success) {
+ for (i = 0; i < count; i++) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
+ uv_insert_pending_req(loop, req);
+ }
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout is reflected in the loop time.
+ */
+ uv__time_forward(loop, timeout);
+ }
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return loop->active_handles > 0 ||
+ !QUEUE_EMPTY(&loop->active_reqs) ||
+ loop->endgame_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t *loop, uv_run_mode mode) {
+ DWORD timeout;
+ int r;
+ int ran_pending;
+ void (*poll)(uv_loop_t* loop, DWORD timeout);
+
+ if (pGetQueuedCompletionStatusEx)
+ poll = &uv_poll_ex;
+ else
+ poll = &uv_poll;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv_update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv_update_time(loop);
+ uv_process_timers(loop);
+
+ ran_pending = uv_process_reqs(loop);
+ uv_idle_invoke(loop);
+ uv_prepare_invoke(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ (*poll)(loop, timeout);
+
+ uv_check_invoke(loop);
+ uv_process_endgames(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv_process_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets the compiler compile it to a conditional store.
+ * Avoids dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ uv_os_fd_t fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
+ break;
+
+ case UV_NAMED_PIPE:
+ fd_out = ((uv_pipe_t*) handle)->handle;
+ break;
+
+ case UV_TTY:
+ fd_out = ((uv_tty_t*) handle)->handle;
+ break;
+
+ case UV_UDP:
+ fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
+ break;
+
+ case UV_POLL:
+ fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
+ break;
+
+ default:
+ return UV_EINVAL;
+ }
+
+ if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int len;
+ SOCKET socket;
+
+ if (handle == NULL || value == NULL)
+ return UV_EINVAL;
+
+ if (handle->type == UV_TCP)
+ socket = ((uv_tcp_t*) handle)->socket;
+ else if (handle->type == UV_UDP)
+ socket = ((uv_udp_t*) handle)->socket;
+ else
+ return UV_ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
+ else
+ r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
+
+ if (r == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/dl.c b/3rdparty/libuv/src/win/dl.c
new file mode 100644
index 00000000000..e5f3407f8eb
--- /dev/null
+++ b/3rdparty/libuv/src/win/dl.c
@@ -0,0 +1,113 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+static int uv__dlerror(uv_lib_t* lib, int errorno);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ WCHAR filename_w[32768];
+
+ lib->handle = NULL;
+ lib->errmsg = NULL;
+
+ if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (lib->handle == NULL) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ return 0;
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ FreeLibrary(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ *ptr = (void*) GetProcAddress(lib->handle, name);
+ return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
+ DWORD_PTR args[1] = { (DWORD_PTR) errorno };
+ LPSTR fallback_error = "error: %1!d!";
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ fallback_error, 0, 0,
+ (LPSTR) &lib->errmsg,
+ 0, (va_list*) args);
+}
+
+
+
+static int uv__dlerror(uv_lib_t* lib, int errorno) {
+ DWORD res;
+
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (errorno) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (!res) {
+ uv__format_fallback_error(lib, errorno);
+ }
+ }
+
+ return errorno ? -1 : 0;
+}
diff --git a/3rdparty/libuv/src/win/error.c b/3rdparty/libuv/src/win/error.c
new file mode 100644
index 00000000000..c512f35af97
--- /dev/null
+++ b/3rdparty/libuv/src/win/error.c
@@ -0,0 +1,170 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/*
+ * Display an error message and abort the event loop.
+ */
+void uv_fatal_error(const int errorno, const char* syscall) {
+ char* buf = NULL;
+ const char* errmsg;
+
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
+
+ if (buf) {
+ errmsg = buf;
+ } else {
+ errmsg = "Unknown error";
+ }
+
+ /* FormatMessage messages include a newline character already, */
+ /* so don't add another. */
+ if (syscall) {
+ fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
+ } else {
+ fprintf(stderr, "(%d) %s", errorno, errmsg);
+ }
+
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ *((char*)NULL) = 0xff; /* Force debug break */
+ abort();
+}
+
+
+int uv_translate_sys_error(int sys_errno) {
+ if (sys_errno <= 0) {
+ return sys_errno; /* If < 0 then it's already a libuv error. */
+ }
+
+ switch (sys_errno) {
+ case ERROR_NOACCESS: return UV_EACCES;
+ case WSAEACCES: return UV_EACCES;
+ case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
+ case WSAEADDRINUSE: return UV_EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
+ case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
+ case WSAEWOULDBLOCK: return UV_EAGAIN;
+ case WSAEALREADY: return UV_EALREADY;
+ case ERROR_INVALID_FLAGS: return UV_EBADF;
+ case ERROR_INVALID_HANDLE: return UV_EBADF;
+ case ERROR_LOCK_VIOLATION: return UV_EBUSY;
+ case ERROR_PIPE_BUSY: return UV_EBUSY;
+ case ERROR_SHARING_VIOLATION: return UV_EBUSY;
+ case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
+ case WSAEINTR: return UV_ECANCELED;
+ case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
+ case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
+ case WSAECONNABORTED: return UV_ECONNABORTED;
+ case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
+ case WSAECONNREFUSED: return UV_ECONNREFUSED;
+ case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
+ case WSAECONNRESET: return UV_ECONNRESET;
+ case ERROR_ALREADY_EXISTS: return UV_EEXIST;
+ case ERROR_FILE_EXISTS: return UV_EEXIST;
+ case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
+ case WSAEFAULT: return UV_EFAULT;
+ case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
+ case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
+ case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
+ case ERROR_INVALID_DATA: return UV_EINVAL;
+ case ERROR_INVALID_PARAMETER: return UV_EINVAL;
+ case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
+ case WSAEINVAL: return UV_EINVAL;
+ case WSAEPFNOSUPPORT: return UV_EINVAL;
+ case WSAESOCKTNOSUPPORT: return UV_EINVAL;
+ case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
+ case ERROR_BUS_RESET: return UV_EIO;
+ case ERROR_CRC: return UV_EIO;
+ case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
+ case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
+ case ERROR_DISK_CORRUPT: return UV_EIO;
+ case ERROR_EOM_OVERFLOW: return UV_EIO;
+ case ERROR_FILEMARK_DETECTED: return UV_EIO;
+ case ERROR_GEN_FAILURE: return UV_EIO;
+ case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
+ case ERROR_IO_DEVICE: return UV_EIO;
+ case ERROR_NO_DATA_DETECTED: return UV_EIO;
+ case ERROR_NO_SIGNAL_SENT: return UV_EIO;
+ case ERROR_OPEN_FAILED: return UV_EIO;
+ case ERROR_SETMARK_DETECTED: return UV_EIO;
+ case ERROR_SIGNAL_REFUSED: return UV_EIO;
+ case WSAEISCONN: return UV_EISCONN;
+ case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
+ case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
+ case WSAEMFILE: return UV_EMFILE;
+ case WSAEMSGSIZE: return UV_EMSGSIZE;
+ case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
+ case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
+ case WSAENETUNREACH: return UV_ENETUNREACH;
+ case WSAENOBUFS: return UV_ENOBUFS;
+ case ERROR_BAD_PATHNAME: return UV_ENOENT;
+ case ERROR_DIRECTORY: return UV_ENOENT;
+ case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
+ case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_INVALID_DRIVE: return UV_ENOENT;
+ case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
+ case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
+ case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
+ case WSAHOST_NOT_FOUND: return UV_ENOENT;
+ case WSANO_DATA: return UV_ENOENT;
+ case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
+ case ERROR_OUTOFMEMORY: return UV_ENOMEM;
+ case ERROR_CANNOT_MAKE: return UV_ENOSPC;
+ case ERROR_DISK_FULL: return UV_ENOSPC;
+ case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
+ case ERROR_END_OF_MEDIA: return UV_ENOSPC;
+ case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
+ case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
+ case WSAENOTCONN: return UV_ENOTCONN;
+ case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
+ case WSAENOTSOCK: return UV_ENOTSOCK;
+ case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
+ case ERROR_BROKEN_PIPE: return UV_EOF;
+ case ERROR_ACCESS_DENIED: return UV_EPERM;
+ case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
+ case ERROR_BAD_PIPE: return UV_EPIPE;
+ case ERROR_NO_DATA: return UV_EPIPE;
+ case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
+ case WSAESHUTDOWN: return UV_EPIPE;
+ case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
+ case ERROR_WRITE_PROTECT: return UV_EROFS;
+ case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
+ case WSAETIMEDOUT: return UV_ETIMEDOUT;
+ case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
+ case ERROR_INVALID_FUNCTION: return UV_EISDIR;
+ case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
+ default: return UV_UNKNOWN;
+ }
+}
diff --git a/3rdparty/libuv/src/win/fs-event.c b/3rdparty/libuv/src/win/fs-event.c
new file mode 100644
index 00000000000..76ecfebaa24
--- /dev/null
+++ b/3rdparty/libuv/src/win/fs-event.c
@@ -0,0 +1,552 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+const unsigned int uv_directory_watcher_buffer_size = 4096;
+
+
+static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+ uv_fs_event_t* handle) {
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
+ assert(!handle->req_pending);
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(&handle->req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+ }
+
+ handle->req_pending = 1;
+}
+
+static int uv_relative_path(const WCHAR* filename,
+ const WCHAR* dir,
+ WCHAR** relpath) {
+ int dirlen = wcslen(dir);
+ int filelen = wcslen(filename);
+ if (dir[dirlen - 1] == '\\')
+ dirlen--;
+ *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*relpath)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1);
+ (*relpath)[filelen - dirlen - 1] = L'\0';
+ return 0;
+}
+
+static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+ WCHAR** file) {
+ int len = wcslen(filename);
+ int i = len;
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
+
+ if (i == 0) {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
+ uv__free(*dir);
+ *dir = NULL;
+ return -1;
+ }
+ }
+
+ *file = wcsdup(filename);
+ } else {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*dir, filename, i);
+ (*dir)[i] = L'\0';
+ }
+
+ *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
+ if (!*file) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*file, filename + i + 1, len - i - 1);
+ (*file)[len - i - 1] = L'\0';
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ handle->buffer = NULL;
+ handle->req_pending = 0;
+ handle->filew = NULL;
+ handle->short_filew = NULL;
+ handle->dirw = NULL;
+
+ uv_req_init(loop, (uv_req_t*)&handle->req);
+ handle->req.type = UV_FS_EVENT_REQ;
+ handle->req.data = handle;
+
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int name_size, is_path_dir;
+ DWORD attr, last_error;
+ WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
+ WCHAR short_path[MAX_PATH];
+
+ if (uv__is_active(handle))
+ return UV_EINVAL;
+
+ handle->cb = cb;
+ handle->path = uv__strdup(path);
+ if (!handle->path) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ uv__handle_start(handle);
+
+ /* Convert name to UTF16. */
+ name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR);
+ pathw = (WCHAR*)uv__malloc(name_size);
+ if (!pathw) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(path, pathw,
+ name_size / sizeof(WCHAR))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Determine whether path is a file or a directory. */
+ attr = GetFileAttributesW(pathw);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+
+ if (is_path_dir) {
+ /* path is a directory, so that's the directory that we will watch. */
+ handle->dirw = pathw;
+ dir_to_watch = pathw;
+ } else {
+ /*
+ * path is a file. So we split path into dir & file parts, and
+ * watch the dir directory.
+ */
+
+ /* Convert to short path. */
+ if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ dir_to_watch = dir;
+ uv__free(pathw);
+ pathw = NULL;
+ }
+
+ handle->dir_handle = CreateFileW(dir_to_watch,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (dir) {
+ uv__free(dir);
+ dir = NULL;
+ }
+
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (CreateIoCompletionPort(handle->dir_handle,
+ handle->loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (!handle->buffer) {
+ handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
+ }
+ if (!handle->buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->req_pending = 1;
+ return 0;
+
+error:
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ uv__free(pathw);
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ return uv_translate_sys_error(last_error);
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ uv__handle_stop(handle);
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->dirw) {
+ uv__free(handle->dirw);
+ handle->dirw = NULL;
+ }
+
+ return 0;
+}
+
+
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle) {
+ FILE_NOTIFY_INFORMATION* file_info;
+ int err, sizew, size, result;
+ char* filename = NULL;
+ WCHAR* filenamew, *long_filenamew = NULL;
+ DWORD offset = 0;
+
+ assert(req->type == UV_FS_EVENT_REQ);
+ assert(handle->req_pending);
+ handle->req_pending = 0;
+
+ /* Don't report any callbacks if:
+ * - We're closing, just push the handle onto the endgame queue
+ * - We are not active, just ignore the callback
+ */
+ if (!uv__is_active(handle)) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+ return;
+ }
+
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
+
+ if (REQ_SUCCESS(req)) {
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ do {
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
+ assert(!filename);
+ assert(!long_filenamew);
+
+ /*
+ * Fire the event only if we were asked to watch a directory,
+ * or if the filename filter matches.
+ */
+ if (handle->dirw ||
+ _wcsnicmp(handle->filew, file_info->FileName,
+ file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
+ _wcsnicmp(handle->short_filew, file_info->FileName,
+ file_info->FileNameLength / sizeof(WCHAR)) == 0) {
+
+ if (handle->dirw) {
+ /*
+ * We attempt to resolve the long form of the file name explicitly.
+ * We only do this for file names that might still exist on disk.
+ * If this fails, we use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (file_info->Action != FILE_ACTION_REMOVED &&
+ file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
+ /* Construct a full path to the file. */
+ size = wcslen(handle->dirw) +
+ file_info->FileNameLength / sizeof(WCHAR) + 2;
+
+ filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
+ file_info->FileNameLength / sizeof(WCHAR),
+ file_info->FileName);
+
+ filenamew[size - 1] = L'\0';
+
+ /* Convert to long name. */
+ size = GetLongPathNameW(filenamew, NULL, 0);
+
+ if (size) {
+ long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!long_filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = GetLongPathNameW(filenamew, long_filenamew, size);
+ if (size) {
+ long_filenamew[size] = '\0';
+ } else {
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+ }
+
+ uv__free(filenamew);
+
+ if (long_filenamew) {
+ /* Get the file name out of the long path. */
+ result = uv_relative_path(long_filenamew,
+ handle->dirw,
+ &filenamew);
+ uv__free(long_filenamew);
+
+ if (result == 0) {
+ long_filenamew = filenamew;
+ sizew = -1;
+ } else {
+ long_filenamew = NULL;
+ }
+ }
+
+ /*
+ * We could not resolve the long form explicitly.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (!long_filenamew) {
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /*
+ * Removed or renamed events cannot be resolved to the long form.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (!long_filenamew) {
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ }
+ } else {
+ /* We already have the long name of the file, so just use it. */
+ filenamew = handle->filew;
+ sizew = -1;
+ }
+
+ if (filenamew) {
+ /* Convert the filename to utf8. */
+ size = uv_utf16_to_utf8(filenamew,
+ sizew,
+ NULL,
+ 0);
+ if (size) {
+ filename = (char*)uv__malloc(size + 1);
+ if (!filename) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = uv_utf16_to_utf8(filenamew,
+ sizew,
+ filename,
+ size);
+ if (size) {
+ filename[size] = '\0';
+ } else {
+ uv__free(filename);
+ filename = NULL;
+ }
+ }
+ }
+
+ switch (file_info->Action) {
+ case FILE_ACTION_ADDED:
+ case FILE_ACTION_REMOVED:
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ handle->cb(handle, filename, UV_RENAME, 0);
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ handle->cb(handle, filename, UV_CHANGE, 0);
+ break;
+ }
+
+ uv__free(filename);
+ filename = NULL;
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+
+ offset = file_info->NextEntryOffset;
+ } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+ } else {
+ handle->cb(handle, NULL, UV_CHANGE, 0);
+ }
+ } else {
+ err = GET_REQ_ERROR(req);
+ handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
+ }
+
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
+ } else {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+
+ uv__handle_closing(handle);
+
+ if (!handle->req_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+}
+
+
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
diff --git a/3rdparty/libuv/src/win/fs.c b/3rdparty/libuv/src/win/fs.c
new file mode 100644
index 00000000000..a32b0127f7e
--- /dev/null
+++ b/3rdparty/libuv/src/win/fs.c
@@ -0,0 +1,2468 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+#include "handle-inl.h"
+
+#include <wincrypt.h>
+
+
+#define UV_FS_FREE_PATHS 0x0002
+#define UV_FS_FREE_PTR 0x0008
+#define UV_FS_CLEANEDUP 0x0010
+
+
+#define QUEUE_FS_TP_JOB(loop, req) \
+ do { \
+ uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
+ } while (0)
+
+#define SET_REQ_RESULT(req, result_value) \
+ do { \
+ req->result = (result_value); \
+ if (req->result == -1) { \
+ req->sys_errno_ = _doserrno; \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } \
+ } while (0)
+
+#define SET_REQ_WIN32_ERROR(req, sys_errno) \
+ do { \
+ req->sys_errno_ = (sys_errno); \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } while (0)
+
+#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
+ do { \
+ req->result = (uv_errno); \
+ req->sys_errno_ = (sys_errno); \
+ } while (0)
+
+#define VERIFY_FD(fd, req) \
+ if (fd == -1) { \
+ req->result = UV_EBADF; \
+ req->sys_errno_ = ERROR_INVALID_HANDLE; \
+ return; \
+ }
+
+#define FILETIME_TO_UINT(filetime) \
+ (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+
+#define FILETIME_TO_TIME_T(filetime) \
+ (FILETIME_TO_UINT(filetime) / 10000000ULL)
+
+#define FILETIME_TO_TIME_NS(filetime, secs) \
+ ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
+
+#define FILETIME_TO_TIMESPEC(ts, filetime) \
+ do { \
+ (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
+ (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
+ } while(0)
+
+#define TIME_T_TO_FILETIME(time, filetime_ptr) \
+ do { \
+ uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
+ 116444736000000000ULL; \
+ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ } while(0)
+
+#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
+#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
+ ((c) >= L'A' && (c) <= L'Z'))
+
+const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
+const WCHAR JUNCTION_PREFIX_LEN = 4;
+
+const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
+const WCHAR LONG_PATH_PREFIX_LEN = 4;
+
+const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
+const WCHAR UNC_PATH_PREFIX_LEN = 8;
+
+
+void uv_fs_init() {
+ _fmode = _O_BINARY;
+}
+
+
+INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
+ const char* new_path, const int copy_path) {
+ char* buf;
+ char* pos;
+ ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
+
+ /* new_path can only be set if path is also set. */
+ assert(new_path == NULL || path != NULL);
+
+ if (path != NULL) {
+ pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ NULL,
+ 0);
+ if (pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += pathw_len * sizeof(WCHAR);
+ }
+
+ if (path != NULL && copy_path) {
+ path_len = 1 + strlen(path);
+ buf_sz += path_len;
+ }
+
+ if (new_path != NULL) {
+ new_pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ NULL,
+ 0);
+ if (new_pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += new_pathw_len * sizeof(WCHAR);
+ }
+
+
+ if (buf_sz == 0) {
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->path = NULL;
+ return 0;
+ }
+
+ buf = (char*) uv__malloc(buf_sz);
+ if (buf == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pos = buf;
+
+ if (path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ (WCHAR*) pos,
+ pathw_len);
+ assert(r == (DWORD) pathw_len);
+ req->file.pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->file.pathw = NULL;
+ }
+
+ if (new_path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ (WCHAR*) pos,
+ new_pathw_len);
+ assert(r == (DWORD) new_pathw_len);
+ req->fs.info.new_pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->fs.info.new_pathw = NULL;
+ }
+
+ if (!copy_path) {
+ req->path = path;
+ } else if (path) {
+ memcpy(pos, path, path_len);
+ assert(path_len == buf_sz - (pos - buf));
+ req->path = pos;
+ } else {
+ req->path = NULL;
+ }
+
+ req->flags |= UV_FS_FREE_PATHS;
+
+ return 0;
+}
+
+
+
+INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
+ uv_fs_type fs_type, const uv_fs_cb cb) {
+ uv_req_init(loop, (uv_req_t*) req);
+
+ req->type = UV_FS;
+ req->loop = loop;
+ req->flags = 0;
+ req->fs_type = fs_type;
+ req->result = 0;
+ req->ptr = NULL;
+ req->path = NULL;
+ req->cb = cb;
+}
+
+
+static int fs__wide_to_utf8(WCHAR* w_source_ptr,
+ DWORD w_source_len,
+ char** target_ptr,
+ uint64_t* target_len_ptr) {
+ int r;
+ int target_len;
+ char* target;
+ target_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (target_len == 0) {
+ return -1;
+ }
+
+ if (target_len_ptr != NULL) {
+ *target_len_ptr = target_len;
+ }
+
+ if (target_ptr == NULL) {
+ return 0;
+ }
+
+ target = uv__malloc(target_len + 1);
+ if (target == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ target,
+ target_len,
+ NULL,
+ NULL);
+ assert(r == target_len);
+ target[target_len] = '\0';
+ *target_ptr = target;
+ return 0;
+}
+
+
+INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
+ uint64_t* target_len_ptr) {
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
+ WCHAR* w_target;
+ DWORD w_target_len;
+ DWORD bytes;
+
+ if (!DeviceIoControl(handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ buffer,
+ sizeof buffer,
+ &bytes,
+ NULL)) {
+ return -1;
+ }
+
+ if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ /* Real symlink */
+ w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len =
+ reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Real symlinks can contain pretty much everything, but the only thing */
+ /* we really care about is undoing the implicit conversion to an NT */
+ /* namespaced path that CreateSymbolicLink will perform on absolute */
+ /* paths. If the path is win32-namespaced then the user must have */
+ /* explicitly made it so, and we better just return the unmodified */
+ /* reparse data. */
+ if (w_target_len >= 4 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\') {
+ /* Starts with \??\ */
+ if (w_target_len >= 6 &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\')) {
+ /* \??\<drive>:\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else if (w_target_len >= 8 &&
+ (w_target[4] == L'U' || w_target[4] == L'u') &&
+ (w_target[5] == L'N' || w_target[5] == L'n') &&
+ (w_target[6] == L'C' || w_target[6] == L'c') &&
+ w_target[7] == L'\\') {
+ /* \??\UNC\<server>\<share>\ - make sure the final path looks like */
+ /* \\<server>\<share>\ */
+ w_target += 6;
+ w_target[0] = L'\\';
+ w_target_len -= 6;
+ }
+ }
+
+ } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ /* Junction. */
+ w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Only treat junctions that look like \??\<drive>:\ as symlink. */
+ /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
+ /* but that's confusing for programs since they wouldn't be able to */
+ /* actually understand such a path when returned by uv_readlink(). */
+ /* UNC paths are never valid for junctions so we don't care about them. */
+ if (!(w_target_len >= 6 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\' &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\'))) {
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ /* Remove leading \??\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else {
+ /* Reparse tag does not indicate a symlink. */
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
+}
+
+
+void fs__open(uv_fs_t* req) {
+ DWORD access;
+ DWORD share;
+ DWORD disposition;
+ DWORD attributes = 0;
+ HANDLE file;
+ int fd, current_umask;
+ int flags = req->fs.info.file_flags;
+
+ /* Obtain the active umask. umask() never fails and returns the previous */
+ /* umask. */
+ current_umask = umask(0);
+ umask(current_umask);
+
+ /* convert flags and mode to CreateFile parameters */
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
+ case _O_RDONLY:
+ access = FILE_GENERIC_READ;
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+ break;
+ case _O_WRONLY:
+ access = FILE_GENERIC_WRITE;
+ break;
+ case _O_RDWR:
+ access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ break;
+ default:
+ goto einval;
+ }
+
+ if (flags & _O_APPEND) {
+ access &= ~FILE_WRITE_DATA;
+ access |= FILE_APPEND_DATA;
+ attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
+ }
+
+ /*
+ * Here is where we deviate significantly from what CRT's _open()
+ * does. We indiscriminately use all the sharing modes, to match
+ * UNIX semantics. In particular, this ensures that the file can
+ * be deleted even whilst it's open, fixing issue #1449.
+ */
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ case 0:
+ case _O_EXCL:
+ disposition = OPEN_EXISTING;
+ break;
+ case _O_CREAT:
+ disposition = OPEN_ALWAYS;
+ break;
+ case _O_CREAT | _O_EXCL:
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
+ disposition = CREATE_NEW;
+ break;
+ case _O_TRUNC:
+ case _O_TRUNC | _O_EXCL:
+ disposition = TRUNCATE_EXISTING;
+ break;
+ case _O_CREAT | _O_TRUNC:
+ disposition = CREATE_ALWAYS;
+ break;
+ default:
+ goto einval;
+ }
+
+ attributes |= FILE_ATTRIBUTE_NORMAL;
+ if (flags & _O_CREAT) {
+ if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
+ attributes |= FILE_ATTRIBUTE_READONLY;
+ }
+ }
+
+ if (flags & _O_TEMPORARY ) {
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
+ access |= DELETE;
+ }
+
+ if (flags & _O_SHORT_LIVED) {
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
+ }
+
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ case 0:
+ break;
+ case _O_SEQUENTIAL:
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ break;
+ case _O_RANDOM:
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
+ break;
+ default:
+ goto einval;
+ }
+
+ /* Setting this flag makes it possible to open a directory. */
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ file = CreateFileW(req->file.pathw,
+ access,
+ share,
+ NULL,
+ disposition,
+ attributes,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
+ !(flags & _O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ /* specified, it means the path referred to a directory. */
+ SET_REQ_UV_ERROR(req, UV_EISDIR, error);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+ return;
+ }
+
+ fd = _open_osfhandle((intptr_t) file, flags);
+ if (fd < 0) {
+ /* The only known failure mode for _open_osfhandle() is EMFILE, in which
+ * case GetLastError() will return zero. However we'll try to handle other
+ * errors as well, should they ever occur.
+ */
+ if (errno == EMFILE)
+ SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
+ else if (GetLastError() != ERROR_SUCCESS)
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ else
+ SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ CloseHandle(file);
+ return;
+ }
+
+ SET_REQ_RESULT(req, fd);
+ return;
+
+ einval:
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+}
+
+void fs__close(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ if (fd > 2)
+ result = _close(fd);
+ else
+ result = 0;
+
+ /* _close doesn't set _doserrno on failure, but it does always set errno
+ * to EBADF on failure.
+ */
+ if (result == -1) {
+ assert(errno == EBADF);
+ SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
+ } else {
+ req->result = 0;
+ }
+}
+
+
+void fs__read(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ DWORD error;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = ReadFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ error = GetLastError();
+ if (error == ERROR_HANDLE_EOF) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, error);
+ }
+ }
+}
+
+
+void fs__write(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = WriteFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+}
+
+
+void fs__rmdir(uv_fs_t* req) {
+ int result = _wrmdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__unlink(uv_fs_t* req) {
+ const WCHAR* pathw = req->file.pathw;
+ HANDLE handle;
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_DISPOSITION_INFORMATION disposition;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ handle = CreateFileW(pathw,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (!GetFileInformationByHandle(handle, &info)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* Do not allow deletion of directories, unless it is a symlink. When */
+ /* the path refers to a non-symlink directory, report EPERM as mandated */
+ /* by POSIX.1. */
+
+ /* Check if it is a reparse point. If it's not, it's a normal directory. */
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ CloseHandle(handle);
+ return;
+ }
+
+ /* Read the reparse point and check if it is a valid symlink. */
+ /* If not, don't unlink. */
+ if (fs__readlink_handle(handle, NULL, NULL) < 0) {
+ DWORD error = GetLastError();
+ if (error == ERROR_SYMLINK_NOT_SUPPORTED)
+ error = ERROR_ACCESS_DENIED;
+ SET_REQ_WIN32_ERROR(req, error);
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ /* Remove read-only attribute */
+ FILE_BASIC_INFORMATION basic = { 0 };
+
+ basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &basic,
+ sizeof basic,
+ FileBasicInformation);
+ if (!NT_SUCCESS(status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ /* Try to set the delete flag. */
+ disposition.DeleteFile = TRUE;
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &disposition,
+ sizeof disposition,
+ FileDispositionInformation);
+ if (NT_SUCCESS(status)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+
+ CloseHandle(handle);
+}
+
+
+void fs__mkdir(uv_fs_t* req) {
+ /* TODO: use req->mode. */
+ int result = _wmkdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+/* OpenBSD original: lib/libc/stdio/mktemp.c */
+void fs__mkdtemp(uv_fs_t* req) {
+ static const WCHAR *tempchars =
+ L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static const size_t num_chars = 62;
+ static const size_t num_x = 6;
+ WCHAR *cp, *ep;
+ unsigned int tries, i;
+ size_t len;
+ HCRYPTPROV h_crypt_prov;
+ uint64_t v;
+ BOOL released;
+
+ len = wcslen(req->file.pathw);
+ ep = req->file.pathw + len;
+ if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ tries = TMP_MAX;
+ do {
+ if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ break;
+ }
+
+ cp = ep - num_x;
+ for (i = 0; i < num_x; i++) {
+ *cp++ = tempchars[v % num_chars];
+ v /= num_chars;
+ }
+
+ if (_wmkdir(req->file.pathw) == 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
+ SET_REQ_RESULT(req, 0);
+ break;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ break;
+ }
+ } while (--tries);
+
+ released = CryptReleaseContext(h_crypt_prov, 0);
+ assert(released);
+ if (tries == 0) {
+ SET_REQ_RESULT(req, -1);
+ }
+}
+
+
+void fs__scandir(uv_fs_t* req) {
+ static const size_t dirents_initial_size = 32;
+
+ HANDLE dir_handle = INVALID_HANDLE_VALUE;
+
+ uv__dirent_t** dirents = NULL;
+ size_t dirents_size = 0;
+ size_t dirents_used = 0;
+
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
+ * It's important that this buffer can hold at least one entry, regardless
+ * of the length of the file names present in the enumerated directory.
+ * A file name is at most 256 WCHARs long.
+ * According to MSDN, the buffer must be aligned at an 8-byte boundary.
+ */
+#if _MSC_VER
+ __declspec(align(8)) char buffer[8192];
+#else
+ __attribute__ ((aligned (8))) char buffer[8192];
+#endif
+
+ STATIC_ASSERT(sizeof buffer >=
+ sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
+
+ /* Open the directory. */
+ dir_handle =
+ CreateFileW(req->file.pathw,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (dir_handle == INVALID_HANDLE_VALUE)
+ goto win32_error;
+
+ /* Read the first chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ TRUE);
+
+ /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
+ * This should be reported back as UV_ENOTDIR.
+ */
+ if (status == STATUS_INVALID_PARAMETER)
+ goto not_a_directory_error;
+
+ while (NT_SUCCESS(status)) {
+ char* position = buffer;
+ size_t next_entry_offset = 0;
+
+ do {
+ FILE_DIRECTORY_INFORMATION* info;
+ uv__dirent_t* dirent;
+
+ size_t wchar_len;
+ size_t utf8_len;
+
+ /* Obtain a pointer to the current directory entry. */
+ position += next_entry_offset;
+ info = (FILE_DIRECTORY_INFORMATION*) position;
+
+ /* Fetch the offset to the next directory entry. */
+ next_entry_offset = info->NextEntryOffset;
+
+ /* Compute the length of the filename in WCHARs. */
+ wchar_len = info->FileNameLength / sizeof info->FileName[0];
+
+ /* Skip over '.' and '..' entries. */
+ if (wchar_len == 1 && info->FileName[0] == L'.')
+ continue;
+ if (wchar_len == 2 && info->FileName[0] == L'.' &&
+ info->FileName[1] == L'.')
+ continue;
+
+ /* Compute the space required to store the filename as UTF-8. */
+ utf8_len = WideCharToMultiByte(
+ CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
+ if (utf8_len == 0)
+ goto win32_error;
+
+ /* Resize the dirent array if needed. */
+ if (dirents_used >= dirents_size) {
+ size_t new_dirents_size =
+ dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
+ uv__dirent_t** new_dirents =
+ uv__realloc(dirents, new_dirents_size * sizeof *dirents);
+
+ if (new_dirents == NULL)
+ goto out_of_memory_error;
+
+ dirents_size = new_dirents_size;
+ dirents = new_dirents;
+ }
+
+ /* Allocate space for the uv dirent structure. The dirent structure
+ * includes room for the first character of the filename, but `utf8_len`
+ * doesn't count the NULL terminator at this point.
+ */
+ dirent = uv__malloc(sizeof *dirent + utf8_len);
+ if (dirent == NULL)
+ goto out_of_memory_error;
+
+ dirents[dirents_used++] = dirent;
+
+ /* Convert file name to UTF-8. */
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ &info->FileName[0],
+ wchar_len,
+ &dirent->d_name[0],
+ utf8_len,
+ NULL,
+ NULL) == 0)
+ goto win32_error;
+
+ /* Add a null terminator to the filename. */
+ dirent->d_name[utf8_len] = '\0';
+
+ /* Fill out the type field. */
+ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
+ dirent->d_type = UV__DT_CHAR;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ dirent->d_type = UV__DT_LINK;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ dirent->d_type = UV__DT_DIR;
+ else
+ dirent->d_type = UV__DT_FILE;
+ } while (next_entry_offset != 0);
+
+ /* Read the next chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ FALSE);
+
+ /* After the first pNtQueryDirectoryFile call, the function may return
+ * STATUS_SUCCESS even if the buffer was too small to hold at least one
+ * directory entry.
+ */
+ if (status == STATUS_SUCCESS && iosb.Information == 0)
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (status != STATUS_NO_MORE_FILES)
+ goto nt_error;
+
+ CloseHandle(dir_handle);
+
+ /* Store the result in the request object. */
+ req->ptr = dirents;
+ if (dirents != NULL)
+ req->flags |= UV_FS_FREE_PTR;
+
+ SET_REQ_RESULT(req, dirents_used);
+
+ /* `nbufs` will be used as index by uv_fs_scandir_next. */
+ req->fs.info.nbufs = 0;
+
+ return;
+
+nt_error:
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ goto cleanup;
+
+win32_error:
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto cleanup;
+
+not_a_directory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
+ goto cleanup;
+
+out_of_memory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
+ goto cleanup;
+
+cleanup:
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(dir_handle);
+ while (dirents_used > 0)
+ uv__free(dirents[--dirents_used]);
+ if (dirents != NULL)
+ uv__free(dirents);
+}
+
+
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+ FILE_ALL_INFORMATION file_info;
+ FILE_FS_VOLUME_INFORMATION volume_info;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileAllInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ }
+
+ nt_status = pNtQueryVolumeInformationFile(handle,
+ &io_status,
+ &volume_info,
+ sizeof volume_info,
+ FileFsVolumeInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
+ statbuf->st_dev = 0;
+ } else if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ } else {
+ statbuf->st_dev = volume_info.VolumeSerialNumber;
+ }
+
+ /* Todo: st_mode should probably always be 0666 for everyone. We might also
+ * want to report 0777 if the file is a .exe or a directory.
+ *
+ * Currently it's based on whether the 'readonly' attribute is set, which
+ * makes little sense because the semantics are so different: the 'read-only'
+ * flag is just a way for a user to protect against accidental deletion, and
+ * serves no security purpose. Windows uses ACLs for that.
+ *
+ * Also people now use uv_fs_chmod() to take away the writable bit for good
+ * reasons. Windows however just makes the file read-only, which makes it
+ * impossible to delete the file afterwards, since read-only files can't be
+ * deleted.
+ *
+ * IOW it's all just a clusterfuck and we should think of something that
+ * makes slightly more sense.
+ *
+ * And uv_fs_chmod should probably just fail on windows or be a total no-op.
+ * There's nothing sensible it can do anyway.
+ */
+ statbuf->st_mode = 0;
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ statbuf->st_mode |= S_IFLNK;
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
+ return -1;
+
+ } else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ statbuf->st_mode |= _S_IFDIR;
+ statbuf->st_size = 0;
+
+ } else {
+ statbuf->st_mode |= _S_IFREG;
+ statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
+ }
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
+ else
+ statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
+ ((_S_IREAD | _S_IWRITE) >> 6);
+
+ FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+
+ statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
+
+ /* st_blocks contains the on-disk allocation size in 512-byte units. */
+ statbuf->st_blocks =
+ file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+
+ statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
+
+ /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
+ * and writing to the disk. That is, for any definition of 'optimal' - it's
+ * supposed to at least avoid read-update-write behavior when writing to the
+ * disk.
+ *
+ * However nobody knows this and even fewer people actually use this value,
+ * and in order to fill it out we'd have to make another syscall to query the
+ * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
+ *
+ * Therefore we'll just report a sensible value that's quite commonly okay
+ * on modern hardware.
+ */
+ statbuf->st_blksize = 2048;
+
+ /* Todo: set st_flags to something meaningful. Also provide a wrapper for
+ * chattr(2).
+ */
+ statbuf->st_flags = 0;
+
+ /* Windows has nothing sensible to say about these values, so they'll just
+ * remain empty.
+ */
+ statbuf->st_gid = 0;
+ statbuf->st_uid = 0;
+ statbuf->st_rdev = 0;
+ statbuf->st_gen = 0;
+
+ return 0;
+}
+
+
+INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
+ size_t len = wcslen(pathw);
+
+ /* TODO: ignore namespaced paths. */
+ if (len > 1 && pathw[len - 2] != L':' &&
+ (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
+ pathw[len - 1] = '\0';
+ }
+}
+
+
+INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+ HANDLE handle;
+ DWORD flags;
+
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (do_lstat) {
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ flags,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ DWORD error = GetLastError();
+ if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ /* We opened a reparse point but it was not a symlink. Try again. */
+ fs__stat_impl(req, 0);
+
+ } else {
+ /* Stat failed. */
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+
+ CloseHandle(handle);
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+ CloseHandle(handle);
+}
+
+
+static void fs__stat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 0);
+}
+
+
+static void fs__lstat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 1);
+}
+
+
+static void fs__fstat(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+}
+
+
+static void fs__rename(uv_fs_t* req) {
+ if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
+INLINE static void fs__sync_impl(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+}
+
+
+static void fs__fsync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__fdatasync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__ftruncate(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status;
+ FILE_END_OF_FILE_INFORMATION eof_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ eof_info.EndOfFile.QuadPart = req->fs.info.offset;
+
+ status = pNtSetInformationFile(handle,
+ &io_status,
+ &eof_info,
+ sizeof eof_info,
+ FileEndOfFileInformation);
+
+ if (NT_SUCCESS(status)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+}
+
+
+static void fs__sendfile(uv_fs_t* req) {
+ int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
+ size_t length = req->fs.info.bufsml[0].len;
+ int64_t offset = req->fs.info.offset;
+ const size_t max_buf_size = 65536;
+ size_t buf_size = length < max_buf_size ? length : max_buf_size;
+ int n, result = 0;
+ int64_t result_offset = 0;
+ char* buf = (char*) uv__malloc(buf_size);
+ if (!buf) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (offset != -1) {
+ result_offset = _lseeki64(fd_in, offset, SEEK_SET);
+ }
+
+ if (result_offset == -1) {
+ result = -1;
+ } else {
+ while (length > 0) {
+ n = _read(fd_in, buf, length < buf_size ? length : buf_size);
+ if (n == 0) {
+ break;
+ } else if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ length -= n;
+
+ n = _write(fd_out, buf, n);
+ if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ result += n;
+ }
+ }
+
+ uv__free(buf);
+
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__access(uv_fs_t* req) {
+ DWORD attr = GetFileAttributesW(req->file.pathw);
+
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ /*
+ * Access is possible if
+ * - write access wasn't requested,
+ * - or the file isn't read-only,
+ * - or it's a directory.
+ * (Directories cannot be read-only on Windows.)
+ */
+ if (!(req->flags & W_OK) ||
+ !(attr & FILE_ATTRIBUTE_READONLY) ||
+ (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, UV_EPERM);
+ }
+
+}
+
+
+static void fs__chmod(uv_fs_t* req) {
+ int result = _wchmod(req->file.pathw, req->fs.info.mode);
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__fchmod(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_BASIC_INFORMATION file_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ if (req->fs.info.mode & _S_IWRITE) {
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+ } else {
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ nt_status = pNtSetInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
+ FILETIME filetime_a, filetime_m;
+
+ TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
+ TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
+
+ if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void fs__utime(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ CloseHandle(handle);
+
+ req->result = 0;
+}
+
+
+static void fs__futime(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->result = 0;
+}
+
+
+static void fs__link(uv_fs_t* req) {
+ DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
+ if (r == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ req->result = 0;
+ }
+}
+
+
+static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
+ const WCHAR* new_path) {
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ int created = 0;
+ int target_len;
+ int is_absolute, is_long_path;
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
+ int start, len, i;
+ int add_slash;
+ DWORD bytes;
+ WCHAR* path_buf;
+
+ target_len = wcslen(path);
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
+
+ if (is_long_path) {
+ is_absolute = 1;
+ } else {
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
+ path[1] == L':' && IS_SLASH(path[2]);
+ }
+
+ if (!is_absolute) {
+ /* Not supporting relative paths */
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ /* Do a pessimistic calculation of the required buffer size */
+ needed_buf_size =
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
+ 2 * (target_len + 2) * sizeof(WCHAR);
+
+ /* Allocate the buffer */
+ buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
+ if (!buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Grab a pointer to the part of the buffer where filenames go */
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
+ path_buf_len = 0;
+
+ /* Copy the substitute (internal) target path */
+ start = path_buf_len;
+
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
+ JUNCTION_PREFIX_LEN);
+ path_buf_len += JUNCTION_PREFIX_LEN;
+
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ path_buf[path_buf_len++] = L'\\';
+ len = path_buf_len - start;
+
+ /* Set the info about the substitute name */
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
+
+ /* Insert null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Copy the print name of the target path */
+ start = path_buf_len;
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ len = path_buf_len - start;
+ if (len == 2) {
+ path_buf[path_buf_len++] = L'\\';
+ len++;
+ }
+
+ /* Set the info about the print name */
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
+
+ /* Insert another null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Calculate how much buffer space was actually used */
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ path_buf_len * sizeof(WCHAR);
+ used_data_size = used_buf_size -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
+
+ /* Put general info in the data buffer */
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = used_data_size;
+ buffer->Reserved = 0;
+
+ /* Create a new directory */
+ if (!CreateDirectoryW(new_path, NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+ created = 1;
+
+ /* Open the directory */
+ handle = CreateFileW(new_path,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Create the actual reparse point */
+ if (!DeviceIoControl(handle,
+ FSCTL_SET_REPARSE_POINT,
+ buffer,
+ used_buf_size,
+ NULL,
+ 0,
+ &bytes,
+ NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Clean up */
+ CloseHandle(handle);
+ uv__free(buffer);
+
+ SET_REQ_RESULT(req, 0);
+ return;
+
+error:
+ uv__free(buffer);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+
+ if (created) {
+ RemoveDirectoryW(new_path);
+ }
+}
+
+
+static void fs__symlink(uv_fs_t* req) {
+ WCHAR* pathw = req->file.pathw;
+ WCHAR* new_pathw = req->fs.info.new_pathw;
+ int flags = req->fs.info.file_flags;
+ int result;
+
+
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
+ fs__create_junction(req, pathw, new_pathw);
+ } else if (pCreateSymbolicLinkW) {
+ result = pCreateSymbolicLinkW(new_pathw,
+ pathw,
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+ } else {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ }
+}
+
+
+static void fs__readlink(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+
+ CloseHandle(handle);
+}
+
+
+static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+ int r;
+ DWORD w_realpath_len;
+ WCHAR* w_realpath_ptr;
+ WCHAR* w_finalpath_ptr = NULL;
+
+ w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+ if (w_realpath_len == 0) {
+ return -1;
+ }
+
+ w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
+ if (w_realpath_ptr == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ if (pGetFinalPathNameByHandleW(handle,
+ w_realpath_ptr,
+ w_realpath_len,
+ VOLUME_NAME_DOS) == 0) {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ /* convert UNC path to long path */
+ if (wcsncmp(w_realpath_ptr,
+ UNC_PATH_PREFIX,
+ UNC_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 6;
+ *w_finalpath_ptr = L'\\';
+ } else if (wcsncmp(w_realpath_ptr,
+ LONG_PATH_PREFIX,
+ LONG_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 4;
+ } else {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL);
+ uv__free(w_realpath_ptr);
+ return r;
+}
+
+static void fs__realpath(uv_fs_t* req) {
+ HANDLE handle;
+
+ if (!pGetFinalPathNameByHandleW) {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
+ CloseHandle(handle);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ CloseHandle(handle);
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
+
+static void fs__chown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void fs__fchown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ assert(req->type == UV_FS);
+
+#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
+ switch (req->fs_type) {
+ XX(OPEN, open)
+ XX(CLOSE, close)
+ XX(READ, read)
+ XX(WRITE, write)
+ XX(SENDFILE, sendfile)
+ XX(STAT, stat)
+ XX(LSTAT, lstat)
+ XX(FSTAT, fstat)
+ XX(FTRUNCATE, ftruncate)
+ XX(UTIME, utime)
+ XX(FUTIME, futime)
+ XX(ACCESS, access)
+ XX(CHMOD, chmod)
+ XX(FCHMOD, fchmod)
+ XX(FSYNC, fsync)
+ XX(FDATASYNC, fdatasync)
+ XX(UNLINK, unlink)
+ XX(RMDIR, rmdir)
+ XX(MKDIR, mkdir)
+ XX(MKDTEMP, mkdtemp)
+ XX(RENAME, rename)
+ XX(SCANDIR, scandir)
+ XX(LINK, link)
+ XX(SYMLINK, symlink)
+ XX(READLINK, readlink)
+ XX(REALPATH, realpath)
+ XX(CHOWN, chown)
+ XX(FCHOWN, fchown);
+ default:
+ assert(!"bad uv_fs_type");
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == UV_ECANCELED) {
+ assert(req->result == 0);
+ req->result = UV_ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req->flags & UV_FS_CLEANEDUP)
+ return;
+
+ if (req->flags & UV_FS_FREE_PATHS)
+ uv__free(req->file.pathw);
+
+ if (req->flags & UV_FS_FREE_PTR)
+ uv__free(req->ptr);
+
+ req->path = NULL;
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->ptr = NULL;
+
+ req->flags |= UV_FS_CLEANEDUP;
+}
+
+
+int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ int mode, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__open(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__close(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__read(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__write(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__unlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
+
+ err = fs__capture_path(req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdtemp(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rmdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__scandir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__link(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, int flags, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__symlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__readlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ if (!req || !path) {
+ return UV_EINVAL;
+ }
+
+ uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__realpath(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__stat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__lstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rename(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fsync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fdatasync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
+ int64_t offset, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
+
+ req->file.fd = fd;
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__ftruncate(req);
+ return req->result;
+ }
+}
+
+
+
+int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
+
+ req->file.fd = fd_in;
+ req->fs.info.fd_out = fd_out;
+ req->fs.info.offset = in_offset;
+ req->fs.info.bufsml[0].len = length;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__sendfile(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ }
+
+ fs__access(req);
+ return req->result;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
+ uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
+
+ req->file.fd = fd;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
+ double mtime, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__utime(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
+ double mtime, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
+
+ req->file.fd = fd;
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__futime(req);
+ return req->result;
+ }
+}
diff --git a/3rdparty/libuv/src/win/getaddrinfo.c b/3rdparty/libuv/src/win/getaddrinfo.c
new file mode 100644
index 00000000000..ceed3b7638b
--- /dev/null
+++ b/3rdparty/libuv/src/win/getaddrinfo.c
@@ -0,0 +1,358 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+/* EAI_* constants. */
+#include <winsock2.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+ case WSATRY_AGAIN: return UV_EAI_AGAIN;
+ case WSAEINVAL: return UV_EAI_BADFLAGS;
+ case WSANO_RECOVERY: return UV_EAI_FAIL;
+ case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
+ case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
+ case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
+ case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
+ case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
+ default: return uv_translate_sys_error(sys_err);
+ }
+}
+
+
+/*
+ * MinGW is missing this
+ */
+#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ WCHAR* ai_canonname;
+ struct sockaddr* ai_addr;
+ struct addrinfoW* ai_next;
+ } ADDRINFOW, *PADDRINFOW;
+
+ DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
+ const WCHAR* service,
+ const ADDRINFOW* hints,
+ PADDRINFOW* result);
+
+ DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+#endif
+
+
+/* adjust size value to be multiple of 4. Use to keep pointer aligned */
+/* Do we need different versions of this for different architectures? */
+#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ struct addrinfoW* hints;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ hints = req->addrinfow;
+ req->addrinfow = NULL;
+ err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+/*
+ * Called from uv_run when complete. Call user specified callback
+ * then free returned addrinfo
+ * Returned addrinfo strings are converted from UTF-16 to UTF-8.
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+ int addrinfo_len = 0;
+ int name_len = 0;
+ size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
+ struct addrinfoW* addrinfow_ptr;
+ struct addrinfo* addrinfo_ptr;
+ char* alloc_ptr = NULL;
+ char* cur_ptr = NULL;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+
+ /* release input parameter memory */
+ uv__free(req->alloc);
+ req->alloc = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ goto complete;
+ }
+
+ if (req->retcode == 0) {
+ /* convert addrinfoW to addrinfo */
+ /* first calculate required length */
+ addrinfow_ptr = req->addrinfow;
+ while (addrinfow_ptr != NULL) {
+ addrinfo_len += addrinfo_struct_len +
+ ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
+ if (name_len == 0) {
+ req->retcode = uv_translate_sys_error(GetLastError());
+ goto complete;
+ }
+ addrinfo_len += ALIGNED_SIZE(name_len);
+ }
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ }
+
+ /* allocate memory for addrinfo results */
+ alloc_ptr = (char*)uv__malloc(addrinfo_len);
+
+ /* do conversions */
+ if (alloc_ptr != NULL) {
+ cur_ptr = alloc_ptr;
+ addrinfow_ptr = req->addrinfow;
+
+ while (addrinfow_ptr != NULL) {
+ /* copy addrinfo struct data */
+ assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
+ addrinfo_ptr = (struct addrinfo*)cur_ptr;
+ addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
+ addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
+ addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
+ addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
+ addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
+ addrinfo_ptr->ai_canonname = NULL;
+ addrinfo_ptr->ai_addr = NULL;
+ addrinfo_ptr->ai_next = NULL;
+
+ cur_ptr += addrinfo_struct_len;
+
+ /* copy sockaddr */
+ if (addrinfo_ptr->ai_addrlen > 0) {
+ assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
+ alloc_ptr + addrinfo_len);
+ memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
+ addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
+ cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
+ }
+
+ /* convert canonical name to UTF-8 */
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0);
+ assert(name_len > 0);
+ assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
+ -1,
+ cur_ptr,
+ name_len);
+ assert(name_len > 0);
+ addrinfo_ptr->ai_canonname = cur_ptr;
+ cur_ptr += ALIGNED_SIZE(name_len);
+ }
+ assert(cur_ptr <= alloc_ptr + addrinfo_len);
+
+ /* set next ptr */
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ if (addrinfow_ptr != NULL) {
+ addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
+ }
+ }
+ req->addrinfo = (struct addrinfo*)alloc_ptr;
+ } else {
+ req->retcode = UV_EAI_MEMORY;
+ }
+ }
+
+ /* return memory to system */
+ if (req->addrinfow != NULL) {
+ FreeAddrInfoW(req->addrinfow);
+ req->addrinfow = NULL;
+ }
+
+complete:
+ uv__req_unregister(req->loop, req);
+
+ /* finally do callback with converted result */
+ if (req->getaddrinfo_cb)
+ req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ char* alloc_ptr = (char*)ai;
+
+ /* release copied result memory */
+ uv__free(alloc_ptr);
+}
+
+
+/*
+ * Entry point for getaddrinfo
+ * we convert the UTF-8 strings to UNICODE
+ * and save the UNICODE string pointers in the req
+ * We also copy hints so that caller does not need to keep memory until the
+ * callback.
+ * return 0 if a callback will be made
+ * return error code if validation fails
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints) {
+ int nodesize = 0;
+ int servicesize = 0;
+ int hintssize = 0;
+ char* alloc_ptr = NULL;
+ int err;
+
+ if (req == NULL || (node == NULL && service == NULL)) {
+ err = WSAEINVAL;
+ goto error;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+
+ req->getaddrinfo_cb = getaddrinfo_cb;
+ req->addrinfo = NULL;
+ req->type = UV_GETADDRINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ /* calculate required memory size for all input values */
+ if (node != NULL) {
+ nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR));
+ if (nodesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ if (service != NULL) {
+ servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) *
+ sizeof(WCHAR));
+ if (servicesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+ if (hints != NULL) {
+ hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
+ }
+
+ /* allocate memory for inputs, and partition it as needed */
+ alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
+ if (!alloc_ptr) {
+ err = WSAENOBUFS;
+ goto error;
+ }
+
+ /* save alloc_ptr now so we can free if error */
+ req->alloc = (void*)alloc_ptr;
+
+ /* convert node string to UTF16 into allocated memory and save pointer in */
+ /* the request. */
+ if (node != NULL) {
+ req->node = (WCHAR*)alloc_ptr;
+ if (uv_utf8_to_utf16(node,
+ (WCHAR*) alloc_ptr,
+ nodesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += nodesize;
+ } else {
+ req->node = NULL;
+ }
+
+ /* convert service string to UTF16 into allocated memory and save pointer */
+ /* in the req. */
+ if (service != NULL) {
+ req->service = (WCHAR*)alloc_ptr;
+ if (uv_utf8_to_utf16(service,
+ (WCHAR*) alloc_ptr,
+ servicesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += servicesize;
+ } else {
+ req->service = NULL;
+ }
+
+ /* copy hints to allocated memory and save pointer in req */
+ if (hints != NULL) {
+ req->addrinfow = (struct addrinfoW*)alloc_ptr;
+ req->addrinfow->ai_family = hints->ai_family;
+ req->addrinfow->ai_socktype = hints->ai_socktype;
+ req->addrinfow->ai_protocol = hints->ai_protocol;
+ req->addrinfow->ai_flags = hints->ai_flags;
+ req->addrinfow->ai_addrlen = 0;
+ req->addrinfow->ai_canonname = NULL;
+ req->addrinfow->ai_addr = NULL;
+ req->addrinfow->ai_next = NULL;
+ } else {
+ req->addrinfow = NULL;
+ }
+
+ uv__req_register(loop, req);
+
+ if (getaddrinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+
+error:
+ if (req != NULL) {
+ uv__free(req->alloc);
+ req->alloc = NULL;
+ }
+ return uv_translate_sys_error(err);
+}
diff --git a/3rdparty/libuv/src/win/getnameinfo.c b/3rdparty/libuv/src/win/getnameinfo.c
new file mode 100644
index 00000000000..66b64b88324
--- /dev/null
+++ b/3rdparty/libuv/src/win/getnameinfo.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+#ifndef GetNameInfo
+int WSAAPI GetNameInfoW(
+ const SOCKADDR *pSockaddr,
+ socklen_t SockaddrLength,
+ PWCHAR pNodeBuffer,
+ DWORD NodeBufferSize,
+ PWCHAR pServiceBuffer,
+ DWORD ServiceBufferSize,
+ INT Flags
+);
+#endif
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ if (GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ ARRAY_SIZE(host),
+ service,
+ ARRAY_SIZE(service),
+ req->flags)) {
+ ret = WSAGetLastError();
+ }
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+ uv__req_register(loop, req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/3rdparty/libuv/src/win/handle-inl.h b/3rdparty/libuv/src/win/handle-inl.h
new file mode 100644
index 00000000000..8d0334cc52a
--- /dev/null
+++ b/3rdparty/libuv/src/win/handle-inl.h
@@ -0,0 +1,179 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_HANDLE_INL_H_
+#define UV_WIN_HANDLE_INL_H_
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define DECREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if (--(handle)->activecnt == 0 && \
+ !((handle)->flags & UV__HANDLE_CLOSING)) { \
+ uv__handle_stop((handle)); \
+ } \
+ assert((handle)->activecnt >= 0); \
+ } while (0)
+
+
+#define INCREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if ((handle)->activecnt++ == 0) { \
+ uv__handle_start((handle)); \
+ } \
+ assert((handle)->activecnt > 0); \
+ } while (0)
+
+
+#define DECREASE_PENDING_REQ_COUNT(handle) \
+ do { \
+ assert(handle->reqs_pending > 0); \
+ handle->reqs_pending--; \
+ \
+ if (handle->flags & UV__HANDLE_CLOSING && \
+ handle->reqs_pending == 0) { \
+ uv_want_endgame(loop, (uv_handle_t*)handle); \
+ } \
+ } while (0)
+
+
+#define uv__handle_closing(handle) \
+ do { \
+ assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
+ \
+ if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
+ ((handle)->flags & UV__HANDLE_REF))) \
+ uv__active_handle_add((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV__HANDLE_CLOSING; \
+ (handle)->flags &= ~UV__HANDLE_ACTIVE; \
+ } while (0)
+
+
+#define uv__handle_close(handle) \
+ do { \
+ QUEUE_REMOVE(&(handle)->handle_queue); \
+ uv__active_handle_rm((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV_HANDLE_CLOSED; \
+ \
+ if ((handle)->close_cb) \
+ (handle)->close_cb((uv_handle_t*) (handle)); \
+ } while (0)
+
+
+INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
+ handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
+
+ handle->endgame_next = loop->endgame_handles;
+ loop->endgame_handles = handle;
+ }
+}
+
+
+INLINE static void uv_process_endgames(uv_loop_t* loop) {
+ uv_handle_t* handle;
+
+ while (loop->endgame_handles) {
+ handle = loop->endgame_handles;
+ loop->endgame_handles = handle->endgame_next;
+
+ handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+ break;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+ break;
+
+ case UV_TTY:
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
+ break;
+
+ case UV_UDP:
+ uv_udp_endgame(loop, (uv_udp_t*) handle);
+ break;
+
+ case UV_POLL:
+ uv_poll_endgame(loop, (uv_poll_t*) handle);
+ break;
+
+ case UV_TIMER:
+ uv_timer_endgame(loop, (uv_timer_t*) handle);
+ break;
+
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ uv_loop_watcher_endgame(loop, handle);
+ break;
+
+ case UV_ASYNC:
+ uv_async_endgame(loop, (uv_async_t*) handle);
+ break;
+
+ case UV_SIGNAL:
+ uv_signal_endgame(loop, (uv_signal_t*) handle);
+ break;
+
+ case UV_PROCESS:
+ uv_process_endgame(loop, (uv_process_t*) handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+INLINE static HANDLE uv__get_osfhandle(int fd)
+{
+ /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
+ /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
+ /* for invalid FDs in release builds (or if you let the assert continue). */
+ /* So this wrapper function disables asserts when calling _get_osfhandle. */
+
+ HANDLE handle;
+ UV_BEGIN_DISABLE_CRT_ASSERT();
+ handle = (HANDLE) _get_osfhandle(fd);
+ UV_END_DISABLE_CRT_ASSERT();
+ return handle;
+}
+
+#endif /* UV_WIN_HANDLE_INL_H_ */
diff --git a/3rdparty/libuv/src/win/handle.c b/3rdparty/libuv/src/win/handle.c
new file mode 100644
index 00000000000..72b49d97904
--- /dev/null
+++ b/3rdparty/libuv/src/win/handle.c
@@ -0,0 +1,154 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ HANDLE handle;
+ DWORD mode;
+
+ if (file < 0) {
+ return UV_UNKNOWN_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(file);
+
+ switch (GetFileType(handle)) {
+ case FILE_TYPE_CHAR:
+ if (GetConsoleMode(handle, &mode)) {
+ return UV_TTY;
+ } else {
+ return UV_FILE;
+ }
+
+ case FILE_TYPE_PIPE:
+ return UV_NAMED_PIPE;
+
+ case FILE_TYPE_DISK:
+ return UV_FILE;
+
+ default:
+ return UV_UNKNOWN_HANDLE;
+ }
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return (handle->flags & UV__HANDLE_ACTIVE) &&
+ !(handle->flags & UV__HANDLE_CLOSING);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(0);
+ return;
+ }
+
+ handle->close_cb = cb;
+
+ /* Handle-specific close actions */
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_close(loop, (uv_tcp_t*)handle);
+ return;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_close(loop, (uv_pipe_t*) handle);
+ return;
+
+ case UV_TTY:
+ uv_tty_close((uv_tty_t*) handle);
+ return;
+
+ case UV_UDP:
+ uv_udp_close(loop, (uv_udp_t*) handle);
+ return;
+
+ case UV_POLL:
+ uv_poll_close(loop, (uv_poll_t*) handle);
+ return;
+
+ case UV_TIMER:
+ uv_timer_stop((uv_timer_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_PREPARE:
+ uv_prepare_stop((uv_prepare_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_CHECK:
+ uv_check_stop((uv_check_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_IDLE:
+ uv_idle_stop((uv_idle_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_ASYNC:
+ uv_async_close(loop, (uv_async_t*) handle);
+ return;
+
+ case UV_SIGNAL:
+ uv_signal_close(loop, (uv_signal_t*) handle);
+ return;
+
+ case UV_PROCESS:
+ uv_process_close(loop, (uv_process_t*) handle);
+ return;
+
+ case UV_FS_EVENT:
+ uv_fs_event_close(loop, (uv_fs_event_t*) handle);
+ return;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*) handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ default:
+ /* Not supported */
+ abort();
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
+}
diff --git a/3rdparty/libuv/src/win/internal.h b/3rdparty/libuv/src/win/internal.h
new file mode 100644
index 00000000000..783f21af0fe
--- /dev/null
+++ b/3rdparty/libuv/src/win/internal.h
@@ -0,0 +1,382 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_INTERNAL_H_
+#define UV_WIN_INTERNAL_H_
+
+#include "uv.h"
+#include "../uv-common.h"
+
+#include "tree.h"
+#include "winapi.h"
+#include "winsock.h"
+
+#ifdef _MSC_VER
+# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
+#else
+# define INLINE inline
+# define UV_THREAD_LOCAL __thread
+#endif
+
+
+#ifdef _DEBUG
+
+extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
+
+#define UV_BEGIN_DISABLE_CRT_ASSERT() \
+ { \
+ int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
+ uv__crt_assert_enabled = FALSE;
+
+
+#define UV_END_DISABLE_CRT_ASSERT() \
+ uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
+ }
+
+#else
+#define UV_BEGIN_DISABLE_CRT_ASSERT()
+#define UV_END_DISABLE_CRT_ASSERT()
+#endif
+
+/*
+ * Handles
+ * (also see handle-inl.h)
+ */
+
+/* Used by all handles. */
+#define UV_HANDLE_CLOSED 0x00000002
+#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
+
+/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
+/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
+/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
+/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
+
+/* Used by streams and UDP handles. */
+#define UV_HANDLE_READING 0x00000100
+#define UV_HANDLE_BOUND 0x00000200
+#define UV_HANDLE_LISTENING 0x00000800
+#define UV_HANDLE_CONNECTION 0x00001000
+#define UV_HANDLE_READABLE 0x00008000
+#define UV_HANDLE_WRITABLE 0x00010000
+#define UV_HANDLE_READ_PENDING 0x00020000
+#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
+#define UV_HANDLE_ZERO_READ 0x00080000
+#define UV_HANDLE_EMULATE_IOCP 0x00100000
+#define UV_HANDLE_BLOCKING_WRITES 0x00200000
+
+/* Used by uv_tcp_t and uv_udp_t handles */
+#define UV_HANDLE_IPV6 0x01000000
+
+/* Only used by uv_tcp_t handles. */
+#define UV_HANDLE_TCP_NODELAY 0x02000000
+#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
+#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
+#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
+#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
+#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
+
+/* Only used by uv_pipe_t handles. */
+#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
+#define UV_HANDLE_PIPESERVER 0x02000000
+#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
+
+/* Only used by uv_tty_t handles. */
+#define UV_HANDLE_TTY_READABLE 0x01000000
+#define UV_HANDLE_TTY_RAW 0x02000000
+#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
+#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
+
+/* Only used by uv_poll_t handles. */
+#define UV_HANDLE_POLL_SLOW 0x02000000
+
+
+/*
+ * Requests: see req-inl.h
+ */
+
+
+/*
+ * Streams: see stream-inl.h
+ */
+
+
+/*
+ * TCP
+ */
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ int delayed_error;
+} uv__ipc_socket_info_ex;
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req);
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req);
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req);
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection);
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info);
+
+
+/*
+ * UDP
+ */
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req);
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
+
+
+/*
+ * Pipes
+ */
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize);
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
+ uv_write_cb cb);
+void uv__pipe_pause_read(uv_pipe_t* handle);
+void uv__pipe_unpause_read(uv_pipe_t* handle);
+void uv__pipe_stop_read(uv_pipe_t* handle);
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req);
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req);
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req);
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req);
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req);
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+
+
+/*
+ * TTY
+ */
+void uv_console_init();
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tty_read_stop(uv_tty_t* handle);
+int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+void uv_tty_close(uv_tty_t* handle);
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req);
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req);
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req);
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req);
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
+
+
+/*
+ * Poll watchers
+ */
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req);
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+
+
+/*
+ * Timers
+ */
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
+
+DWORD uv__next_timeout(const uv_loop_t* loop);
+void uv__time_forward(uv_loop_t* loop, uint64_t msecs);
+void uv_process_timers(uv_loop_t* loop);
+
+
+/*
+ * Loop watchers
+ */
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
+
+void uv_prepare_invoke(uv_loop_t* loop);
+void uv_check_invoke(uv_loop_t* loop);
+void uv_idle_invoke(uv_loop_t* loop);
+
+void uv__once_init();
+
+
+/*
+ * Async watcher
+ */
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Signal watcher
+ */
+void uv_signals_init();
+int uv__signal_dispatch(int signum);
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Spawn
+ */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
+
+
+/*
+ * Error
+ */
+int uv_translate_sys_error(int sys_errno);
+
+
+/*
+ * FS
+ */
+void uv_fs_init();
+
+
+/*
+ * FS Event
+ */
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle);
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
+
+
+/*
+ * Stat poller.
+ */
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
+
+
+/*
+ * Utilities.
+ */
+void uv__util_init();
+
+uint64_t uv__hrtime(double scale);
+int uv_parent_pid();
+int uv_current_pid();
+__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
+
+
+/*
+ * Process stdio handles.
+ */
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr);
+void uv__stdio_destroy(BYTE* buffer);
+void uv__stdio_noinherit(BYTE* buffer);
+int uv__stdio_verify(BYTE* buffer, WORD size);
+WORD uv__stdio_size(BYTE* buffer);
+HANDLE uv__stdio_handle(BYTE* buffer, int fd);
+
+
+/*
+ * Winapi and ntapi utility functions
+ */
+void uv_winapi_init();
+
+
+/*
+ * Winsock utility functions
+ */
+void uv_winsock_init();
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status);
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
+
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+extern int uv_tcp_non_ifs_lsp_ipv4;
+extern int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+extern struct sockaddr_in uv_addr_ip4_any_;
+extern struct sockaddr_in6 uv_addr_ip6_any_;
+
+#endif /* UV_WIN_INTERNAL_H_ */
diff --git a/3rdparty/libuv/src/win/loop-watcher.c b/3rdparty/libuv/src/win/loop-watcher.c
new file mode 100644
index 00000000000..20e4509f838
--- /dev/null
+++ b/3rdparty/libuv/src/win/loop-watcher.c
@@ -0,0 +1,122 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+ uv__handle_close(handle);
+ }
+}
+
+
+#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ uv_loop_t* loop = handle->loop; \
+ uv_##name##_t* old_head; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (uv__is_active(handle)) \
+ return 0; \
+ \
+ if (cb == NULL) \
+ return UV_EINVAL; \
+ \
+ old_head = loop->name##_handles; \
+ \
+ handle->name##_next = old_head; \
+ handle->name##_prev = NULL; \
+ \
+ if (old_head) { \
+ old_head->name##_prev = handle; \
+ } \
+ \
+ loop->name##_handles = handle; \
+ \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ uv_loop_t* loop = handle->loop; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (!uv__is_active(handle)) \
+ return 0; \
+ \
+ /* Update loop head if needed */ \
+ if (loop->name##_handles == handle) { \
+ loop->name##_handles = handle->name##_next; \
+ } \
+ \
+ /* Update the iterator-next pointer of needed */ \
+ if (loop->next_##name##_handle == handle) { \
+ loop->next_##name##_handle = handle->name##_next; \
+ } \
+ \
+ if (handle->name##_prev) { \
+ handle->name##_prev->name##_next = handle->name##_next; \
+ } \
+ if (handle->name##_next) { \
+ handle->name##_next->name##_prev = handle->name##_prev; \
+ } \
+ \
+ uv__handle_stop(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ void uv_##name##_invoke(uv_loop_t* loop) { \
+ uv_##name##_t* handle; \
+ \
+ (loop)->next_##name##_handle = (loop)->name##_handles; \
+ \
+ while ((loop)->next_##name##_handle != NULL) { \
+ handle = (loop)->next_##name##_handle; \
+ (loop)->next_##name##_handle = handle->name##_next; \
+ \
+ handle->name##_cb(handle); \
+ } \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/3rdparty/libuv/src/win/pipe.c b/3rdparty/libuv/src/win/pipe.c
new file mode 100644
index 00000000000..bcce80c77e5
--- /dev/null
+++ b/3rdparty/libuv/src/win/pipe.c
@@ -0,0 +1,2118 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
+
+struct uv__ipc_queue_item_s {
+ /*
+ * NOTE: It is important for socket_info_ex to be the first field,
+ * because we will we assigning it to the pending_ipc_info.socket_info
+ */
+ uv__ipc_socket_info_ex socket_info_ex;
+ QUEUE member;
+ int tcp_connection;
+};
+
+/* A zero-size buffer for use by uv_pipe_read */
+static char uv_zero_[] = "";
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+/* The timeout that the pipe will wait for the remote end to write data */
+/* when the local ends wants to shut it down. */
+static const int64_t eof_timeout = 50; /* ms */
+
+static const int default_pending_pipe_instances = 4;
+
+/* Pipe prefix */
+static char pipe_prefix[] = "\\\\?\\pipe";
+static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
+
+/* IPC protocol flags. */
+#define UV_IPC_RAW_DATA 0x0001
+#define UV_IPC_TCP_SERVER 0x0002
+#define UV_IPC_TCP_CONNECTION 0x0004
+
+/* IPC frame header. */
+typedef struct {
+ int flags;
+ uint64_t raw_data_length;
+} uv_ipc_frame_header_t;
+
+/* IPC frame, which contains an imported TCP socket stream. */
+typedef struct {
+ uv_ipc_frame_header_t header;
+ uv__ipc_socket_info_ex socket_info_ex;
+} uv_ipc_frame_uv_stream;
+
+static void eof_timer_init(uv_pipe_t* pipe);
+static void eof_timer_start(uv_pipe_t* pipe);
+static void eof_timer_stop(uv_pipe_t* pipe);
+static void eof_timer_cb(uv_timer_t* timer);
+static void eof_timer_destroy(uv_pipe_t* pipe);
+static void eof_timer_close_cb(uv_handle_t* handle);
+
+
+static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
+ snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
+}
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+
+ handle->reqs_pending = 0;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->name = NULL;
+ handle->pipe.conn.ipc_pid = 0;
+ handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
+ QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+ handle->ipc = ipc;
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ handle->pipe.conn.readfile_thread = NULL;
+
+ uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
+
+ return 0;
+}
+
+
+static void uv_pipe_connection_init(uv_pipe_t* handle) {
+ uv_connection_init((uv_stream_t*) handle);
+ handle->read_req.data = handle;
+ handle->pipe.conn.eof_timer = NULL;
+ assert(!(handle->flags & UV_HANDLE_PIPESERVER));
+ if (pCancelSynchronousIo &&
+ handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ uv_mutex_init(&handle->pipe.conn.readfile_mutex);
+ handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE;
+ }
+}
+
+
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
+ HANDLE pipeHandle;
+
+ /*
+ * Assume that we have a duplex pipe first, so attempt to
+ * connect with GENERIC_READ | GENERIC_WRITE.
+ */
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+
+ /*
+ * If the pipe is not duplex CreateFileW fails with
+ * ERROR_ACCESS_DENIED. In that case try to connect
+ * as a read-only or write-only.
+ */
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE;
+ return pipeHandle;
+ }
+ }
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+static void close_pipe(uv_pipe_t* pipe) {
+ assert(pipe->u.fd == -1 || pipe->u.fd > 2);
+ if (pipe->u.fd == -1)
+ CloseHandle(pipe->handle);
+ else
+ close(pipe->u.fd);
+
+ pipe->u.fd = -1;
+ pipe->handle = INVALID_HANDLE_VALUE;
+}
+
+
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize) {
+ HANDLE pipeHandle;
+ int err;
+ char* ptr = (char*)handle;
+
+ for (;;) {
+ uv_unique_pipe_name(ptr, name, nameSize);
+
+ pipeHandle = CreateNamedPipeA(name,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ /* No name collisions. We're done. */
+ break;
+ }
+
+ err = GetLastError();
+ if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
+ goto error;
+ }
+
+ /* Pipe name collision. Increment the pointer and try again. */
+ ptr++;
+ }
+
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv_pipe_connection_init(handle);
+ handle->handle = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ return err;
+}
+
+
+static int uv_set_pipe_handle(uv_loop_t* loop,
+ uv_pipe_t* handle,
+ HANDLE pipeHandle,
+ int fd,
+ DWORD duplex_flags) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_MODE_INFORMATION mode_info;
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ DWORD current_mode = 0;
+ DWORD err = 0;
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
+ handle->handle != INVALID_HANDLE_VALUE)
+ return UV_EBUSY;
+
+ if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ /*
+ * SetNamedPipeHandleState can fail if the handle doesn't have either
+ * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES.
+ * But if the handle already has the desired wait and blocking modes
+ * we can continue.
+ */
+ if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
+ NULL, NULL, 0)) {
+ return -1;
+ } else if (current_mode & PIPE_NOWAIT) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return -1;
+ }
+ } else {
+ /* If this returns ERROR_INVALID_PARAMETER we probably opened
+ * something that is not a pipe. */
+ if (err == ERROR_INVALID_PARAMETER) {
+ SetLastError(WSAENOTSOCK);
+ }
+ return -1;
+ }
+ }
+
+ /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
+ nt_status = pNtQueryInformationFile(pipeHandle,
+ &io_status,
+ &mode_info,
+ sizeof(mode_info),
+ FileModeInformation);
+ if (nt_status != STATUS_SUCCESS) {
+ return -1;
+ }
+
+ if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
+ mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
+ /* Non-overlapped pipe. */
+ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
+ } else {
+ /* Overlapped pipe. Try to associate with IOCP. */
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ }
+ }
+
+ handle->handle = pipeHandle;
+ handle->u.fd = fd;
+ handle->flags |= duplex_flags;
+
+ return 0;
+}
+
+
+static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_shutdown_t* req;
+
+ req = (uv_shutdown_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ FlushFileBuffers(handle->handle);
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
+ int err;
+ DWORD result;
+ uv_shutdown_t* req;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_PIPE_LOCAL_INFORMATION pipe_info;
+ uv__ipc_queue_item_t* item;
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE;
+ uv_mutex_destroy(&handle->pipe.conn.readfile_mutex);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ req = handle->stream.conn.shutdown_req;
+
+ /* Clear the shutdown_req field so we don't go here again. */
+ handle->stream.conn.shutdown_req = NULL;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ /* Already closing. Cancel the shutdown. */
+ if (req->cb) {
+ req->cb(req, UV_ECANCELED);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ /* Try to avoid flushing the pipe buffer in the thread pool. */
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &pipe_info,
+ sizeof pipe_info,
+ FilePipeLocalInformation);
+
+ if (nt_status != STATUS_SUCCESS) {
+ /* Failure */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = pRtlNtStatusToDosError(nt_status);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
+ /* Short-circuit, no need to call FlushFileBuffers. */
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return;
+ }
+
+ /* Run FlushFileBuffers in the thread pool. */
+ result = QueueUserWorkItem(pipe_shutdown_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION);
+ if (result) {
+ return;
+
+ } else {
+ /* Failure. */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = GetLastError();
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ /* Free pending sockets */
+ while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) {
+ QUEUE* q;
+ SOCKET socket;
+
+ q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ /* Materialize socket and close it */
+ socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &item->socket_info_ex.socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ uv__free(item);
+
+ if (socket != INVALID_SOCKET)
+ closesocket(socket);
+ }
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ assert(handle->pipe.serv.accept_reqs);
+ uv__free(handle->pipe.serv.accept_reqs);
+ handle->pipe.serv.accept_reqs = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return;
+ handle->pipe.serv.pending_instances = count;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+}
+
+
+/* Creates a pipe server. */
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ uv_loop_t* loop = handle->loop;
+ int i, err, nameSize;
+ uv_pipe_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ return UV_EINVAL;
+ }
+
+ if (!name) {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ handle->pipe.serv.pending_instances = default_pending_pipe_instances;
+ }
+
+ handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
+ uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
+ if (!handle->pipe.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ req = &handle->pipe.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->data = handle;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ req->next_pending = NULL;
+ }
+
+ /* Convert name to UTF16. */
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /*
+ * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
+ * If this fails then there's already a pipe server for the given pipe name.
+ */
+ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
+ } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
+ err = WSAEACCES; /* Translates to UV_EACCES. */
+ }
+ goto error;
+ }
+
+ if (uv_set_pipe_handle(loop,
+ handle,
+ handle->pipe.serv.accept_reqs[0].pipeHandle,
+ -1,
+ 0)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ handle->pipe.serv.pending_accepts = NULL;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
+ handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_connect_t* req;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ req = (uv_connect_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
+ /* We wait for the pipe to become available with WaitNamedPipe. */
+ while (WaitNamedPipeW(handle->name, 30000)) {
+ /* The pipe is now available, try to connect. */
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ SwitchToThread();
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE &&
+ !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+ const char* name, uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err, nameSize;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Convert name to UTF16. */
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_PIPE_BUSY) {
+ /* Wait for the server to make a pipe instance available. */
+ if (!QueueUserWorkItem(&pipe_connect_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+
+ return;
+ }
+
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
+
+ if (uv_set_pipe_handle(loop,
+ (uv_pipe_t*) req->handle,
+ pipeHandle,
+ -1,
+ duplex_flags)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ SET_REQ_SUCCESS(req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, err);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+}
+
+
+void uv__pipe_pause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ /* Pause the ReadFile task briefly, to work
+ around the Windows kernel bug that causes
+ any access to a NamedPipe to deadlock if
+ any process has called ReadFile */
+ HANDLE h;
+ uv_mutex_lock(&handle->pipe.conn.readfile_mutex);
+ h = handle->pipe.conn.readfile_thread;
+ while (h) {
+ /* spinlock: we expect this to finish quickly,
+ or we are probably about to deadlock anyways
+ (in the kernel), so it doesn't matter */
+ pCancelSynchronousIo(h);
+ SwitchToThread(); /* yield thread control briefly */
+ h = handle->pipe.conn.readfile_thread;
+ }
+ }
+}
+
+
+void uv__pipe_unpause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_unlock(&handle->pipe.conn.readfile_mutex);
+ }
+}
+
+
+void uv__pipe_stop_read(uv_pipe_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ uv__pipe_pause_read((uv_pipe_t*)handle);
+ uv__pipe_unpause_read((uv_pipe_t*)handle);
+}
+
+
+/* Cleans up uv_pipe_t (server or connection) and all resources associated */
+/* with it. */
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
+ int i;
+ HANDLE pipeHandle;
+
+ uv__pipe_stop_read(handle);
+
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ handle->handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ eof_timer_destroy(handle);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION)
+ && handle->handle != INVALID_HANDLE_VALUE)
+ close_pipe(handle);
+}
+
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ uv_pipe_cleanup(loop, handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+}
+
+
+static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_pipe_accept_t* req, BOOL firstInstance) {
+ assert(handle->flags & UV_HANDLE_LISTENING);
+
+ if (!firstInstance) {
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+
+ req->pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (req->pipeHandle == INVALID_HANDLE_VALUE) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+ }
+
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+
+ if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
+ GetLastError() != ERROR_IO_PENDING) {
+ if (GetLastError() == ERROR_PIPE_CONNECTED) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ }
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
+ uv_loop_t* loop = server->loop;
+ uv_pipe_t* pipe_client;
+ uv_pipe_accept_t* req;
+ QUEUE* q;
+ uv__ipc_queue_item_t* item;
+ int err;
+
+ if (server->ipc) {
+ if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) {
+ /* No valid pending sockets. */
+ return WSAEWOULDBLOCK;
+ }
+
+ q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ server->pipe.conn.pending_ipc_info.queue_len--;
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ err = uv_tcp_import((uv_tcp_t*)client,
+ &item->socket_info_ex,
+ item->tcp_connection);
+ if (err != 0)
+ return err;
+
+ uv__free(item);
+
+ } else {
+ pipe_client = (uv_pipe_t*)client;
+
+ /* Find a connection instance that has been connected, but not yet */
+ /* accepted. */
+ req = server->pipe.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ /* Initialize the client handle and copy the pipeHandle to the client */
+ uv_pipe_connection_init(pipe_client);
+ pipe_client->handle = req->pipeHandle;
+ pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+
+ /* Prepare the req to pick up a new connection */
+ server->pipe.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, server, req, FALSE);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Starts listening for connections for the given pipe. */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int i;
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return WSAEINVAL;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->stream.serv.connection_cb = cb;
+
+ /* First pipe handle should have already been created in uv_pipe_bind */
+ assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
+ }
+
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_read_t* req = (uv_read_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->data;
+ uv_loop_t* loop = handle->loop;
+ HANDLE hThread = NULL;
+ DWORD err;
+ uv_mutex_t *m = &handle->pipe.conn.readfile_mutex;
+
+ assert(req != NULL);
+ assert(req->type == UV_READ);
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */
+ if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hThread,
+ 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ handle->pipe.conn.readfile_thread = hThread;
+ } else {
+ hThread = NULL;
+ }
+ uv_mutex_unlock(m);
+ }
+restart_readfile:
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
+ }
+ }
+ if (hThread) {
+ assert(hThread == handle->pipe.conn.readfile_thread);
+ /* mutex does not control clearing readfile_thread */
+ handle->pipe.conn.readfile_thread = NULL;
+ uv_mutex_lock(m);
+ /* only when we hold the mutex lock is it safe to
+ open or close the handle */
+ CloseHandle(hThread);
+ uv_mutex_unlock(m);
+ }
+
+ if (!result) {
+ SET_REQ_ERROR(req, err);
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_write_t* req = (uv_write_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->handle;
+ uv_loop_t* loop = handle->loop;
+
+ assert(req != NULL);
+ assert(req->type == UV_WRITE);
+ assert(handle->type == UV_NAMED_PIPE);
+ assert(req->write_buffer.base);
+
+ result = WriteFile(handle->handle,
+ req->write_buffer.base,
+ req->write_buffer.len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
+ uv_read_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_read_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
+ uv_read_t* req;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ } else {
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
+ }
+
+ /* Do 0-read */
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (!req->event_handle) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ if (req->wait_handle == INVALID_HANDLE_VALUE) {
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ }
+ }
+ }
+
+ /* Start the eof timer if there is one */
+ eof_timer_start(handle);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return;
+
+error:
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_read_start(uv_pipe_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_pipe_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
+ uv_write_t* req) {
+ req->next_req = NULL;
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req->next_req =
+ handle->pipe.conn.non_overlapped_writes_tail->next_req;
+ handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ } else {
+ req->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ }
+}
+
+
+static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
+ uv_write_t* req;
+
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
+
+ if (req == handle->pipe.conn.non_overlapped_writes_tail) {
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ } else {
+ handle->pipe.conn.non_overlapped_writes_tail->next_req =
+ req->next_req;
+ }
+
+ return req;
+ } else {
+ /* queue empty */
+ return NULL;
+ }
+}
+
+
+static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
+ uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
+ if (req) {
+ if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ uv_fatal_error(GetLastError(), "QueueUserWorkItem");
+ }
+ }
+}
+
+
+static int uv_pipe_write_impl(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int err;
+ int result;
+ uv_tcp_t* tcp_send_handle;
+ uv_write_t* ipc_header_req = NULL;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ if (nbufs != 1 && (nbufs != 0 || !send_handle)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ /* Only TCP handles are supported for sharing. */
+ if (send_handle && ((send_handle->type != UV_TCP) ||
+ (!(send_handle->flags & UV_HANDLE_BOUND) &&
+ !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ req->ipc_header = 0;
+ req->event_handle = NULL;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ if (handle->ipc) {
+ assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ ipc_frame.header.flags = 0;
+
+ /* Use the IPC framing protocol. */
+ if (send_handle) {
+ tcp_send_handle = (uv_tcp_t*)send_handle;
+
+ if (handle->pipe.conn.ipc_pid == 0) {
+ handle->pipe.conn.ipc_pid = uv_current_pid();
+ }
+
+ err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
+ &ipc_frame.socket_info_ex.socket_info);
+ if (err) {
+ return err;
+ }
+
+ ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
+
+ ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
+
+ if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
+ ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
+ }
+ }
+
+ if (nbufs == 1) {
+ ipc_frame.header.flags |= UV_IPC_RAW_DATA;
+ ipc_frame.header.raw_data_length = bufs[0].len;
+ }
+
+ /*
+ * Use the provided req if we're only doing a single write.
+ * If we're doing multiple writes, use ipc_header_write_req to do
+ * the first write, and then use the provided req for the second write.
+ */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ ipc_header_req = req;
+ } else {
+ /*
+ * Try to use the preallocated write req if it's available.
+ * Otherwise allocate a new one.
+ */
+ if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) {
+ ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req;
+ } else {
+ ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t));
+ if (!ipc_header_req) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) ipc_header_req);
+ ipc_header_req->type = UV_WRITE;
+ ipc_header_req->handle = (uv_stream_t*) handle;
+ ipc_header_req->cb = NULL;
+ ipc_header_req->ipc_header = 1;
+ }
+
+ /* Write the header or the whole frame. */
+ memset(&ipc_header_req->u.io.overlapped, 0,
+ sizeof(ipc_header_req->u.io.overlapped));
+
+ /* Using overlapped IO, but wait for completion before returning.
+ This write is blocking because ipc_frame is on stack. */
+ ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!ipc_header_req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ &ipc_frame,
+ ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
+ sizeof(ipc_frame) : sizeof(ipc_frame.header),
+ NULL,
+ &ipc_header_req->u.io.overlapped);
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (!result) {
+ /* Request not completed immediately. Wait for it.*/
+ if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+ }
+ ipc_header_req->u.io.queued_bytes = 0;
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ ipc_header_req->u.io.overlapped.hEvent = NULL;
+
+ REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ /* If we don't have any raw data to write - we're done. */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ return 0;
+ }
+ }
+
+ if ((handle->flags &
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) ==
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) {
+ DWORD bytes;
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ err = GetLastError();
+ return err;
+ } else {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ req->write_buffer = bufs[0];
+ uv_insert_non_overlapped_write_req(handle, req);
+ if (handle->stream.conn.write_reqs_pending == 0) {
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
+ /* Using overlapped IO, but wait for completion before returning */
+ req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return uv_translate_sys_error(err);
+ }
+ }
+ CloseHandle(req->u.io.overlapped.hEvent);
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ return 0;
+ } else {
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ return GetLastError();
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ return GetLastError();
+ }
+ }
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ return 0;
+}
+
+
+int uv_pipe_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+int uv_pipe_write2(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ if (!handle->ipc) {
+ return WSAEINVAL;
+ }
+
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb);
+}
+
+
+static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ handle->flags &= ~UV_HANDLE_READABLE;
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
+}
+
+
+static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
+}
+
+
+static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ int error, uv_buf_t buf) {
+ if (error == ERROR_BROKEN_PIPE) {
+ uv_pipe_read_eof(loop, handle, buf);
+ } else {
+ uv_pipe_read_error(loop, handle, error, buf);
+ }
+}
+
+
+void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
+ uv__ipc_socket_info_ex* info,
+ int tcp_connection) {
+ uv__ipc_queue_item_t* item;
+
+ item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item));
+ if (item == NULL)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+
+ memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
+ item->tcp_connection = tcp_connection;
+ QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member);
+ handle->pipe.conn.pending_ipc_info.queue_len++;
+}
+
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, avail;
+ uv_buf_t buf;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ eof_timer_stop(handle);
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the 0-read. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_pipe_read_error_or_eof(loop,
+ handle,
+ GET_REQ_ERROR(req),
+ uv_null_buf_);
+ }
+ } else {
+ /* Do non-blocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ if (!PeekNamedPipe(handle->handle,
+ NULL,
+ 0,
+ NULL,
+ &avail,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
+ break;
+ }
+
+ if (avail == 0) {
+ /* There is nothing to read after all. */
+ break;
+ }
+
+ if (handle->ipc) {
+ /* Use the IPC framing protocol to read the incoming data. */
+ if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) {
+ /* We're reading a new frame. First, read the header. */
+ assert(avail >= sizeof(ipc_frame.header));
+
+ if (!ReadFile(handle->handle,
+ &ipc_frame.header,
+ sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame.header));
+ assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA |
+ UV_IPC_TCP_CONNECTION));
+
+ if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
+ assert(avail - sizeof(ipc_frame.header) >=
+ sizeof(ipc_frame.socket_info_ex));
+
+ /* Read the TCP socket info. */
+ if (!ReadFile(handle->handle,
+ &ipc_frame.socket_info_ex,
+ sizeof(ipc_frame) - sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
+
+ /* Store the pending socket info. */
+ uv__pipe_insert_pending_socket(
+ handle,
+ &ipc_frame.socket_info_ex,
+ ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
+ }
+
+ if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ ipc_frame.header.raw_data_length;
+ continue;
+ }
+ } else {
+ avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes);
+ }
+ }
+
+ handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ if (ReadFile(handle->handle,
+ buf.base,
+ min(buf.len, avail),
+ &bytes,
+ NULL)) {
+ /* Successful read */
+ if (handle->ipc) {
+ assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes);
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes;
+ }
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+
+ /* Read again only if bytes == buf.len */
+ if (bytes <= buf.len) {
+ break;
+ }
+ } else {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
+ break;
+ }
+ }
+
+ /* Post another 0-read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_pipe_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->ipc_header) {
+ if (req == &handle->pipe.conn.ipc_header_write_req) {
+ req->type = UV_UNKNOWN_REQ;
+ } else {
+ uv__free(req);
+ }
+ } else {
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
+ handle->pipe.conn.non_overlapped_writes_tail) {
+ assert(handle->stream.conn.write_reqs_pending > 0);
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req) {
+ uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (REQ_SUCCESS(req)) {
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+ req->next_pending = handle->pipe.serv.pending_accepts;
+ handle->pipe.serv.pending_accepts = req;
+
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ if (req->pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, handle, req, FALSE);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ uv_pipe_connection_init(handle);
+ } else {
+ err = GET_REQ_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req) {
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_READABLE) {
+ /* Initialize and optionally start the eof timer. Only do this if the */
+ /* pipe is readable and we haven't seen EOF come in ourselves. */
+ eof_timer_init(handle);
+
+ /* If reading start the timer right now. */
+ /* Otherwise uv_pipe_queue_read will start it. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ eof_timer_start(handle);
+ }
+
+ } else {
+ /* This pipe is not readable. We can just close it to let the other end */
+ /* know that we're done writing. */
+ close_pipe(handle);
+ }
+
+ if (req->cb) {
+ req->cb(req, 0);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static void eof_timer_init(uv_pipe_t* pipe) {
+ int r;
+
+ assert(pipe->pipe.conn.eof_timer == NULL);
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
+
+ r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
+ assert(r == 0); /* timers can't fail */
+ pipe->pipe.conn.eof_timer->data = pipe;
+ uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
+}
+
+
+static void eof_timer_start(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
+ }
+}
+
+
+static void eof_timer_stop(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_stop(pipe->pipe.conn.eof_timer);
+ }
+}
+
+
+static void eof_timer_cb(uv_timer_t* timer) {
+ uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
+ uv_loop_t* loop = timer->loop;
+
+ assert(pipe->type == UV_NAMED_PIPE);
+
+ /* This should always be true, since we start the timer only */
+ /* in uv_pipe_queue_read after successfully calling ReadFile, */
+ /* or in uv_process_pipe_shutdown_req if a read is pending, */
+ /* and we always immediately stop the timer in */
+ /* uv_process_pipe_read_req. */
+ assert(pipe->flags & UV_HANDLE_READ_PENDING);
+
+ /* If there are many packets coming off the iocp then the timer callback */
+ /* may be called before the read request is coming off the queue. */
+ /* Therefore we check here if the read request has completed but will */
+ /* be processed later. */
+ if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
+ HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
+ return;
+ }
+
+ /* Force both ends off the pipe. */
+ close_pipe(pipe);
+
+ /* Stop reading, so the pending read that is going to fail will */
+ /* not be reported to the user. */
+ uv_read_stop((uv_stream_t*) pipe);
+
+ /* Report the eof and update flags. This will get reported even if the */
+ /* user stopped reading in the meantime. TODO: is that okay? */
+ uv_pipe_read_eof(loop, pipe, uv_null_buf_);
+}
+
+
+static void eof_timer_destroy(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer) {
+ uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
+ pipe->pipe.conn.eof_timer = NULL;
+ }
+}
+
+
+static void eof_timer_close_cb(uv_handle_t* handle) {
+ assert(handle->type == UV_TIMER);
+ uv__free(handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
+ HANDLE os_handle = uv__get_osfhandle(file);
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_ACCESS_INFORMATION access;
+ DWORD duplex_flags = 0;
+
+ if (os_handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (file <= 2) {
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ os_handle,
+ INVALID_HANDLE_VALUE,
+ &os_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ file = -1;
+ }
+
+ /* Determine what kind of permissions we have on this handle.
+ * Cygwin opens the pipe in message mode, but we can support it,
+ * just query the access flags and set the stream flags accordingly.
+ */
+ nt_status = pNtQueryInformationFile(os_handle,
+ &io_status,
+ &access,
+ sizeof(access),
+ FileAccessInformation);
+ if (nt_status != STATUS_SUCCESS)
+ return UV_EINVAL;
+
+ if (pipe->ipc) {
+ if (!(access.AccessFlags & FILE_WRITE_DATA) ||
+ !(access.AccessFlags & FILE_READ_DATA)) {
+ return UV_EINVAL;
+ }
+ }
+
+ if (access.AccessFlags & FILE_WRITE_DATA)
+ duplex_flags |= UV_HANDLE_WRITABLE;
+ if (access.AccessFlags & FILE_READ_DATA)
+ duplex_flags |= UV_HANDLE_READABLE;
+
+ if (os_handle == INVALID_HANDLE_VALUE ||
+ uv_set_pipe_handle(pipe->loop,
+ pipe,
+ os_handle,
+ file,
+ duplex_flags) == -1) {
+ return UV_EINVAL;
+ }
+
+ uv_pipe_connection_init(pipe);
+
+ if (pipe->ipc) {
+ assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ pipe->pipe.conn.ipc_pid = uv_parent_pid();
+ assert(pipe->pipe.conn.ipc_pid != -1);
+ }
+ return 0;
+}
+
+
+static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_NAME_INFORMATION tmp_name_info;
+ FILE_NAME_INFORMATION* name_info;
+ WCHAR* name_buf;
+ unsigned int addrlen;
+ unsigned int name_size;
+ unsigned int name_len;
+ int err;
+
+ name_info = NULL;
+
+ if (handle->handle == INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &tmp_name_info,
+ sizeof tmp_name_info,
+ FileNameInformation);
+ if (nt_status == STATUS_BUFFER_OVERFLOW) {
+ name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
+ name_info = uv__malloc(name_size);
+ if (!name_info) {
+ *size = 0;
+ err = UV_ENOMEM;
+ goto cleanup;
+ }
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ name_info,
+ name_size,
+ FileNameInformation);
+ }
+
+ if (nt_status != STATUS_SUCCESS) {
+ *size = 0;
+ err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
+ goto error;
+ }
+
+ if (!name_info) {
+ /* the struct on stack was used */
+ name_buf = tmp_name_info.FileName;
+ name_len = tmp_name_info.FileNameLength;
+ } else {
+ name_buf = name_info->FileName;
+ name_len = name_info->FileNameLength;
+ }
+
+ if (name_len == 0) {
+ *size = 0;
+ err = 0;
+ goto error;
+ }
+
+ name_len /= sizeof(WCHAR);
+
+ /* check how much space we need */
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ } else if (pipe_prefix_len + addrlen > *size) {
+ /* "\\\\.\\pipe" + name */
+ *size = pipe_prefix_len + addrlen;
+ err = UV_ENOBUFS;
+ goto error;
+ }
+
+ memcpy(buffer, pipe_prefix, pipe_prefix_len);
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ buffer+pipe_prefix_len,
+ *size-pipe_prefix_len,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ }
+
+ addrlen += pipe_prefix_len;
+ *size = addrlen;
+
+ err = 0;
+ goto cleanup;
+
+error:
+ uv__free(name_info);
+
+cleanup:
+ uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */
+ return err;
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return 0;
+ return handle->pipe.conn.pending_ipc_info.queue_len;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return uv__pipe_getname(handle, buffer, size);
+
+ if (handle->flags & UV_HANDLE_CONNECTION ||
+ handle->handle != INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return 0;
+ }
+
+ return UV_EBADF;
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ /* emulate unix behaviour */
+ if (handle->flags & UV_HANDLE_BOUND)
+ return UV_ENOTCONN;
+
+ if (handle->handle != INVALID_HANDLE_VALUE)
+ return uv__pipe_getname(handle, buffer, size);
+
+ return UV_EBADF;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+ if (handle->pipe.conn.pending_ipc_info.queue_len == 0)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return UV_TCP;
+}
diff --git a/3rdparty/libuv/src/win/poll.c b/3rdparty/libuv/src/win/poll.c
new file mode 100644
index 00000000000..ce861d6ffc4
--- /dev/null
+++ b/3rdparty/libuv/src/win/poll.c
@@ -0,0 +1,635 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
+ {0xe70f1aa0, 0xab8b, 0x11cf,
+ {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
+ {0xf9eab0c0, 0x26d4, 0x11d0,
+ {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
+ {0x9fc48064, 0x7298, 0x43e4,
+ {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+};
+
+typedef struct uv_single_fd_set_s {
+ unsigned int fd_count;
+ SOCKET fd_array[1];
+} uv_single_fd_set_t;
+
+
+static OVERLAPPED overlapped_dummy_;
+static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
+
+static AFD_POLL_INFO afd_poll_info_dummy_;
+
+
+static void uv__init_overlapped_dummy(void) {
+ HANDLE event;
+
+ event = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (event == NULL)
+ uv_fatal_error(GetLastError(), "CreateEvent");
+
+ memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
+ overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
+}
+
+
+static OVERLAPPED* uv__get_overlapped_dummy() {
+ uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
+ return &overlapped_dummy_;
+}
+
+
+static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
+ return &afd_poll_info_dummy_;
+}
+
+
+static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+ AFD_POLL_INFO* afd_poll_info;
+ DWORD result;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Setting Exclusive to TRUE makes the other poll request return if there */
+ /* is any. */
+ afd_poll_info->Exclusive = TRUE;
+ afd_poll_info->NumberOfHandles = 1;
+ afd_poll_info->Timeout.QuadPart = INT64_MAX;
+ afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info->Handles[0].Status = 0;
+ afd_poll_info->Handles[0].Events = 0;
+
+ if (handle->events & UV_READABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
+ }
+ if (handle->events & UV_WRITABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
+ }
+
+ memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
+
+ result = uv_msafd_poll((SOCKET) handle->peer_socket,
+ afd_poll_info,
+ afd_poll_info,
+ &req->u.io.overlapped);
+ if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ AFD_POLL_INFO afd_poll_info;
+ DWORD result;
+
+ afd_poll_info.Exclusive = TRUE;
+ afd_poll_info.NumberOfHandles = 1;
+ afd_poll_info.Timeout.QuadPart = INT64_MAX;
+ afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info.Handles[0].Status = 0;
+ afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
+
+ result = uv_msafd_poll(handle->socket,
+ &afd_poll_info,
+ uv__get_afd_poll_info_dummy(),
+ uv__get_overlapped_dummy());
+
+ if (result == SOCKET_ERROR) {
+ DWORD error = WSAGetLastError();
+ if (error != WSA_IO_PENDING)
+ return error;
+ }
+
+ return 0;
+}
+
+
+static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ AFD_POLL_INFO* afd_poll_info;
+
+ if (req == &handle->poll_req_1) {
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Report an error unless the select was just interrupted. */
+ if (!REQ_SUCCESS(req)) {
+ DWORD error = GET_REQ_SOCK_ERROR(req);
+ if (error != WSAEINTR && handle->events != 0) {
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(error), 0);
+ }
+
+ } else if (afd_poll_info->NumberOfHandles >= 1) {
+ unsigned char events = 0;
+
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
+ events |= UV_READABLE;
+ }
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
+ AFD_POLL_CONNECT_FAIL)) != 0) {
+ events |= UV_WRITABLE;
+ }
+
+ events &= handle->events & ~mask_events;
+
+ if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
+ /* Stop polling. */
+ handle->events = 0;
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
+ }
+
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return 0;
+ } else {
+ /* Cancel outstanding poll requests by executing another, unique poll */
+ /* request that forces the outstanding ones to return. */
+ return uv__fast_poll_cancel_poll_req(loop, handle);
+ }
+}
+
+
+static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ SOCKET sock = 0;
+
+ sock = WSASocketW(protocol_info->iAddressFamily,
+ protocol_info->iSocketType,
+ protocol_info->iProtocol,
+ protocol_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ if (sock == INVALID_SOCKET) {
+ return INVALID_SOCKET;
+ }
+
+ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+ goto error;
+ };
+
+ if (CreateIoCompletionPort((HANDLE) sock,
+ iocp,
+ (ULONG_PTR) sock,
+ 0) == NULL) {
+ goto error;
+ }
+
+ return sock;
+
+ error:
+ closesocket(sock);
+ return INVALID_SOCKET;
+}
+
+
+static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ int index, i;
+ SOCKET peer_socket;
+
+ index = -1;
+ for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+ if (memcmp((void*) &protocol_info->ProviderId,
+ (void*) &uv_msafd_provider_ids[i],
+ sizeof protocol_info->ProviderId) == 0) {
+ index = i;
+ }
+ }
+
+ /* Check if the protocol uses an msafd socket. */
+ if (index < 0) {
+ return INVALID_SOCKET;
+ }
+
+ /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+ /* try again if the peer socket creation failed earlier for the same */
+ /* protocol. */
+ peer_socket = loop->poll_peer_sockets[index];
+ if (peer_socket == 0) {
+ peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
+ loop->poll_peer_sockets[index] = peer_socket;
+ }
+
+ return peer_socket;
+}
+
+
+static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
+ uv_req_t* req = (uv_req_t*) arg;
+ uv_poll_t* handle = (uv_poll_t*) req->data;
+ unsigned char reported_events;
+ int r;
+ uv_single_fd_set_t rfds, wfds, efds;
+ struct timeval timeout;
+
+ assert(handle->type == UV_POLL);
+ assert(req->type == UV_POLL_REQ);
+
+ if (handle->events & UV_READABLE) {
+ rfds.fd_count = 1;
+ rfds.fd_array[0] = handle->socket;
+ } else {
+ rfds.fd_count = 0;
+ }
+
+ if (handle->events & UV_WRITABLE) {
+ wfds.fd_count = 1;
+ wfds.fd_array[0] = handle->socket;
+ efds.fd_count = 1;
+ efds.fd_array[0] = handle->socket;
+ } else {
+ wfds.fd_count = 0;
+ efds.fd_count = 0;
+ }
+
+ /* Make the select() time out after 3 minutes. If select() hangs because */
+ /* the user closed the socket, we will at least not hang indefinitely. */
+ timeout.tv_sec = 3 * 60;
+ timeout.tv_usec = 0;
+
+ r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
+ if (r == SOCKET_ERROR) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+ return 0;
+ }
+
+ reported_events = 0;
+
+ if (r > 0) {
+ if (rfds.fd_count > 0) {
+ assert(rfds.fd_count == 1);
+ assert(rfds.fd_array[0] == handle->socket);
+ reported_events |= UV_READABLE;
+ }
+
+ if (wfds.fd_count > 0) {
+ assert(wfds.fd_count == 1);
+ assert(wfds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ } else if (efds.fd_count > 0) {
+ assert(efds.fd_count == 1);
+ assert(efds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ }
+ }
+
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+
+ return 0;
+}
+
+
+static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending, reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+
+static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ int err;
+
+ if (req == &handle->poll_req_1) {
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* Error. */
+ if (handle->events != 0) {
+ err = GET_REQ_ERROR(req);
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(err), 0);
+ }
+ } else {
+ /* Got some events. */
+ int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events &
+ ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ return 0;
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int len;
+ SOCKET peer_socket, base_socket;
+ DWORD bytes;
+ DWORD yes = 1;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ /* Try to obtain a base handle for the socket. This increases this chances */
+ /* that we find an AFD handle and are able to use the fast poll mechanism. */
+ /* This will always fail on windows XP/2k3, since they don't support the */
+ /* SIO_BASE_HANDLE ioctl. */
+#ifndef NDEBUG
+ base_socket = INVALID_SOCKET;
+#endif
+
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &base_socket,
+ sizeof base_socket,
+ &bytes,
+ NULL,
+ NULL) == 0) {
+ assert(base_socket != 0 && base_socket != INVALID_SOCKET);
+ socket = base_socket;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ handle->socket = socket;
+ handle->events = 0;
+
+ /* Obtain protocol information about the socket. */
+ len = sizeof protocol_info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &len) != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ /* Get the peer socket that is needed to enable fast poll. If the returned */
+ /* value is NULL, the protocol is not implemented by MSAFD and we'll have */
+ /* to use slow mode. */
+ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
+
+ if (peer_socket != INVALID_SOCKET) {
+ /* Initialize fast poll specific fields. */
+ handle->peer_socket = peer_socket;
+ } else {
+ /* Initialize slow poll specific fields. */
+ handle->flags |= UV_HANDLE_POLL_SLOW;
+ }
+
+ /* Initialize 2 poll reqs. */
+ handle->submitted_events_1 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
+ handle->poll_req_1.type = UV_POLL_REQ;
+ handle->poll_req_1.data = handle;
+
+ handle->submitted_events_2 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
+ handle->poll_req_2.type = UV_POLL_REQ;
+ handle->poll_req_2.data = handle;
+
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, events);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, events);
+ }
+
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ handle->poll_cb = cb;
+
+ return 0;
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, 0);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, 0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ uv__fast_poll_process_poll_req(loop, handle, req);
+ } else {
+ uv__slow_poll_process_poll_req(loop, handle, req);
+ }
+}
+
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ return uv__fast_poll_close(loop, handle);
+ } else {
+ return uv__slow_poll_close(loop, handle);
+ }
+}
+
+
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->submitted_events_1 == 0);
+ assert(handle->submitted_events_2 == 0);
+
+ uv__handle_close(handle);
+}
diff --git a/3rdparty/libuv/src/win/process-stdio.c b/3rdparty/libuv/src/win/process-stdio.c
new file mode 100644
index 00000000000..e3c06f57dea
--- /dev/null
+++ b/3rdparty/libuv/src/win/process-stdio.c
@@ -0,0 +1,510 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+/*
+ * The `child_stdio_buffer` buffer has the following layout:
+ * int number_of_fds
+ * unsigned char crt_flags[number_of_fds]
+ * HANDLE os_handle[number_of_fds]
+ */
+#define CHILD_STDIO_SIZE(count) \
+ (sizeof(int) + \
+ sizeof(unsigned char) * (count) + \
+ sizeof(uintptr_t) * (count))
+
+#define CHILD_STDIO_COUNT(buffer) \
+ *((unsigned int*) (buffer))
+
+#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
+ *((unsigned char*) (buffer) + sizeof(int) + fd)
+
+#define CHILD_STDIO_HANDLE(buffer, fd) \
+ *((HANDLE*) ((unsigned char*) (buffer) + \
+ sizeof(int) + \
+ sizeof(unsigned char) * \
+ CHILD_STDIO_COUNT((buffer)) + \
+ sizeof(HANDLE) * (fd)))
+
+
+/* CRT file descriptor mode flags */
+#define FOPEN 0x01
+#define FEOFLAG 0x02
+#define FCRLF 0x04
+#define FPIPE 0x08
+#define FNOINHERIT 0x10
+#define FAPPEND 0x20
+#define FDEV 0x40
+#define FTEXT 0x80
+
+
+/*
+ * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
+ * the parent process. Don't check for errors - the stdio handles may not be
+ * valid, or may be closed already. There is no guarantee that this function
+ * does a perfect job.
+ */
+void uv_disable_stdio_inheritance(void) {
+ HANDLE handle;
+ STARTUPINFOW si;
+
+ /* Make the windows stdio handles non-inheritable. */
+ handle = GetStdHandle(STD_INPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_ERROR_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ /* Make inherited CRT FDs non-inheritable. */
+ GetStartupInfoW(&si);
+ if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
+ uv__stdio_noinherit(si.lpReserved2);
+}
+
+
+static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access = 0;
+ DWORD client_access = 0;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+ int err;
+
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound access too, otherwise CreateNamedPipe() */
+ /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
+ /* probe the state of the write buffer when we're trying to shutdown */
+ /* the pipe. */
+ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_access |= PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ }
+
+ /* Create server pipe handle. */
+ err = uv_stdio_pipe_server(loop,
+ server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name));
+ if (err)
+ goto error;
+
+ /* Create child pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ child_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (child_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r = GetNamedPipeHandleState(child_pipe,
+ &mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ assert(r == TRUE);
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have */
+ /* both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_READABLE;
+
+ *child_pipe_ptr = child_pipe;
+ return 0;
+
+ error:
+ if (server_pipe->handle != INVALID_HANDLE_VALUE) {
+ uv_pipe_cleanup(loop, server_pipe);
+ }
+
+ if (child_pipe != INVALID_HANDLE_VALUE) {
+ CloseHandle(child_pipe);
+ }
+
+ return err;
+}
+
+
+static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
+ HANDLE current_process;
+
+
+ /* _get_osfhandle will sometimes return -2 in case of an error. This seems */
+ /* to happen when fd <= 2 and the process' corresponding stdio handle is */
+ /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
+ /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
+ /* use the duplicate. Therefore we filter out known-invalid handles here. */
+ if (handle == INVALID_HANDLE_VALUE ||
+ handle == NULL ||
+ handle == (HANDLE) -2) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ current_process = GetCurrentProcess();
+
+ if (!DuplicateHandle(current_process,
+ handle,
+ current_process,
+ dup,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS)) {
+ *dup = INVALID_HANDLE_VALUE;
+ return GetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
+ HANDLE handle;
+
+ if (fd == -1) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(fd);
+ return uv__duplicate_handle(loop, handle, dup);
+}
+
+
+int uv__create_nul_handle(HANDLE* handle_ptr,
+ DWORD access) {
+ HANDLE handle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ handle = CreateFileW(L"NUL",
+ access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ return GetLastError();
+ }
+
+ *handle_ptr = handle;
+ return 0;
+}
+
+
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr) {
+ BYTE* buffer;
+ int count, i;
+ int err;
+
+ count = options->stdio_count;
+
+ if (count < 0 || count > 255) {
+ /* Only support FDs 0-255 */
+ return ERROR_NOT_SUPPORTED;
+ } else if (count < 3) {
+ /* There should always be at least 3 stdio handles. */
+ count = 3;
+ }
+
+ /* Allocate the child stdio buffer */
+ buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
+ if (buffer == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
+ /* clean up on failure. */
+ CHILD_STDIO_COUNT(buffer) = count;
+ for (i = 0; i < count; i++) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ }
+
+ for (i = 0; i < count; i++) {
+ uv_stdio_container_t fdopt;
+ if (i < options->stdio_count) {
+ fdopt = options->stdio[i];
+ } else {
+ fdopt.flags = UV_IGNORE;
+ }
+
+ switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
+ UV_INHERIT_STREAM)) {
+ case UV_IGNORE:
+ /* Starting a process with no stdin/stout/stderr can confuse it. */
+ /* So no matter what the user specified, we make sure the first */
+ /* three FDs are always open in their typical modes, e.g. stdin */
+ /* be readable and stdout/err should be writable. For FDs > 2, don't */
+ /* do anything - all handles in the stdio buffer are initialized with */
+ /* INVALID_HANDLE_VALUE, which should be okay. */
+ if (i <= 2) {
+ DWORD access = (i == 0) ? FILE_GENERIC_READ :
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+
+ err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
+ access);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ }
+ break;
+
+ case UV_CREATE_PIPE: {
+ /* Create a pair of two connected pipe ends; one end is turned into */
+ /* an uv_pipe_t for use by the parent. The other one is given to */
+ /* the child. */
+ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+
+ /* Create a new, connected pipe pair. stdio[i].stream should point */
+ /* to an uninitialized, but not connected pipe handle. */
+ assert(fdopt.data.stream->type == UV_NAMED_PIPE);
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
+
+ err = uv__create_stdio_pipe_pair(loop,
+ parent_pipe,
+ &child_pipe,
+ fdopt.flags);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+ }
+
+ case UV_INHERIT_FD: {
+ /* Inherit a raw FD. */
+ HANDLE child_handle;
+
+ /* Make an inheritable duplicate of the handle. */
+ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
+ if (err) {
+ /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
+ /* error. */
+ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ break;
+ }
+ goto error;
+ }
+
+ /* Figure out what the type is. */
+ switch (GetFileType(child_handle)) {
+ case FILE_TYPE_DISK:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
+ break;
+
+ case FILE_TYPE_PIPE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_REMOTE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ case FILE_TYPE_UNKNOWN:
+ if (GetLastError() != 0) {
+ err = GetLastError();
+ CloseHandle(child_handle);
+ goto error;
+ }
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ default:
+ assert(0);
+ return -1;
+ }
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ break;
+ }
+
+ case UV_INHERIT_STREAM: {
+ /* Use an existing stream as the stdio handle for the child. */
+ HANDLE stream_handle, child_handle;
+ unsigned char crt_flags;
+ uv_stream_t* stream = fdopt.data.stream;
+
+ /* Leech the handle out of the stream. */
+ if (stream->type == UV_TTY) {
+ stream_handle = ((uv_tty_t*) stream)->handle;
+ crt_flags = FOPEN | FDEV;
+ } else if (stream->type == UV_NAMED_PIPE &&
+ stream->flags & UV_HANDLE_CONNECTION) {
+ stream_handle = ((uv_pipe_t*) stream)->handle;
+ crt_flags = FOPEN | FPIPE;
+ } else {
+ stream_handle = INVALID_HANDLE_VALUE;
+ crt_flags = 0;
+ }
+
+ if (stream_handle == NULL ||
+ stream_handle == INVALID_HANDLE_VALUE) {
+ /* The handle is already closed, or not yet created, or the */
+ /* stream type is not supported. */
+ err = ERROR_NOT_SUPPORTED;
+ goto error;
+ }
+
+ /* Make an inheritable copy of the handle. */
+ err = uv__duplicate_handle(loop, stream_handle, &child_handle);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
+ break;
+ }
+
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+
+ *buffer_ptr = buffer;
+ return 0;
+
+ error:
+ uv__stdio_destroy(buffer);
+ return err;
+}
+
+
+void uv__stdio_destroy(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+ }
+
+ uv__free(buffer);
+}
+
+
+void uv__stdio_noinherit(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+ }
+ }
+}
+
+
+int uv__stdio_verify(BYTE* buffer, WORD size) {
+ unsigned int count;
+
+ /* Check the buffer pointer. */
+ if (buffer == NULL)
+ return 0;
+
+ /* Verify that the buffer is at least big enough to hold the count. */
+ if (size < CHILD_STDIO_SIZE(0))
+ return 0;
+
+ /* Verify if the count is within range. */
+ count = CHILD_STDIO_COUNT(buffer);
+ if (count > 256)
+ return 0;
+
+ /* Verify that the buffer size is big enough to hold info for N FDs. */
+ if (size < CHILD_STDIO_SIZE(count))
+ return 0;
+
+ return 1;
+}
+
+
+WORD uv__stdio_size(BYTE* buffer) {
+ return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
+}
+
+
+HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
+ return CHILD_STDIO_HANDLE(buffer, fd);
+}
diff --git a/3rdparty/libuv/src/win/process.c b/3rdparty/libuv/src/win/process.c
new file mode 100644
index 00000000000..855c3740816
--- /dev/null
+++ b/3rdparty/libuv/src/win/process.c
@@ -0,0 +1,1247 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <limits.h>
+#include <wchar.h>
+#include <malloc.h> /* alloca */
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+#define SIGKILL 9
+
+
+typedef struct env_var {
+ const WCHAR* const wide;
+ const WCHAR* const wide_eq;
+ const size_t len; /* including null or '=' */
+} env_var_t;
+
+#define E_V(str) { L##str, L##str L"=", sizeof(str) }
+
+static const env_var_t required_vars[] = { /* keep me sorted */
+ E_V("HOMEDRIVE"),
+ E_V("HOMEPATH"),
+ E_V("LOGONSERVER"),
+ E_V("PATH"),
+ E_V("SYSTEMDRIVE"),
+ E_V("SYSTEMROOT"),
+ E_V("TEMP"),
+ E_V("USERDOMAIN"),
+ E_V("USERNAME"),
+ E_V("USERPROFILE"),
+ E_V("WINDIR"),
+};
+static size_t n_required_vars = ARRAY_SIZE(required_vars);
+
+
+static HANDLE uv_global_job_handle_;
+static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
+
+
+static void uv__init_global_job_handle(void) {
+ /* Create a job object and set it up to kill all contained processes when
+ * it's closed. Since this handle is made non-inheritable and we're not
+ * giving it to anyone, we're the only process holding a reference to it.
+ * That means that if this process exits it is closed and all the processes
+ * it contains are killed. All processes created with uv_spawn that are not
+ * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
+ *
+ * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
+ * processes that we explicitly add are affected, and *their* subprocesses
+ * are not. This ensures that our child processes are not limited in their
+ * ability to use job control on Windows versions that don't deal with
+ * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
+ * processes created detached processes without explicitly breaking away
+ * from job control (which uv_spawn doesn't, either).
+ */
+ SECURITY_ATTRIBUTES attr;
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+
+ memset(&attr, 0, sizeof attr);
+ attr.bInheritHandle = FALSE;
+
+ memset(&info, 0, sizeof info);
+ info.BasicLimitInformation.LimitFlags =
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
+ JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+ uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
+ if (uv_global_job_handle_ == NULL)
+ uv_fatal_error(GetLastError(), "CreateJobObjectW");
+
+ if (!SetInformationJobObject(uv_global_job_handle_,
+ JobObjectExtendedLimitInformation,
+ &info,
+ sizeof info))
+ uv_fatal_error(GetLastError(), "SetInformationJobObject");
+}
+
+
+static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+ int ws_len, r;
+ WCHAR* ws;
+
+ ws_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ NULL,
+ 0);
+ if (ws_len <= 0) {
+ return GetLastError();
+ }
+
+ ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
+ if (ws == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ ws,
+ ws_len);
+ assert(r == ws_len);
+
+ *ws_ptr = ws;
+ return 0;
+}
+
+
+static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
+ handle->exit_cb = NULL;
+ handle->pid = 0;
+ handle->exit_signal = 0;
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ handle->process_handle = INVALID_HANDLE_VALUE;
+ handle->child_stdio_buffer = NULL;
+ handle->exit_cb_pending = 0;
+
+ uv_req_init(loop, (uv_req_t*)&handle->exit_req);
+ handle->exit_req.type = UV_PROCESS_EXIT;
+ handle->exit_req.data = handle;
+}
+
+
+/*
+ * Path search functions
+ */
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* search_path_join_test(const WCHAR* dir,
+ size_t dir_len,
+ const WCHAR* name,
+ size_t name_len,
+ const WCHAR* ext,
+ size_t ext_len,
+ const WCHAR* cwd,
+ size_t cwd_len) {
+ WCHAR *result, *result_pos;
+ DWORD attrs;
+ if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
+ /* It's a UNC path so ignore cwd */
+ cwd_len = 0;
+ } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
+ /* It's a full path without drive letter, use cwd's drive letter only */
+ cwd_len = 2;
+ } else if (dir_len >= 2 && dir[1] == L':' &&
+ (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
+ /* It's a relative path with drive letter (ext.g. D:../some/file)
+ * Replace drive letter in dir by full cwd if it points to the same drive,
+ * otherwise use the dir only.
+ */
+ if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
+ cwd_len = 0;
+ } else {
+ dir += 2;
+ dir_len -= 2;
+ }
+ } else if (dir_len > 2 && dir[1] == L':') {
+ /* It's an absolute path with drive letter
+ * Don't use the cwd at all
+ */
+ cwd_len = 0;
+ }
+
+ /* Allocate buffer for output */
+ result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
+ (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
+
+ /* Copy cwd */
+ wcsncpy(result_pos, cwd, cwd_len);
+ result_pos += cwd_len;
+
+ /* Add a path separator if cwd didn't end with one */
+ if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy dir */
+ wcsncpy(result_pos, dir, dir_len);
+ result_pos += dir_len;
+
+ /* Add a separator if the dir didn't end with one */
+ if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy filename */
+ wcsncpy(result_pos, name, name_len);
+ result_pos += name_len;
+
+ if (ext_len) {
+ /* Add a dot if the filename didn't end with one */
+ if (name_len && result_pos[-1] != '.') {
+ result_pos[0] = L'.';
+ result_pos++;
+ }
+
+ /* Copy extension */
+ wcsncpy(result_pos, ext, ext_len);
+ result_pos += ext_len;
+ }
+
+ /* Null terminator */
+ result_pos[0] = L'\0';
+
+ attrs = GetFileAttributesW(result);
+
+ if (attrs != INVALID_FILE_ATTRIBUTES &&
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ return result;
+ }
+
+ uv__free(result);
+ return NULL;
+}
+
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* path_search_walk_ext(const WCHAR *dir,
+ size_t dir_len,
+ const WCHAR *name,
+ size_t name_len,
+ WCHAR *cwd,
+ size_t cwd_len,
+ int name_has_ext) {
+ WCHAR* result;
+
+ /* If the name itself has a nonempty extension, try this extension first */
+ if (name_has_ext) {
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"", 0,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+ }
+
+ /* Try .com extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"com", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ /* Try .exe extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"exe", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * search_path searches the system path for an executable filename -
+ * the windows API doesn't provide this as a standalone function nor as an
+ * option to CreateProcess.
+ *
+ * It tries to return an absolute filename.
+ *
+ * Furthermore, it tries to follow the semantics that cmd.exe, with this
+ * exception that PATHEXT environment variable isn't used. Since CreateProcess
+ * can start only .com and .exe files, only those extensions are tried. This
+ * behavior equals that of msvcrt's spawn functions.
+ *
+ * - Do not search the path if the filename already contains a path (either
+ * relative or absolute).
+ *
+ * - If there's really only a filename, check the current directory for file,
+ * then search all path directories.
+ *
+ * - If filename specified has *any* extension, search for the file with the
+ * specified extension first.
+ *
+ * - If the literal filename is not found in a directory, try *appending*
+ * (not replacing) .com first and then .exe.
+ *
+ * - The path variable may contain relative paths; relative paths are relative
+ * to the cwd.
+ *
+ * - Directories in path may or may not end with a trailing backslash.
+ *
+ * - CMD does not trim leading/trailing whitespace from path/pathex entries
+ * nor from the environment variables as a whole.
+ *
+ * - When cmd.exe cannot read a directory, it will just skip it and go on
+ * searching. However, unlike posix-y systems, it will happily try to run a
+ * file that is not readable/executable; if the spawn fails it will not
+ * continue searching.
+ *
+ * UNC path support: we are dealing with UNC paths in both the path and the
+ * filename. This is a deviation from what cmd.exe does (it does not let you
+ * start a program by specifying an UNC path on the command line) but this is
+ * really a pointless restriction.
+ *
+ */
+static WCHAR* search_path(const WCHAR *file,
+ WCHAR *cwd,
+ const WCHAR *path) {
+ int file_has_dir;
+ WCHAR* result = NULL;
+ WCHAR *file_name_start;
+ WCHAR *dot;
+ const WCHAR *dir_start, *dir_end, *dir_path;
+ size_t dir_len;
+ int name_has_ext;
+
+ size_t file_len = wcslen(file);
+ size_t cwd_len = wcslen(cwd);
+
+ /* If the caller supplies an empty filename,
+ * we're not gonna return c:\windows\.exe -- GFY!
+ */
+ if (file_len == 0
+ || (file_len == 1 && file[0] == L'.')) {
+ return NULL;
+ }
+
+ /* Find the start of the filename so we can split the directory from the */
+ /* name. */
+ for (file_name_start = (WCHAR*)file + file_len;
+ file_name_start > file
+ && file_name_start[-1] != L'\\'
+ && file_name_start[-1] != L'/'
+ && file_name_start[-1] != L':';
+ file_name_start--);
+
+ file_has_dir = file_name_start != file;
+
+ /* Check if the filename includes an extension */
+ dot = wcschr(file_name_start, L'.');
+ name_has_ext = (dot != NULL && dot[1] != L'\0');
+
+ if (file_has_dir) {
+ /* The file has a path inside, don't use path */
+ result = path_search_walk_ext(
+ file, file_name_start - file,
+ file_name_start, file_len - (file_name_start - file),
+ cwd, cwd_len,
+ name_has_ext);
+
+ } else {
+ dir_end = path;
+
+ /* The file is really only a name; look in cwd first, then scan path */
+ result = path_search_walk_ext(L"", 0,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+
+ while (result == NULL) {
+ if (*dir_end == L'\0') {
+ break;
+ }
+
+ /* Skip the separator that dir_end now points to */
+ if (dir_end != path || *path == L';') {
+ dir_end++;
+ }
+
+ /* Next slice starts just after where the previous one ended */
+ dir_start = dir_end;
+
+ /* Slice until the next ; or \0 is found */
+ dir_end = wcschr(dir_start, L';');
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+
+ /* If the slice is zero-length, don't bother */
+ if (dir_end - dir_start == 0) {
+ continue;
+ }
+
+ dir_path = dir_start;
+ dir_len = dir_end - dir_start;
+
+ /* Adjust if the path is quoted. */
+ if (dir_path[0] == '"' || dir_path[0] == '\'') {
+ ++dir_path;
+ --dir_len;
+ }
+
+ if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
+ --dir_len;
+ }
+
+ result = path_search_walk_ext(dir_path, dir_len,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Quotes command line arguments
+ * Returns a pointer to the end (next char to be written) of the buffer
+ */
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
+ size_t len = wcslen(source);
+ size_t i;
+ int quote_hit;
+ WCHAR* start;
+
+ if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L" \t\"")) {
+ /* No quotation needed */
+ wcsncpy(target, source, len);
+ target += len;
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L"\"\\")) {
+ /*
+ * No embedded double quotes or backlashes, so I can just wrap
+ * quote marks around the whole thing.
+ */
+ *(target++) = L'"';
+ wcsncpy(target, source, len);
+ target += len;
+ *(target++) = L'"';
+ return target;
+ }
+
+ /*
+ * Expected input/output:
+ * input : hello"world
+ * output: "hello\"world"
+ * input : hello""world
+ * output: "hello\"\"world"
+ * input : hello\world
+ * output: hello\world
+ * input : hello\\world
+ * output: hello\\world
+ * input : hello\"world
+ * output: "hello\\\"world"
+ * input : hello\\"world
+ * output: "hello\\\\\"world"
+ * input : hello world\
+ * output: "hello world\"
+ */
+
+ *(target++) = L'"';
+ start = target;
+ quote_hit = 1;
+
+ for (i = len; i > 0; --i) {
+ *(target++) = source[i - 1];
+
+ if (quote_hit && source[i - 1] == L'\\') {
+ *(target++) = L'\\';
+ } else if(source[i - 1] == L'"') {
+ quote_hit = 1;
+ *(target++) = L'\\';
+ } else {
+ quote_hit = 0;
+ }
+ }
+ target[0] = L'\0';
+ wcsrev(start);
+ *(target++) = L'"';
+ return target;
+}
+
+
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
+ char** arg;
+ WCHAR* dst = NULL;
+ WCHAR* temp_buffer = NULL;
+ size_t dst_len = 0;
+ size_t temp_buffer_len = 0;
+ WCHAR* pos;
+ int arg_count = 0;
+ int err = 0;
+
+ /* Count the required size. */
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ NULL,
+ 0);
+ if (arg_len == 0) {
+ return GetLastError();
+ }
+
+ dst_len += arg_len;
+
+ if (arg_len > temp_buffer_len)
+ temp_buffer_len = arg_len;
+
+ arg_count++;
+ }
+
+ /* Adjust for potential quotes. Also assume the worst-case scenario */
+ /* that every character needs escaping, so we need twice as much space. */
+ dst_len = dst_len * 2 + arg_count * 2;
+
+ /* Allocate buffer for the final command line. */
+ dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
+ if (dst == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ /* Allocate temporary working buffer. */
+ temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
+ if (temp_buffer == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ pos = dst;
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ /* Convert argument to wide char. */
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ temp_buffer,
+ (int) (dst + dst_len - pos));
+ if (arg_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (verbatim_arguments) {
+ /* Copy verbatim. */
+ wcscpy(pos, temp_buffer);
+ pos += arg_len - 1;
+ } else {
+ /* Quote/escape, if needed. */
+ pos = quote_cmd_arg(temp_buffer, pos);
+ }
+
+ *pos++ = *(arg + 1) ? L' ' : L'\0';
+ }
+
+ uv__free(temp_buffer);
+
+ *dst_ptr = dst;
+ return 0;
+
+error:
+ uv__free(dst);
+ uv__free(temp_buffer);
+ return err;
+}
+
+
+int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
+ wchar_t* a_eq;
+ wchar_t* b_eq;
+ wchar_t* A;
+ wchar_t* B;
+ int nb;
+ int r;
+
+ if (na < 0) {
+ a_eq = wcschr(a, L'=');
+ assert(a_eq);
+ na = (int)(long)(a_eq - a);
+ } else {
+ na--;
+ }
+ b_eq = wcschr(b, L'=');
+ assert(b_eq);
+ nb = b_eq - b;
+
+ A = alloca((na+1) * sizeof(wchar_t));
+ B = alloca((nb+1) * sizeof(wchar_t));
+
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
+ assert(r==na);
+ A[na] = L'\0';
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
+ assert(r==nb);
+ B[nb] = L'\0';
+
+ while (1) {
+ wchar_t AA = *A++;
+ wchar_t BB = *B++;
+ if (AA < BB) {
+ return -1;
+ } else if (AA > BB) {
+ return 1;
+ } else if (!AA && !BB) {
+ return 0;
+ }
+ }
+}
+
+
+static int qsort_wcscmp(const void *a, const void *b) {
+ wchar_t* astr = *(wchar_t* const*)a;
+ wchar_t* bstr = *(wchar_t* const*)b;
+ return env_strncmp(astr, -1, bstr);
+}
+
+
+/*
+ * The way windows takes environment variables is different than what C does;
+ * Windows wants a contiguous block of null-terminated strings, terminated
+ * with an additional null.
+ *
+ * Windows has a few "essential" environment variables. winsock will fail
+ * to initialize if SYSTEMROOT is not defined; some APIs make reference to
+ * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
+ * these get defined if the input environment block does not contain any
+ * values for them.
+ *
+ * Also add variables known to Cygwin to be required for correct
+ * subprocess operation in many cases:
+ * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
+ *
+ */
+int make_program_env(char* env_block[], WCHAR** dst_ptr) {
+ WCHAR* dst;
+ WCHAR* ptr;
+ char** env;
+ size_t env_len = 0;
+ int len;
+ size_t i;
+ DWORD var_size;
+ size_t env_block_count = 1; /* 1 for null-terminator */
+ WCHAR* dst_copy;
+ WCHAR** ptr_copy;
+ WCHAR** env_copy;
+ DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
+
+ /* first pass: determine size in UTF-16 */
+ for (env = env_block; *env; env++) {
+ int len;
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ NULL,
+ 0);
+ if (len <= 0) {
+ return GetLastError();
+ }
+ env_len += len;
+ env_block_count++;
+ }
+ }
+
+ /* second pass: copy to UTF-16 environment block */
+ dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
+ if (!dst_copy) {
+ return ERROR_OUTOFMEMORY;
+ }
+ env_copy = alloca(env_block_count * sizeof(WCHAR*));
+
+ ptr = dst_copy;
+ ptr_copy = env_copy;
+ for (env = env_block; *env; env++) {
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ ptr,
+ (int) (env_len - (ptr - dst_copy)));
+ if (len <= 0) {
+ DWORD err = GetLastError();
+ uv__free(dst_copy);
+ return err;
+ }
+ *ptr_copy++ = ptr;
+ ptr += len;
+ }
+ }
+ *ptr_copy = NULL;
+ assert(env_len == ptr - dst_copy);
+
+ /* sort our (UTF-16) copy */
+ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
+
+ /* third pass: check for required variables */
+ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
+ int cmp;
+ if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
+ required_vars_value_len[i] = var_size;
+ if (var_size != 0) {
+ env_len += required_vars[i].len;
+ env_len += var_size;
+ }
+ i++;
+ } else {
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* final pass: copy, in sort order, and inserting required variables */
+ dst = uv__malloc((1+env_len) * sizeof(WCHAR));
+ if (!dst) {
+ uv__free(dst_copy);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ for (ptr = dst, ptr_copy = env_copy, i = 0;
+ *ptr_copy || i < n_required_vars;
+ ptr += len) {
+ int cmp;
+ if (i >= n_required_vars) {
+ cmp = 1;
+ } else if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ len = required_vars_value_len[i];
+ if (len) {
+ wcscpy(ptr, required_vars[i].wide_eq);
+ ptr += required_vars[i].len;
+ var_size = GetEnvironmentVariableW(required_vars[i].wide,
+ ptr,
+ (int) (env_len - (ptr - dst)));
+ if (var_size != len-1) { /* race condition? */
+ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ }
+ }
+ i++;
+ } else {
+ /* copy var from env_block */
+ len = wcslen(*ptr_copy) + 1;
+ wmemcpy(ptr, *ptr_copy, len);
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* Terminate with an extra NULL. */
+ assert(env_len == (ptr - dst));
+ *ptr = L'\0';
+
+ uv__free(dst_copy);
+ *dst_ptr = dst;
+ return 0;
+}
+
+/*
+ * Attempt to find the value of the PATH environment variable in the child's
+ * preprocessed environment.
+ *
+ * If found, a pointer into `env` is returned. If not found, NULL is returned.
+ */
+static WCHAR* find_path(WCHAR *env) {
+ for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
+ if (wcsncmp(env, L"PATH=", 5) == 0)
+ return &env[5];
+ }
+
+ return NULL;
+}
+
+/*
+ * Called on Windows thread-pool thread to indicate that
+ * a child process has exited.
+ */
+static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
+ uv_process_t* process = (uv_process_t*) data;
+ uv_loop_t* loop = process->loop;
+
+ assert(didTimeout == FALSE);
+ assert(process);
+ assert(!process->exit_cb_pending);
+
+ process->exit_cb_pending = 1;
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
+}
+
+
+/* Called on main thread after a child process has exited. */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+ int64_t exit_code;
+ DWORD status;
+
+ assert(handle->exit_cb_pending);
+ handle->exit_cb_pending = 0;
+
+ /* If we're closing, don't call the exit callback. Just schedule a close */
+ /* callback now. */
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return;
+ }
+
+ /* Unregister from process notification. */
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->wait_handle);
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Set the handle to inactive: no callbacks will be made after the exit */
+ /* callback.*/
+ uv__handle_stop(handle);
+
+ if (GetExitCodeProcess(handle->process_handle, &status)) {
+ exit_code = status;
+ } else {
+ /* Unable to to obtain the exit code. This should never happen. */
+ exit_code = uv_translate_sys_error(GetLastError());
+ }
+
+ /* Fire the exit callback. */
+ if (handle->exit_cb) {
+ handle->exit_cb(handle, exit_code, handle->exit_signal);
+ }
+}
+
+
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_closing(handle);
+
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ /* This blocks until either the wait was cancelled, or the callback has */
+ /* completed. */
+ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
+ if (!r) {
+ /* This should never happen, and if it happens, we can't recover... */
+ uv_fatal_error(GetLastError(), "UnregisterWaitEx");
+ }
+
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (!handle->exit_cb_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
+ assert(!handle->exit_cb_pending);
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ /* Clean-up the process handle. */
+ CloseHandle(handle->process_handle);
+
+ uv__handle_close(handle);
+}
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+ int i;
+ int err = 0;
+ WCHAR* path = NULL, *alloc_path = NULL;
+ BOOL result;
+ WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
+ *env = NULL, *cwd = NULL;
+ STARTUPINFOW startup;
+ PROCESS_INFORMATION info;
+ DWORD process_flags;
+
+ uv_process_init(loop, process);
+ process->exit_cb = options->exit_cb;
+
+ if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
+ return UV_ENOTSUP;
+ }
+
+ if (options->file == NULL ||
+ options->args == NULL) {
+ return UV_EINVAL;
+ }
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ err = uv_utf8_to_utf16_alloc(options->file, &application);
+ if (err)
+ goto done;
+
+ err = make_program_args(
+ options->args,
+ options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
+ &arguments);
+ if (err)
+ goto done;
+
+ if (options->env) {
+ err = make_program_env(options->env, &env);
+ if (err)
+ goto done;
+ }
+
+ if (options->cwd) {
+ /* Explicit cwd */
+ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
+ if (err)
+ goto done;
+
+ } else {
+ /* Inherit cwd */
+ DWORD cwd_len, r;
+
+ cwd_len = GetCurrentDirectoryW(0, NULL);
+ if (!cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+
+ cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
+ if (cwd == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+
+ r = GetCurrentDirectoryW(cwd_len, cwd);
+ if (r == 0 || r >= cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ /* Get PATH environment variable. */
+ path = find_path(env);
+ if (path == NULL) {
+ DWORD path_len, r;
+
+ path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ if (path_len == 0) {
+ err = GetLastError();
+ goto done;
+ }
+
+ alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
+ if (alloc_path == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+ path = alloc_path;
+
+ r = GetEnvironmentVariableW(L"PATH", path, path_len);
+ if (r == 0 || r >= path_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
+ if (err)
+ goto done;
+
+ application_path = search_path(application,
+ cwd,
+ path);
+ if (application_path == NULL) {
+ /* Not found. */
+ err = ERROR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ startup.cb = sizeof(startup);
+ startup.lpReserved = NULL;
+ startup.lpDesktop = NULL;
+ startup.lpTitle = NULL;
+ startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+ startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
+ startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
+
+ startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
+ startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
+ startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+
+ if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
+ /* Use SW_HIDE to avoid any potential process window. */
+ startup.wShowWindow = SW_HIDE;
+ } else {
+ startup.wShowWindow = SW_SHOWDEFAULT;
+ }
+
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
+ if (options->flags & UV_PROCESS_DETACHED) {
+ /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
+ * means that libuv might not let you create a fully daemonized process
+ * when run under job control. However the type of job control that libuv
+ * itself creates doesn't trickle down to subprocesses so they can still
+ * daemonize.
+ *
+ * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
+ * CreateProcess call fail if we're under job control that doesn't allow
+ * breakaway.
+ */
+ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ }
+
+ if (!CreateProcessW(application_path,
+ arguments,
+ NULL,
+ NULL,
+ 1,
+ process_flags,
+ env,
+ cwd,
+ &startup,
+ &info)) {
+ /* CreateProcessW failed. */
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Spawn succeeded */
+ /* Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
+ /* If the process isn't spawned as detached, assign to the global job */
+ /* object so windows will kill it when the parent process dies. */
+ if (!(options->flags & UV_PROCESS_DETACHED)) {
+ uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
+ }
+
+ /* Set IPC pid to all IPC pipes. */
+ for (i = 0; i < options->stdio_count; i++) {
+ const uv_stdio_container_t* fdopt = &options->stdio[i];
+ if (fdopt->flags & UV_CREATE_PIPE &&
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
+ ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
+ }
+ }
+
+ /* Setup notifications for when the child process exits. */
+ result = RegisterWaitForSingleObject(&process->wait_handle,
+ process->process_handle, exit_wait_callback, (void*)process, INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!result) {
+ uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+ }
+
+ CloseHandle(info.hThread);
+
+ assert(!err);
+
+ /* Make the handle active. It will remain active until the exit callback */
+ /* is made or the handle is closed, whichever happens first. */
+ uv__handle_start(process);
+
+ /* Cleanup, whether we succeeded or failed. */
+ done:
+ uv__free(application);
+ uv__free(application_path);
+ uv__free(arguments);
+ uv__free(cwd);
+ uv__free(env);
+ uv__free(alloc_path);
+
+ if (process->child_stdio_buffer != NULL) {
+ /* Clean up child stdio handles. */
+ uv__stdio_destroy(process->child_stdio_buffer);
+ process->child_stdio_buffer = NULL;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__kill(HANDLE process_handle, int signum) {
+ switch (signum) {
+ case SIGTERM:
+ case SIGKILL:
+ case SIGINT: {
+ /* Unconditionally terminate the process. On Windows, killed processes */
+ /* normally return 1. */
+ DWORD status;
+ int err;
+
+ if (TerminateProcess(process_handle, 1))
+ return 0;
+
+ /* If the process already exited before TerminateProcess was called, */
+ /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED &&
+ GetExitCodeProcess(process_handle, &status) &&
+ status != STILL_ACTIVE) {
+ return UV_ESRCH;
+ }
+
+ return uv_translate_sys_error(err);
+ }
+
+ case 0: {
+ /* Health check: is the process still alive? */
+ DWORD status;
+
+ if (!GetExitCodeProcess(process_handle, &status))
+ return uv_translate_sys_error(GetLastError());
+
+ if (status != STILL_ACTIVE)
+ return UV_ESRCH;
+
+ return 0;
+ }
+
+ default:
+ /* Unsupported signal. */
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ int err;
+
+ if (process->process_handle == INVALID_HANDLE_VALUE) {
+ return UV_EINVAL;
+ }
+
+ err = uv__kill(process->process_handle, signum);
+ if (err) {
+ return err; /* err is already translated. */
+ }
+
+ process->exit_signal = signum;
+
+ return 0;
+}
+
+
+int uv_kill(int pid, int signum) {
+ int err;
+ HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (process_handle == NULL) {
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER) {
+ return UV_ESRCH;
+ } else {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ err = uv__kill(process_handle, signum);
+ CloseHandle(process_handle);
+
+ return err; /* err is already translated. */
+}
diff --git a/3rdparty/libuv/src/win/req-inl.h b/3rdparty/libuv/src/win/req-inl.h
new file mode 100644
index 00000000000..b5e502eef55
--- /dev/null
+++ b/3rdparty/libuv/src/win/req-inl.h
@@ -0,0 +1,224 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_REQ_INL_H_
+#define UV_WIN_REQ_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define SET_REQ_STATUS(req, status) \
+ (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((NTSTATUS) (req)->u.io.overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+
+#define REGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ INCREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_register((loop), (req)); \
+ } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ DECREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_unregister((loop), (req)); \
+ } while (0)
+
+
+#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
+ ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
+
+#define UV_SUCCEEDED_WITH_IOCP(result) \
+ ((result) || (GetLastError() == ERROR_IO_PENDING))
+
+
+#define POST_COMPLETION_FOR_REQ(loop, req) \
+ if (!PostQueuedCompletionStatus((loop)->iocp, \
+ 0, \
+ 0, \
+ &((req)->u.io.overlapped))) { \
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
+ }
+
+
+INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
+ req->type = UV_UNKNOWN_REQ;
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+ return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
+}
+
+
+INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+ req->next_req = NULL;
+ if (loop->pending_reqs_tail) {
+#ifdef _DEBUG
+ /* Ensure the request is not already in the queue, or the queue
+ * will get corrupted.
+ */
+ uv_req_t* current = loop->pending_reqs_tail;
+ do {
+ assert(req != current);
+ current = current->next_req;
+ } while(current != loop->pending_reqs_tail);
+#endif
+
+ req->next_req = loop->pending_reqs_tail->next_req;
+ loop->pending_reqs_tail->next_req = req;
+ loop->pending_reqs_tail = req;
+ } else {
+ req->next_req = req;
+ loop->pending_reqs_tail = req;
+ }
+}
+
+
+#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
+ do { \
+ switch (((uv_handle_t*) (req)->handle_at)->type) { \
+ case UV_TCP: \
+ uv_process_tcp_##method##_req(loop, \
+ (uv_tcp_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_NAMED_PIPE: \
+ uv_process_pipe_##method##_req(loop, \
+ (uv_pipe_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_TTY: \
+ uv_process_tty_##method##_req(loop, \
+ (uv_tty_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ default: \
+ assert(0); \
+ } \
+ } while (0)
+
+
+INLINE static int uv_process_reqs(uv_loop_t* loop) {
+ uv_req_t* req;
+ uv_req_t* first;
+ uv_req_t* next;
+
+ if (loop->pending_reqs_tail == NULL)
+ return 0;
+
+ first = loop->pending_reqs_tail->next_req;
+ next = first;
+ loop->pending_reqs_tail = NULL;
+
+ while (next != NULL) {
+ req = next;
+ next = req->next_req != first ? req->next_req : NULL;
+
+ switch (req->type) {
+ case UV_READ:
+ DELEGATE_STREAM_REQ(loop, req, read, data);
+ break;
+
+ case UV_WRITE:
+ DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
+ break;
+
+ case UV_ACCEPT:
+ DELEGATE_STREAM_REQ(loop, req, accept, data);
+ break;
+
+ case UV_CONNECT:
+ DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
+ break;
+
+ case UV_SHUTDOWN:
+ /* Tcp shutdown requests don't come here. */
+ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
+ uv_process_pipe_shutdown_req(
+ loop,
+ (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
+ (uv_shutdown_t*) req);
+ break;
+
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(loop,
+ ((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
+ case UV_WAKEUP:
+ uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+ break;
+
+ case UV_SIGNAL_REQ:
+ uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+ break;
+
+ case UV_POLL_REQ:
+ uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+ break;
+
+ case UV_PROCESS_EXIT:
+ uv_process_proc_exit(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return 1;
+}
+
+#endif /* UV_WIN_REQ_INL_H_ */
diff --git a/3rdparty/libuv/src/win/req.c b/3rdparty/libuv/src/win/req.c
new file mode 100644
index 00000000000..111cc5e2893
--- /dev/null
+++ b/3rdparty/libuv/src/win/req.c
@@ -0,0 +1,25 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
diff --git a/3rdparty/libuv/src/win/signal.c b/3rdparty/libuv/src/win/signal.c
new file mode 100644
index 00000000000..2c64a55dc39
--- /dev/null
+++ b/3rdparty/libuv/src/win/signal.c
@@ -0,0 +1,356 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <signal.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+RB_HEAD(uv_signal_tree_s, uv_signal_s);
+
+static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
+static ssize_t volatile uv__signal_control_handler_refs = 0;
+static CRITICAL_SECTION uv__signal_lock;
+
+
+void uv_signals_init() {
+ InitializeCriticalSection(&uv__signal_lock);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up */
+ /* adjacent. */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after */
+ /* { .signum = x, .loop = NULL } */
+ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
+ if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
+
+ if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
+ if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
+
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+
+
+/*
+ * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
+ * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
+ * no active signal watchers observing this signal.
+ */
+int uv__signal_dispatch(int signum) {
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+ int dispatched = 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
+ unsigned long previous = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, signum);
+
+ if (!previous) {
+ POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
+ }
+
+ dispatched = 1;
+ }
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ return dispatched;
+}
+
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type) {
+ switch (type) {
+ case CTRL_C_EVENT:
+ return uv__signal_dispatch(SIGINT);
+
+ case CTRL_BREAK_EVENT:
+ return uv__signal_dispatch(SIGBREAK);
+
+ case CTRL_CLOSE_EVENT:
+ if (uv__signal_dispatch(SIGHUP)) {
+ /* Windows will terminate the process after the control handler */
+ /* returns. After that it will just terminate our process. Therefore */
+ /* block the signal handler so the main loop has some time to pick */
+ /* up the signal and do something for a few seconds. */
+ Sleep(INFINITE);
+ return TRUE;
+ }
+ return FALSE;
+
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ /* These signals are only sent to services. Services have their own */
+ /* notification mechanism, so there's no point in handling these. */
+
+ default:
+ /* We don't handle these. */
+ return FALSE;
+ }
+}
+
+
+static int uv__signal_register_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+
+ /* If the console control handler has already been hooked, just add a */
+ /* reference. */
+ if (uv__signal_control_handler_refs > 0) {
+ uv__signal_control_handler_refs++;
+ return 0;
+ }
+
+ if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+ return GetLastError();
+
+ uv__signal_control_handler_refs++;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+ BOOL r;
+
+ /* Don't unregister if the number of console control handlers exceeds one. */
+ /* Just remove a reference in that case. */
+ if (uv__signal_control_handler_refs > 1) {
+ uv__signal_control_handler_refs--;
+ return;
+ }
+
+ assert(uv__signal_control_handler_refs == 1);
+
+ r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
+ /* This should never fail; if it does it is probably a bug in libuv. */
+ assert(r);
+
+ uv__signal_control_handler_refs--;
+}
+
+
+static int uv__signal_register(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ return uv__signal_register_control_handler();
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to register anything. */
+ return 0;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Signal is never raised. */
+ return 0;
+
+ default:
+ /* Invalid signal. */
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+
+static void uv__signal_unregister(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ uv__signal_unregister_control_handler();
+ return;
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to unregister anything. */
+ return;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Nothing is registered for this signal. */
+ return;
+
+ default:
+ /* Libuv bug. */
+ assert(0 && "Invalid signum");
+ return;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->pending_signum = 0;
+ handle->signum = 0;
+ handle->signal_cb = NULL;
+
+ req = &handle->signal_req;
+ uv_req_init(loop, req);
+ req->type = UV_SIGNAL_REQ;
+ req->data = handle;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ uv__signal_unregister(handle->signum);
+
+ removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ int err;
+
+ /* If the user supplies signum == 0, then return an error already. If the */
+ /* signum is otherwise invalid then uv__signal_register will find out */
+ /* eventually. */
+ if (signum == 0) {
+ return UV_EINVAL;
+ }
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't */
+ /* go through the process of deregistering and registering the handler. */
+ /* Additionally, this avoids pending signals getting lost in the (small) */
+ /* time frame that handle->signum == 0. */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ int r = uv_signal_stop(handle);
+ /* uv_signal_stop is infallible. */
+ assert(r == 0);
+ }
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ err = uv__signal_register(signum);
+ if (err) {
+ /* Uh-oh, didn't work. */
+ LeaveCriticalSection(&uv__signal_lock);
+ return uv_translate_sys_error(err);
+ }
+
+ handle->signum = signum;
+ RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req) {
+ long dispatched_signum;
+
+ assert(handle->type == UV_SIGNAL);
+ assert(req->type == UV_SIGNAL_REQ);
+
+ dispatched_signum = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, 0);
+ assert(dispatched_signum != 0);
+
+ /* Check if the pending signal equals the signum that we are watching for. */
+ /* These can get out of sync when the handler is stopped and restarted */
+ /* while the signal_req is pending. */
+ if (dispatched_signum == handle->signum)
+ handle->signal_cb(handle, dispatched_signum);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* When it is closing, it must be stopped at this point. */
+ assert(handle->signum == 0);
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_signal_stop(handle);
+ uv__handle_closing(handle);
+
+ if (handle->pending_signum == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->signum == 0);
+ assert(handle->pending_signum == 0);
+
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ uv__handle_close(handle);
+}
diff --git a/3rdparty/libuv/src/win/snprintf.c b/3rdparty/libuv/src/win/snprintf.c
new file mode 100644
index 00000000000..776c0e39217
--- /dev/null
+++ b/3rdparty/libuv/src/win/snprintf.c
@@ -0,0 +1,42 @@
+/* Copyright the libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
+ * on overflow...
+ */
+int snprintf(char* buf, size_t len, const char* fmt, ...) {
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ n = _vscprintf(fmt, ap);
+ vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
+
+ va_end(ap);
+ return n;
+}
+
+#endif
diff --git a/3rdparty/libuv/src/win/stream-inl.h b/3rdparty/libuv/src/win/stream-inl.h
new file mode 100644
index 00000000000..b7a3c11958c
--- /dev/null
+++ b/3rdparty/libuv/src/win/stream-inl.h
@@ -0,0 +1,56 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_STREAM_INL_H_
+#define UV_WIN_STREAM_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+INLINE static void uv_stream_init(uv_loop_t* loop,
+ uv_stream_t* handle,
+ uv_handle_type type) {
+ uv__handle_init(loop, (uv_handle_t*) handle, type);
+ handle->write_queue_size = 0;
+ handle->activecnt = 0;
+}
+
+
+INLINE static void uv_connection_init(uv_stream_t* handle) {
+ handle->flags |= UV_HANDLE_CONNECTION;
+ handle->stream.conn.write_reqs_pending = 0;
+
+ uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
+ handle->read_req.event_handle = NULL;
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ handle->read_req.type = UV_READ;
+ handle->read_req.data = handle;
+
+ handle->stream.conn.shutdown_req = NULL;
+}
+
+
+#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/3rdparty/libuv/src/win/stream.c b/3rdparty/libuv/src/win/stream.c
new file mode 100644
index 00000000000..a2466e5e9db
--- /dev/null
+++ b/3rdparty/libuv/src/win/stream.c
@@ -0,0 +1,249 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (server->type) {
+ case UV_TCP:
+ err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_accept((uv_pipe_t*)server, client);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return UV_EALREADY;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ return UV_ENOTCONN;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_stop(uv_stream_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_READING))
+ return 0;
+
+ err = 0;
+ if (handle->type == UV_TTY) {
+ err = uv_tty_read_stop((uv_tty_t*) handle);
+ } else {
+ if (handle->type == UV_NAMED_PIPE) {
+ uv__pipe_stop_read((uv_pipe_t*) handle);
+ } else {
+ handle->flags &= ~UV_HANDLE_READING;
+ }
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write2(loop,
+ req,
+ (uv_pipe_t*) handle,
+ bufs,
+ nbufs,
+ send_handle,
+ cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ if (stream->flags & UV__HANDLE_CLOSING)
+ return UV_EBADF;
+ if (!(stream->flags & UV_HANDLE_WRITABLE))
+ return UV_EPIPE;
+
+ switch (stream->type) {
+ case UV_TCP:
+ return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
+ case UV_TTY:
+ return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
+ case UV_NAMED_PIPE:
+ return UV_EAGAIN;
+ default:
+ assert(0);
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_SHUTDOWN;
+ req->handle = handle;
+ req->cb = cb;
+
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ handle->stream.conn.shutdown_req = req;
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_WRITABLE);
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ if (handle->type != UV_NAMED_PIPE)
+ return UV_EINVAL;
+
+ if (blocking != 0)
+ handle->flags |= UV_HANDLE_BLOCKING_WRITES;
+ else
+ handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/tcp.c b/3rdparty/libuv/src/win/tcp.c
new file mode 100644
index 00000000000..0f5654863e9
--- /dev/null
+++ b/3rdparty/libuv/src/win/tcp.c
@@ -0,0 +1,1507 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active tcp streams for which to preallocate tcp read buffers.
+ * (Due to node slab allocator performing poorly under this pattern,
+ * the optimization is temporarily disabled (threshold=0). This will be
+ * revisited once node allocator is improved.)
+ */
+const unsigned int uv_active_tcp_streams_threshold = 0;
+
+/*
+ * Number of simultaneous pending AcceptEx calls.
+ */
+const unsigned int uv_simultaneous_server_accepts = 32;
+
+/* A zero-size buffer for use by uv_tcp_read */
+static char uv_zero_[] = "";
+
+static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
+ if (setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+ return 0;
+}
+
+
+static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
+ if (setsockopt(socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+
+ if (enable && setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_KEEPALIVE,
+ (const char*)&delay,
+ sizeof delay) == -1) {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_set_socket(uv_loop_t* loop,
+ uv_tcp_t* handle,
+ SOCKET socket,
+ int family,
+ int imported) {
+ DWORD yes = 1;
+ int non_ifs_lsp;
+ int err;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
+ return GetLastError();
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ if (imported) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ } else {
+ return GetLastError();
+ }
+ }
+
+ if (family == AF_INET6) {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6;
+ } else {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
+ }
+
+ if (pSetFileCompletionNotificationModes &&
+ !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
+ if (pSetFileCompletionNotificationModes((HANDLE) socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_TCP_NODELAY) {
+ err = uv__tcp_nodelay(handle, socket, 1);
+ if (err)
+ return err;
+ }
+
+ /* TODO: Use stored delay. */
+ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) {
+ err = uv__tcp_keepalive(handle, socket, 1, 60);
+ if (err)
+ return err;
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+ handle->tcp.serv.accept_reqs = NULL;
+ handle->tcp.serv.pending_accepts = NULL;
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->tcp.serv.func_acceptex = NULL;
+ handle->tcp.conn.func_connectex = NULL;
+ handle->tcp.serv.processed_accepts = 0;
+ handle->delayed_error = 0;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
+ return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+ int err;
+ unsigned int i;
+ uv_tcp_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ err = 0;
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ err = ERROR_OPERATION_ABORTED;
+ } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ }
+
+ if (handle->stream.conn.shutdown_req->cb) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
+ uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+ handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+ }
+
+ uv__free(handle->tcp.serv.accept_reqs);
+ handle->tcp.serv.accept_reqs = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+
+ uv__handle_close(handle);
+ loop->active_tcp_streams--;
+ }
+}
+
+
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
+static int uv_tcp_try_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ DWORD err;
+ int r;
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return ERROR_INVALID_PARAMETER;
+
+ sock = socket(addr->sa_family, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ int on;
+
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (const char*)&on,
+ sizeof on);
+ }
+#endif
+
+ r = bind(handle->socket, addr, addrlen);
+
+ if (r == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err == WSAEADDRINUSE) {
+ /* Some errors are not to be reported until connect() or listen() */
+ handle->delayed_error = err;
+ } else {
+ return err;
+ }
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
+ uv_req_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_req_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
+ uv_loop_t* loop = handle->loop;
+ BOOL success;
+ DWORD bytes;
+ SOCKET accept_socket;
+ short family;
+
+ assert(handle->flags & UV_HANDLE_LISTENING);
+ assert(req->accept_socket == INVALID_SOCKET);
+
+ /* choose family and extension function */
+ if (handle->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ /* Open a socket for the accepted connection. */
+ accept_socket = socket(family, SOCK_STREAM, 0);
+ if (accept_socket == INVALID_SOCKET) {
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ closesocket(accept_socket);
+ return;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ success = handle->tcp.serv.func_acceptex(handle->socket,
+ accept_socket,
+ (void*)req->accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ /* Destroy the preallocated client socket. */
+ closesocket(accept_socket);
+ /* Destroy the event handle */
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ CloseHandle(req->u.io.overlapped.hEvent);
+ req->event_handle = NULL;
+ }
+ }
+}
+
+
+static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
+ uv_read_t* req;
+ uv_buf_t buf;
+ int result;
+ DWORD bytes, flags;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
+ if (handle->tcp.conn.read_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
+ return;
+ }
+ assert(handle->tcp.conn.read_buffer.base != NULL);
+ buf = handle->tcp.conn.read_buffer;
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+ buf.base = (char*) &uv_zero_;
+ buf.len = 0;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ assert(req->event_handle);
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ flags = 0;
+ result = WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ }
+}
+
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ unsigned int i, simultaneous_accepts;
+ uv_tcp_accept_t* req;
+ int err;
+
+ assert(backlog > 0);
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ err = uv_tcp_try_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.serv.func_acceptex) {
+ if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ listen(handle->socket, backlog) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ handle->stream.serv.connection_cb = cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
+ : uv_simultaneous_server_accepts;
+
+ if(!handle->tcp.serv.accept_reqs) {
+ handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
+ uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
+ if (!handle->tcp.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < simultaneous_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*)req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ } else {
+ req->event_handle = NULL;
+ }
+
+ uv_tcp_queue_accept(handle, req);
+ }
+
+ /* Initialize other unused requests too, because uv_tcp_endgame */
+ /* doesn't know how how many requests were initialized, so it will */
+ /* try to clean up {uv_simultaneous_server_accepts} requests. */
+ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ req->event_handle = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
+ uv_loop_t* loop = server->loop;
+ int err = 0;
+ int family;
+
+ uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ if (req->accept_socket == INVALID_SOCKET) {
+ return WSAENOTCONN;
+ }
+
+ if (server->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ err = uv_tcp_set_socket(client->loop,
+ client,
+ req->accept_socket,
+ family,
+ 0);
+ if (err) {
+ closesocket(req->accept_socket);
+ } else {
+ uv_connection_init((uv_stream_t*) client);
+ /* AcceptEx() implicitly binds the accepted socket. */
+ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ /* Prepare the req to pick up a new connection */
+ server->tcp.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->accept_socket = INVALID_SOCKET;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
+ uv_tcp_queue_accept(server, req);
+ } else {
+ /* We better be switching to a single pending accept. */
+ assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
+
+ server->tcp.serv.processed_accepts++;
+
+ if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
+ server->tcp.serv.processed_accepts = 0;
+ /*
+ * All previously queued accept requests are now processed.
+ * We now switch to queueing just a single accept.
+ */
+ uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
+ server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+ }
+ }
+ }
+
+ loop->active_tcp_streams++;
+
+ return err;
+}
+
+
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !handle->read_req.event_handle) {
+ handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!handle->read_req.event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ uv_tcp_queue_read(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ const struct sockaddr* bind_addr;
+ BOOL success;
+ DWORD bytes;
+ int err;
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.conn.func_connectex) {
+ if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ success = handle->tcp.conn.func_connectex(handle->socket,
+ addr,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getpeername(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ int result;
+ DWORD bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_write_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Send failed due to an error, report it later */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ }
+
+ return 0;
+}
+
+
+int uv__tcp_try_write(uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int result;
+ DWORD bytes;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+ else
+ return bytes;
+}
+
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, flags, err;
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TCP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the read. */
+ if ((handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_ZERO_READ)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
+
+ err = GET_REQ_SOCK_ERROR(req);
+
+ if (err == WSAECONNABORTED) {
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ } else {
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* The read was done with a non-zero buffer length. */
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->tcp.conn.read_buffer);
+ /* Read again only if bytes == buf.len */
+ if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
+ goto done;
+ }
+ } else {
+ /* Connection closed */
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+ handle->flags &= ~UV_HANDLE_READABLE;
+
+ buf.base = 0;
+ buf.len = 0;
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
+ goto done;
+ }
+ }
+
+ /* Do nonblocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ flags = 0;
+ if (WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+ if (bytes > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+ /* Read again only if bytes == buf.len */
+ if (bytes < buf.len) {
+ break;
+ }
+ } else {
+ /* Connection closed */
+ handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
+ break;
+ }
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ /* Read buffer was completely empty, report a 0-byte read. */
+ handle->read_cb((uv_stream_t*)handle, 0, &buf);
+ } else {
+ /* Ouch! serious error. */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ if (err == WSAECONNABORTED) {
+ /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
+ /* Unix. */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ break;
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tcp_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->cb) {
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* raw_req) {
+ uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ /* If handle->accepted_socket is not a valid socket, then */
+ /* uv_queue_accept must have failed. This is a serious error. We stop */
+ /* accepting connections and report this error to the connection */
+ /* callback. */
+ if (req->accept_socket == INVALID_SOCKET) {
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ if (handle->stream.serv.connection_cb) {
+ err = GET_REQ_SOCK_ERROR(req);
+ handle->stream.serv.connection_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err));
+ }
+ }
+ } else if (REQ_SUCCESS(req) &&
+ setsockopt(req->accept_socket,
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&handle->socket,
+ sizeof(handle->socket)) == 0) {
+ req->next_pending = handle->tcp.serv.pending_accepts;
+ handle->tcp.serv.pending_accepts = req;
+
+ /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ /* Error related to accepted socket is ignored because the server */
+ /* socket may still be healthy. If the server socket is broken */
+ /* uv_queue_accept will detect it. */
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ uv_tcp_queue_accept(handle, req);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT,
+ NULL,
+ 0) == 0) {
+ uv_connection_init((uv_stream_t*)handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ loop->active_tcp_streams++;
+ } else {
+ err = WSAGetLastError();
+ }
+ } else {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection) {
+ int err;
+ SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &socket_info_ex->socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+
+ if (socket == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(tcp->loop,
+ tcp,
+ socket,
+ socket_info_ex->socket_info.iAddressFamily,
+ 1);
+ if (err) {
+ closesocket(socket);
+ return err;
+ }
+
+ if (tcp_connection) {
+ uv_connection_init((uv_stream_t*)tcp);
+ tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
+ tcp->loop->active_tcp_streams++;
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_nodelay(handle, handle->socket, enable);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_NODELAY;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_NODELAY;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
+ }
+
+ /* TODO: Store delay if handle->socket isn't created yet. */
+
+ return 0;
+}
+
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info) {
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+ /*
+ * We're about to share the socket with another process. Because
+ * this is a listening socket, we assume that the other process will
+ * be accepting connections on it. So, before sharing the socket
+ * with another process, we call listen here in the parent process.
+ */
+
+ if (!(handle->flags & UV_HANDLE_LISTENING)) {
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
+ }
+ }
+ }
+
+ if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ return UV_EINVAL;
+ }
+
+ /* Check if we're already in the desired mode. */
+ if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
+ (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
+ return 0;
+ }
+
+ /* Don't allow switching from single pending accept to many. */
+ if (enable) {
+ return UV_ENOTSUP;
+ }
+
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
+ return 0;
+ }
+
+ handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+
+ /* Flip the changing flag if we have already queued multiple accepts. */
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
+ SOCKET socket = tcp->socket;
+ int non_ifs_lsp;
+
+ /* Check if we have any non-IFS LSPs stacked on top of TCP */
+ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
+ uv_tcp_non_ifs_lsp_ipv4;
+
+ /* If there are non-ifs LSPs then try to obtain a base handle for the */
+ /* socket. This will always fail on Windows XP/3k. */
+ if (non_ifs_lsp) {
+ DWORD bytes;
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &socket,
+ sizeof socket,
+ &bytes,
+ NULL,
+ NULL) != 0) {
+ /* Failed. We can't do CancelIo. */
+ return -1;
+ }
+ }
+
+ assert(socket != 0 && socket != INVALID_SOCKET);
+
+ if (!CancelIo((HANDLE) socket)) {
+ return GetLastError();
+ }
+
+ /* It worked. */
+ return 0;
+}
+
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
+ int close_socket = 1;
+
+ if (tcp->flags & UV_HANDLE_READ_PENDING) {
+ /* In order for winsock to do a graceful close there must not be any */
+ /* any pending reads, or the socket must be shut down for writing */
+ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
+ /* Just do shutdown on non-shared sockets, which ensures graceful close. */
+ shutdown(tcp->socket, SD_SEND);
+
+ } else if (uv_tcp_try_cancel_io(tcp) == 0) {
+ /* In case of a shared socket, we try to cancel all outstanding I/O, */
+ /* If that works, don't close the socket yet - wait for the read req to */
+ /* return and close the socket in uv_tcp_endgame. */
+ close_socket = 0;
+
+ } else {
+ /* When cancelling isn't possible - which could happen when an LSP is */
+ /* present on an old Windows version, we will have to close the socket */
+ /* with a read pending. That is not nice because trailing sent bytes */
+ /* may not make it to the other side. */
+ }
+
+ } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ tcp->tcp.serv.accept_reqs != NULL) {
+ /* Under normal circumstances closesocket() will ensure that all pending */
+ /* accept reqs are canceled. However, when the socket is shared the */
+ /* presence of another reference to the socket in another process will */
+ /* keep the accept reqs going, so we have to ensure that these are */
+ /* canceled. */
+ if (uv_tcp_try_cancel_io(tcp) != 0) {
+ /* When cancellation is not possible, there is another option: we can */
+ /* close the incoming sockets, which will also cancel the accept */
+ /* operations. However this is not cool because we might inadvertently */
+ /* close a socket that just accepted a new connection, which will */
+ /* cause the connection to be aborted. */
+ unsigned int i;
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
+ if (req->accept_socket != INVALID_SOCKET &&
+ !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ }
+ }
+ }
+ }
+
+ if (tcp->flags & UV_HANDLE_READING) {
+ tcp->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (tcp->flags & UV_HANDLE_LISTENING) {
+ tcp->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (close_socket) {
+ closesocket(tcp->socket);
+ tcp->socket = INVALID_SOCKET;
+ tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(tcp);
+
+ if (tcp->reqs_pending == 0) {
+ uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
+ }
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_tcp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily,
+ 1);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_tcp_try_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+
+ err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/thread.c b/3rdparty/libuv/src/win/thread.c
new file mode 100644
index 00000000000..91684e93875
--- /dev/null
+++ b/3rdparty/libuv/src/win/thread.c
@@ -0,0 +1,697 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
+
+static int uv_cond_fallback_init(uv_cond_t* cond);
+static void uv_cond_fallback_destroy(uv_cond_t* cond);
+static void uv_cond_fallback_signal(uv_cond_t* cond);
+static void uv_cond_fallback_broadcast(uv_cond_t* cond);
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+static int uv_cond_condvar_init(uv_cond_t* cond);
+static void uv_cond_condvar_destroy(uv_cond_t* cond);
+static void uv_cond_condvar_signal(uv_cond_t* cond);
+static void uv_cond_condvar_broadcast(uv_cond_t* cond);
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+
+static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
+ DWORD result;
+ HANDLE existing_event, created_event;
+
+ created_event = CreateEvent(NULL, 1, 0, NULL);
+ if (created_event == 0) {
+ /* Could fail in a low-memory situation? */
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ existing_event = InterlockedCompareExchangePointer(&guard->event,
+ created_event,
+ NULL);
+
+ if (existing_event == NULL) {
+ /* We won the race */
+ callback();
+
+ result = SetEvent(created_event);
+ assert(result);
+ guard->ran = 1;
+
+ } else {
+ /* We lost the race. Destroy the event we created and wait for the */
+ /* existing one to become signaled. */
+ CloseHandle(created_event);
+ result = WaitForSingleObject(existing_event, INFINITE);
+ assert(result == WAIT_OBJECT_0);
+ }
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ /* Fast case - avoid WaitForSingleObject. */
+ if (guard->ran) {
+ return;
+ }
+
+ uv__once_inner(guard, callback);
+}
+
+
+/* Verify that uv_thread_t can be stored in a TLS slot. */
+STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
+
+static uv_key_t uv__current_thread_key;
+static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
+
+
+static void uv__init_current_thread_key(void) {
+ if (uv_key_create(&uv__current_thread_key))
+ abort();
+}
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+ uv_thread_t self;
+};
+
+
+static UINT __stdcall uv__thread_start(void* arg) {
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ uv_key_set(&uv__current_thread_key, (void*) ctx.self);
+
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+ HANDLE thread;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ /* Create the thread in suspended state so we have a chance to pass
+ * its own creation handle to it */
+ thread = (HANDLE) _beginthreadex(NULL,
+ 0,
+ uv__thread_start,
+ ctx,
+ CREATE_SUSPENDED,
+ NULL);
+ if (thread == NULL) {
+ err = errno;
+ uv__free(ctx);
+ } else {
+ err = 0;
+ *tid = thread;
+ ctx->self = thread;
+ ResumeThread(thread);
+ }
+
+ switch (err) {
+ case 0:
+ return 0;
+ case EACCES:
+ return UV_EACCES;
+ case EAGAIN:
+ return UV_EAGAIN;
+ case EINVAL:
+ return UV_EINVAL;
+ }
+
+ return UV_EIO;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ return (uv_thread_t) uv_key_get(&uv__current_thread_key);
+}
+
+
+int uv_thread_join(uv_thread_t *tid) {
+ if (WaitForSingleObject(*tid, INFINITE))
+ return uv_translate_sys_error(GetLastError());
+ else {
+ CloseHandle(*tid);
+ *tid = 0;
+ return 0;
+ }
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return *t1 == *t2;
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ DeleteCriticalSection(mutex);
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ EnterCriticalSection(mutex);
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ if (TryEnterCriticalSection(mutex))
+ return 0;
+ else
+ return UV_EBUSY;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ LeaveCriticalSection(mutex);
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ /* Initialize the semaphore that acts as the write lock. */
+ HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
+ if (handle == NULL)
+ return uv_translate_sys_error(GetLastError());
+ rwlock->state_.write_semaphore_ = handle;
+
+ /* Initialize the critical section protecting the reader count. */
+ InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Initialize the reader count. */
+ rwlock->state_.num_readers_ = 0;
+
+ return 0;
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
+ CloseHandle(rwlock->state_.write_semaphore_);
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ /* Acquire the lock that protects the reader count. */
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Increase the reader count, and lock for write if this is the first
+ * reader.
+ */
+ if (++rwlock->state_.num_readers_ == 1) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+ }
+
+ /* Release the lock that protects the reader count. */
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
+ return UV_EBUSY;
+
+ err = 0;
+
+ if (rwlock->state_.num_readers_ == 0) {
+ /* Currently there are no other readers, which means that the write lock
+ * needs to be acquired.
+ */
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ rwlock->state_.num_readers_++;
+ else if (r == WAIT_TIMEOUT)
+ err = UV_EBUSY;
+ else if (r == WAIT_FAILED)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+
+ } else {
+ /* The write lock has already been acquired because there are other
+ * active readers.
+ */
+ rwlock->state_.num_readers_++;
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ return err;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ if (--rwlock->state_.num_readers_ == 0) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ return 0;
+ else if (r == WAIT_TIMEOUT)
+ return UV_EBUSY;
+ else
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+}
+
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
+ if (*sem == NULL)
+ return uv_translate_sys_error(GetLastError());
+ else
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (!CloseHandle(*sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (!ReleaseSemaphore(*sem, 1, NULL))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ DWORD r = WaitForSingleObject(*sem, 0);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+
+ if (r == WAIT_TIMEOUT)
+ return UV_EAGAIN;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+static int uv_cond_fallback_init(uv_cond_t* cond) {
+ int err;
+
+ /* Initialize the count to 0. */
+ cond->fallback.waiters_count = 0;
+
+ InitializeCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Create an auto-reset event. */
+ cond->fallback.signal_event = CreateEvent(NULL, /* no security */
+ FALSE, /* auto-reset event */
+ FALSE, /* non-signaled initially */
+ NULL); /* unnamed */
+ if (!cond->fallback.signal_event) {
+ err = GetLastError();
+ goto error2;
+ }
+
+ /* Create a manual-reset event. */
+ cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */
+ TRUE, /* manual-reset */
+ FALSE, /* non-signaled */
+ NULL); /* unnamed */
+ if (!cond->fallback.broadcast_event) {
+ err = GetLastError();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ CloseHandle(cond->fallback.signal_event);
+error2:
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv_cond_condvar_init(uv_cond_t* cond) {
+ pInitializeConditionVariable(&cond->cond_var);
+ return 0;
+}
+
+
+int uv_cond_init(uv_cond_t* cond) {
+ uv__once_init();
+
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_init(cond);
+ else
+ return uv_cond_fallback_init(cond);
+}
+
+
+static void uv_cond_fallback_destroy(uv_cond_t* cond) {
+ if (!CloseHandle(cond->fallback.broadcast_event))
+ abort();
+ if (!CloseHandle(cond->fallback.signal_event))
+ abort();
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+}
+
+
+static void uv_cond_condvar_destroy(uv_cond_t* cond) {
+ /* nothing to do */
+}
+
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_destroy(cond);
+ else
+ uv_cond_fallback_destroy(cond);
+}
+
+
+static void uv_cond_fallback_signal(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.signal_event);
+}
+
+
+static void uv_cond_condvar_signal(uv_cond_t* cond) {
+ pWakeConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_signal(cond);
+ else
+ uv_cond_fallback_signal(cond);
+}
+
+
+static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.broadcast_event);
+}
+
+
+static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
+ pWakeAllConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_broadcast(cond);
+ else
+ uv_cond_fallback_broadcast(cond);
+}
+
+
+static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
+ DWORD dwMilliseconds) {
+ DWORD result;
+ int last_waiter;
+ HANDLE handles[2] = {
+ cond->fallback.signal_event,
+ cond->fallback.broadcast_event
+ };
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count++;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* It's ok to release the <mutex> here since Win32 manual-reset events */
+ /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
+ /* bug. */
+ uv_mutex_unlock(mutex);
+
+ /* Wait for either event to become signaled due to <uv_cond_signal> being */
+ /* called or <uv_cond_broadcast> being called. */
+ result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
+
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count--;
+ last_waiter = result == WAIT_OBJECT_0 + 1
+ && cond->fallback.waiters_count == 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Some thread called <pthread_cond_broadcast>. */
+ if (last_waiter) {
+ /* We're the last waiter to be notified or to stop waiting, so reset the */
+ /* the manual-reset event. */
+ ResetEvent(cond->fallback.broadcast_event);
+ }
+
+ /* Reacquire the <mutex>. */
+ uv_mutex_lock(mutex);
+
+ if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
+ return 0;
+
+ if (result == WAIT_TIMEOUT)
+ return UV_ETIMEDOUT;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (uv_cond_wait_helper(cond, mutex, INFINITE))
+ abort();
+}
+
+
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
+ abort();
+}
+
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_wait(cond, mutex);
+ else
+ uv_cond_fallback_wait(cond, mutex);
+}
+
+
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
+}
+
+
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
+ return 0;
+ if (GetLastError() != ERROR_TIMEOUT)
+ abort();
+ return UV_ETIMEDOUT;
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
+ uint64_t timeout) {
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_timedwait(cond, mutex, timeout);
+ else
+ return uv_cond_fallback_timedwait(cond, mutex, timeout);
+}
+
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+
+int uv_key_create(uv_key_t* key) {
+ key->tls_index = TlsAlloc();
+ if (key->tls_index == TLS_OUT_OF_INDEXES)
+ return UV_ENOMEM;
+ return 0;
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (TlsFree(key->tls_index) == FALSE)
+ abort();
+ key->tls_index = TLS_OUT_OF_INDEXES;
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ void* value;
+
+ value = TlsGetValue(key->tls_index);
+ if (value == NULL)
+ if (GetLastError() != ERROR_SUCCESS)
+ abort();
+
+ return value;
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (TlsSetValue(key->tls_index, value) == FALSE)
+ abort();
+}
diff --git a/3rdparty/libuv/src/win/timer.c b/3rdparty/libuv/src/win/timer.c
new file mode 100644
index 00000000000..0da541a2c86
--- /dev/null
+++ b/3rdparty/libuv/src/win/timer.c
@@ -0,0 +1,200 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "tree.h"
+#include "handle-inl.h"
+
+
+/* The number of milliseconds in one second. */
+#define UV__MILLISEC 1000
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uint64_t new_time = uv__hrtime(UV__MILLISEC);
+ if (new_time > loop->time) {
+ loop->time = new_time;
+ }
+}
+
+void uv__time_forward(uv_loop_t* loop, uint64_t msecs) {
+ loop->time += msecs;
+}
+
+
+static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
+ if (a->due < b->due)
+ return -1;
+ if (a->due > b->due)
+ return 1;
+ /*
+ * compare start_id when both has the same due. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return -1;
+ if (a->start_id > b->start_id)
+ return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+
+ return 0;
+}
+
+
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
+ uint64_t clamped_timeout;
+
+ clamped_timeout = loop_time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ return clamped_timeout;
+}
+
+
+int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
+ uint64_t repeat) {
+ uv_loop_t* loop = handle->loop;
+ uv_timer_t* old;
+
+ if (timer_cb == NULL)
+ return UV_EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ handle->timer_cb = timer_cb;
+ handle->due = get_clamped_due_time(loop->time, timeout);
+ handle->repeat = repeat;
+ uv__handle_start(handle);
+
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
+ assert(old == NULL);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ /* If timer_cb is NULL that means that the timer was never started. */
+ if (!handle->timer_cb) {
+ return UV_EINVAL;
+ }
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ assert(handle->type == UV_TIMER);
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ assert(handle->type == UV_TIMER);
+ return handle->repeat;
+}
+
+
+DWORD uv__next_timeout(const uv_loop_t* loop) {
+ uv_timer_t* timer;
+ int64_t delta;
+
+ /* Check if there are any running timers
+ * Need to cast away const first, since RB_MIN doesn't know what we are
+ * going to do with this return value, it can't be marked const
+ */
+ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
+ if (timer) {
+ delta = timer->due - loop->time;
+ if (delta >= UINT_MAX - 1) {
+ /* A timeout value of UINT_MAX means infinite, so that's no good. */
+ return UINT_MAX - 1;
+ } else if (delta < 0) {
+ /* Negative timeout values are not allowed */
+ return 0;
+ } else {
+ return (DWORD)delta;
+ }
+ } else {
+ /* No timers */
+ return INFINITE;
+ }
+}
+
+
+void uv_process_timers(uv_loop_t* loop) {
+ uv_timer_t* timer;
+
+ /* Call timer callbacks */
+ for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
+ timer != NULL && timer->due <= loop->time;
+ timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
+
+ uv_timer_stop(timer);
+ uv_timer_again(timer);
+ timer->timer_cb((uv_timer_t*) timer);
+ }
+}
diff --git a/3rdparty/libuv/src/win/tty.c b/3rdparty/libuv/src/win/tty.c
new file mode 100644
index 00000000000..d87cc699097
--- /dev/null
+++ b/3rdparty/libuv/src/win/tty.c
@@ -0,0 +1,2084 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#ifndef COMMON_LVB_REVERSE_VIDEO
+# define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
+
+#define ANSI_NORMAL 0x00
+#define ANSI_ESCAPE_SEEN 0x02
+#define ANSI_CSI 0x04
+#define ANSI_ST_CONTROL 0x08
+#define ANSI_IGNORE 0x10
+#define ANSI_IN_ARG 0x20
+#define ANSI_IN_STRING 0x40
+#define ANSI_BACKSLASH_SEEN 0x80
+
+#define MAX_INPUT_BUFFER_LENGTH 8192
+
+
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
+
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+
+/*
+ * The console virtual window.
+ *
+ * Normally cursor movement in windows is relative to the console screen buffer,
+ * e.g. the application is allowed to overwrite the 'history'. This is very
+ * inconvenient, it makes absolute cursor movement pretty useless. There is
+ * also the concept of 'client rect' which is defined by the actual size of
+ * the console window and the scroll position of the screen buffer, but it's
+ * very volatile because it changes when the user scrolls.
+ *
+ * To make cursor movement behave sensibly we define a virtual window to which
+ * cursor movement is confined. The virtual window is always as wide as the
+ * console screen buffer, but it's height is defined by the size of the
+ * console window. The top of the virtual window aligns with the position
+ * of the caret when the first stdout/err handle is created, unless that would
+ * mean that it would extend beyond the bottom of the screen buffer - in that
+ * that case it's located as far down as possible.
+ *
+ * When the user writes a long text or many newlines, such that the output
+ * reaches beyond the bottom of the virtual window, the virtual window is
+ * shifted downwards, but not resized.
+ *
+ * Since all tty i/o happens on the same console, this window is shared
+ * between all stdout/stderr handles.
+ */
+
+static int uv_tty_virtual_offset = -1;
+static int uv_tty_virtual_height = -1;
+static int uv_tty_virtual_width = -1;
+
+static CRITICAL_SECTION uv_tty_output_lock;
+
+static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
+
+static WORD uv_tty_default_text_attributes =
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+static char uv_tty_default_fg_color = 7;
+static char uv_tty_default_bg_color = 0;
+static char uv_tty_default_fg_bright = 0;
+static char uv_tty_default_bg_bright = 0;
+static char uv_tty_default_inverse = 0;
+
+
+void uv_console_init() {
+ InitializeCriticalSection(&uv_tty_output_lock);
+}
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+
+ handle = (HANDLE) uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (fd <= 2) {
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ handle,
+ INVALID_HANDLE_VALUE,
+ &handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ fd = -1;
+ }
+
+ if (!readable) {
+ /* Obtain the screen buffer info with the output handle. */
+ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Obtain the the tty_output_lock because the virtual window state is */
+ /* shared between all uv_tty_t handles. */
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ /* Store the global tty output handle. This handle is used by TTY read */
+ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
+ /* is received. */
+ uv_tty_output_handle = handle;
+
+ /* Remember the original console text attributes. */
+ uv_tty_capture_initial_style(&screen_buffer_info);
+
+ uv_tty_update_virtual_window(&screen_buffer_info);
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+ }
+
+
+ uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+ uv_connection_init((uv_stream_t*) tty);
+
+ tty->handle = handle;
+ tty->u.fd = fd;
+ tty->reqs_pending = 0;
+ tty->flags |= UV_HANDLE_BOUND;
+
+ if (readable) {
+ /* Initialize TTY input specific fields. */
+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
+ tty->tty.rd.read_line_handle = NULL;
+ tty->tty.rd.read_line_buffer = uv_null_buf_;
+ tty->tty.rd.read_raw_wait = NULL;
+
+ /* Init keycode-to-vt100 mapper state. */
+ tty->tty.rd.last_key_len = 0;
+ tty->tty.rd.last_key_offset = 0;
+ tty->tty.rd.last_utf16_high_surrogate = 0;
+ memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
+ } else {
+ /* TTY output specific fields. */
+ tty->flags |= UV_HANDLE_WRITABLE;
+
+ /* Init utf8-to-utf16 conversion state. */
+ tty->tty.wr.utf8_bytes_left = 0;
+ tty->tty.wr.utf8_codepoint = 0;
+
+ /* Initialize eol conversion state */
+ tty->tty.wr.previous_eol = 0;
+
+ /* Init ANSI parser state. */
+ tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
+ }
+
+ return 0;
+}
+
+
+/* Set the default console text attributes based on how the console was
+ * configured when libuv started.
+ */
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ static int style_captured = 0;
+
+ /* Only do this once.
+ Assumption: Caller has acquired uv_tty_output_lock. */
+ if (style_captured)
+ return;
+
+ /* Save raw win32 attributes. */
+ uv_tty_default_text_attributes = info->wAttributes;
+
+ /* Convert black text on black background to use white text. */
+ if (uv_tty_default_text_attributes == 0)
+ uv_tty_default_text_attributes = 7;
+
+ /* Convert Win32 attributes to ANSI colors. */
+ uv_tty_default_fg_color = 0;
+ uv_tty_default_bg_color = 0;
+ uv_tty_default_fg_bright = 0;
+ uv_tty_default_bg_bright = 0;
+ uv_tty_default_inverse = 0;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_RED)
+ uv_tty_default_fg_color |= 1;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
+ uv_tty_default_fg_color |= 2;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
+ uv_tty_default_fg_color |= 4;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_RED)
+ uv_tty_default_bg_color |= 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
+ uv_tty_default_bg_color |= 2;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
+ uv_tty_default_bg_color |= 4;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
+ uv_tty_default_fg_bright = 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
+ uv_tty_default_bg_bright = 1;
+
+ if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
+ uv_tty_default_inverse = 1;
+
+ style_captured = 1;
+}
+
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ DWORD flags;
+ unsigned char was_reading;
+ uv_alloc_cb alloc_cb;
+ uv_read_cb read_cb;
+ int err;
+
+ if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
+ return UV_EINVAL;
+ }
+
+ if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
+ return 0;
+ }
+
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ break;
+ case UV_TTY_MODE_RAW:
+ flags = ENABLE_WINDOW_INPUT;
+ break;
+ case UV_TTY_MODE_IO:
+ return UV_ENOTSUP;
+ }
+
+ if (!SetConsoleMode(tty->handle, flags)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* If currently reading, stop, and restart reading. */
+ if (tty->flags & UV_HANDLE_READING) {
+ was_reading = 1;
+ alloc_cb = tty->alloc_cb;
+ read_cb = tty->read_cb;
+
+ if (was_reading) {
+ err = uv_tty_read_stop(tty);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+ } else {
+ was_reading = 0;
+ }
+
+ /* Update flag. */
+ tty->flags &= ~UV_HANDLE_TTY_RAW;
+ tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
+
+ /* If we just stopped reading, restart. */
+ if (was_reading) {
+ err = uv_tty_read_start(tty, alloc_cb, read_cb);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_is_tty(uv_file file) {
+ DWORD result;
+ return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ EnterCriticalSection(&uv_tty_output_lock);
+ uv_tty_update_virtual_window(&info);
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ *width = uv_tty_virtual_width;
+ *height = uv_tty_virtual_height;
+
+ return 0;
+}
+
+
+static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+
+ assert(data);
+ assert(!didTimeout);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ UnregisterWait(handle->tty.rd.read_raw_wait);
+ handle->tty.rd.read_raw_wait = NULL;
+
+ SET_REQ_SUCCESS(req);
+ POST_COMPLETION_FOR_REQ(loop, req);
+}
+
+
+static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
+ handle->handle,
+ uv_tty_post_raw_read,
+ (void*) req,
+ INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!r) {
+ handle->tty.rd.read_raw_wait = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+ DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
+
+ assert(data);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+ assert(handle->tty.rd.read_line_buffer.len > 0);
+
+ /* ReadConsole can't handle big buffers. */
+ if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
+ bytes = handle->tty.rd.read_line_buffer.len;
+ } else {
+ bytes = MAX_INPUT_BUFFER_LENGTH;
+ }
+
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ if (ReadConsoleW(handle->tty.rd.read_line_handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
+ NULL)) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->tty.rd.read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = read_bytes;
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle,
+ UV_ENOBUFS,
+ &handle->tty.rd.read_line_buffer);
+ return;
+ }
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+
+ /* Duplicate the console handle, so if we want to cancel the read, we can */
+ /* just close this handle duplicate. */
+ if (handle->tty.rd.read_line_handle == NULL) {
+ HANDLE this_process = GetCurrentProcess();
+ r = DuplicateHandle(this_process,
+ handle->handle,
+ this_process,
+ &handle->tty.rd.read_line_handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ if (!r) {
+ handle->tty.rd.read_line_handle = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ goto out;
+ }
+ }
+
+ r = QueueUserWorkItem(uv_tty_line_read_thread,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION);
+ if (!r) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ out:
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ uv_tty_queue_read_raw(loop, handle);
+ } else {
+ uv_tty_queue_read_line(loop, handle);
+ }
+}
+
+
+static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
+ size_t* len) {
+#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
+ case (vk): \
+ if (shift && ctrl) { \
+ *len = sizeof shift_ctrl_str; \
+ return "\033" shift_ctrl_str; \
+ } else if (shift) { \
+ *len = sizeof shift_str ; \
+ return "\033" shift_str; \
+ } else if (ctrl) { \
+ *len = sizeof ctrl_str; \
+ return "\033" ctrl_str; \
+ } else { \
+ *len = sizeof normal_str; \
+ return "\033" normal_str; \
+ }
+
+ switch (code) {
+ /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
+ /* keypad keys comply with linux console, modifiers comply with xterm */
+ /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
+ /* f6..f12 with and without modifiers comply with rxvt. */
+ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
+ VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
+ VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
+ VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
+ VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
+ VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
+ VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
+ VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
+ VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
+ VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
+ VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
+ VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
+
+ default:
+ *len = 0;
+ return NULL;
+ }
+#undef VK_CASE
+}
+
+
+void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
+#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
+
+ DWORD records_left, records_read;
+ uv_buf_t buf;
+ off_t buf_used;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!(handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_TTY_RAW)) {
+ goto out;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred while waiting for the event. */
+ if ((handle->flags & UV_HANDLE_READING)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &uv_null_buf_);
+ }
+ goto out;
+ }
+
+ /* Fetch the number of events */
+ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GetLastError()),
+ &uv_null_buf_);
+ goto out;
+ }
+
+ /* Windows sends a lot of events that we're not interested in, so buf */
+ /* will be allocated on demand, when there's actually something to emit. */
+ buf = uv_null_buf_;
+ buf_used = 0;
+
+ while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
+ (handle->flags & UV_HANDLE_READING)) {
+ if (handle->tty.rd.last_key_len == 0) {
+ /* Read the next input record */
+ if (!ReadConsoleInputW(handle->handle,
+ &handle->tty.rd.last_input_record,
+ 1,
+ &records_read)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+ records_left--;
+
+ /* If the window was resized, recompute the virtual window size. This */
+ /* will trigger a SIGWINCH signal if the window size changed in an */
+ /* way that matters to libuv. */
+ if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
+ uv_tty_update_virtual_window(&info);
+ }
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ continue;
+ }
+
+ /* Ignore other events that are not key or resize events. */
+ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
+ continue;
+ }
+
+ /* Ignore keyup events, unless the left alt key was held and a valid */
+ /* unicode character was emitted. */
+ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
+ KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
+ continue;
+ }
+
+ /* Ignore keypresses to numpad number keys if the left alt is held */
+ /* because the user is composing a character, or windows simulating */
+ /* this. */
+ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
+ !(KEV.dwControlKeyState & ENHANCED_KEY) &&
+ (KEV.wVirtualKeyCode == VK_INSERT ||
+ KEV.wVirtualKeyCode == VK_END ||
+ KEV.wVirtualKeyCode == VK_DOWN ||
+ KEV.wVirtualKeyCode == VK_NEXT ||
+ KEV.wVirtualKeyCode == VK_LEFT ||
+ KEV.wVirtualKeyCode == VK_CLEAR ||
+ KEV.wVirtualKeyCode == VK_RIGHT ||
+ KEV.wVirtualKeyCode == VK_HOME ||
+ KEV.wVirtualKeyCode == VK_UP ||
+ KEV.wVirtualKeyCode == VK_PRIOR ||
+ KEV.wVirtualKeyCode == VK_NUMPAD0 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD1 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD2 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD3 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD4 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD5 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD6 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD7 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD8 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD9)) {
+ continue;
+ }
+
+ if (KEV.uChar.UnicodeChar != 0) {
+ int prefix_len, char_len;
+
+ /* Character key pressed */
+ if (KEV.uChar.UnicodeChar >= 0xD800 &&
+ KEV.uChar.UnicodeChar < 0xDC00) {
+ /* UTF-16 high surrogate */
+ handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
+ continue;
+ }
+
+ /* Prefix with \u033 if alt was held, but alt was not used as part */
+ /* a compose sequence. */
+ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ if (KEV.uChar.UnicodeChar >= 0xDC00 &&
+ KEV.uChar.UnicodeChar < 0xE000) {
+ /* UTF-16 surrogate pair */
+ WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
+ KEV.uChar.UnicodeChar};
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ 2,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ } else {
+ /* Single UTF-16 character */
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ &KEV.uChar.UnicodeChar,
+ 1,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ }
+
+ /* Whatever happened, the last character wasn't a high surrogate. */
+ handle->tty.rd.last_utf16_high_surrogate = 0;
+
+ /* If the utf16 character(s) couldn't be converted something must */
+ /* be wrong. */
+ if (!char_len) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+
+ } else {
+ /* Function key pressed */
+ const char* vt100;
+ size_t prefix_len, vt100_len;
+
+ vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
+ !!(KEV.dwControlKeyState & SHIFT_PRESSED),
+ !!(KEV.dwControlKeyState & (
+ LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)),
+ &vt100_len);
+
+ /* If we were unable to map to a vt100 sequence, just ignore. */
+ if (!vt100) {
+ continue;
+ }
+
+ /* Prefix with \x033 when the alt key was held. */
+ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ /* Copy the vt100 sequence to the handle buffer. */
+ assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
+ memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+ } else {
+ /* Copy any bytes left from the last keypress to the user buffer. */
+ if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
+ /* Allocate a buffer if needed */
+ if (buf_used == 0) {
+ handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ goto out;
+ }
+ assert(buf.base != NULL);
+ }
+
+ buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
+
+ /* If the buffer is full, emit it */
+ if ((size_t) buf_used == buf.len) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ buf = uv_null_buf_;
+ buf_used = 0;
+ }
+
+ continue;
+ }
+
+ /* Apply dwRepeat from the last input record. */
+ if (--KEV.wRepeatCount > 0) {
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+
+ handle->tty.rd.last_key_len = 0;
+ continue;
+ }
+ }
+
+ /* Send the buffer back to the user */
+ if (buf_used > 0) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ }
+
+ out:
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+
+#undef KEV
+}
+
+
+
+void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ buf = handle->tty.rd.read_line_buffer;
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ if (!REQ_SUCCESS(req)) {
+ /* Read was not successful */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ handle->tty.rd.read_line_handle != NULL) {
+ /* Real error */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &buf);
+ } else {
+ /* The read was cancelled, or whatever we don't care */
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+
+ } else {
+ /* Read successful */
+ /* TODO: read unicode, convert to utf-8 */
+ DWORD bytes = req->u.io.overlapped.InternalHigh;
+ handle->read_cb((uv_stream_t*) handle, bytes, &buf);
+ }
+
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ /* If the read_line_buffer member is zero, it must have been an raw read. */
+ /* Otherwise it was a line-buffered read. */
+ /* FIXME: This is quite obscure. Use a flag or something. */
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ uv_process_tty_read_raw_req(loop, handle, req);
+ } else {
+ uv_process_tty_read_line_req(loop, handle, req);
+ }
+}
+
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ return 0;
+ }
+
+ /* Maybe the user stopped reading half-way while processing key events. */
+ /* Short-circuit if this could be the case. */
+ if (handle->tty.rd.last_key_len > 0) {
+ SET_REQ_SUCCESS(&handle->read_req);
+ uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+ return 0;
+ }
+
+ uv_tty_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+int uv_tty_read_stop(uv_tty_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+
+ /* Cancel raw read */
+ if ((handle->flags & UV_HANDLE_READ_PENDING) &&
+ (handle->flags & UV_HANDLE_TTY_RAW)) {
+ /* Write some bullshit event to force the console wait to return. */
+ INPUT_RECORD record;
+ DWORD written;
+ memset(&record, 0, sizeof record);
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
+ return GetLastError();
+ }
+ }
+
+ /* Cancel line-buffered read */
+ if (handle->tty.rd.read_line_handle != NULL) {
+ /* Closing this handle will cancel the ReadConsole operation */
+ CloseHandle(handle->tty.rd.read_line_handle);
+ handle->tty.rd.read_line_handle = NULL;
+ }
+
+
+ return 0;
+}
+
+
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ int old_virtual_width = uv_tty_virtual_width;
+ int old_virtual_height = uv_tty_virtual_height;
+
+ uv_tty_virtual_width = info->dwSize.X;
+ uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
+
+ /* Recompute virtual window offset row. */
+ if (uv_tty_virtual_offset == -1) {
+ uv_tty_virtual_offset = info->dwCursorPosition.Y;
+ } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1) {
+ /* If suddenly find the cursor outside of the virtual window, it must */
+ /* have somehow scrolled. Update the virtual window offset. */
+ uv_tty_virtual_offset = info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1;
+ }
+ if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
+ uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
+ }
+ if (uv_tty_virtual_offset < 0) {
+ uv_tty_virtual_offset = 0;
+ }
+
+ /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
+ /* if this was the first time the virtual window size was computed. */
+ if (old_virtual_width != -1 && old_virtual_height != -1 &&
+ (uv_tty_virtual_width != old_virtual_width ||
+ uv_tty_virtual_height != old_virtual_height)) {
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
+
+
+static COORD uv_tty_make_real_coord(uv_tty_t* handle,
+ CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
+ unsigned char y_relative) {
+ COORD result;
+
+ uv_tty_update_virtual_window(info);
+
+ /* Adjust y position */
+ if (y_relative) {
+ y = info->dwCursorPosition.Y + y;
+ } else {
+ y = uv_tty_virtual_offset + y;
+ }
+ /* Clip y to virtual client rectangle */
+ if (y < uv_tty_virtual_offset) {
+ y = uv_tty_virtual_offset;
+ } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
+ y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
+ }
+
+ /* Adjust x */
+ if (x_relative) {
+ x = info->dwCursorPosition.X + x;
+ }
+ /* Clip x */
+ if (x < 0) {
+ x = 0;
+ } else if (x >= uv_tty_virtual_width) {
+ x = uv_tty_virtual_width - 1;
+ }
+
+ result.X = (unsigned short) x;
+ result.Y = (unsigned short) y;
+ return result;
+}
+
+
+static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
+ DWORD* error) {
+ DWORD written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!WriteConsoleW(handle->handle,
+ (void*) buffer,
+ length,
+ &written,
+ NULL)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
+ int y, unsigned char y_relative, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD pos;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ }
+
+ pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
+
+ if (!SetConsoleCursorPosition(handle->handle, pos)) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
+ const COORD origin = {0, 0};
+ const WORD char_attrs = uv_tty_default_text_attributes;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ DWORD count, written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ /* Reset original text attributes. */
+ if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Move the cursor position to (0, 0). */
+ if (!SetConsoleCursorPosition(handle->handle, origin)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Clear the screen buffer. */
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ count = info.dwSize.X * info.dwSize.Y;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ origin,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ char_attrs,
+ written,
+ origin,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ /* Move the virtual window up to the top. */
+ uv_tty_virtual_offset = 0;
+ uv_tty_update_virtual_window(&info);
+
+ return 0;
+}
+
+
+static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD start, end;
+ DWORD count, written;
+
+ int x1, x2, y1, y2;
+ int x1r, x2r, y1r, y2r;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (dir == 0) {
+ /* Clear from current position */
+ x1 = 0;
+ x1r = 1;
+ } else {
+ /* Clear from column 0 */
+ x1 = 0;
+ x1r = 0;
+ }
+
+ if (dir == 1) {
+ /* Clear to current position */
+ x2 = 0;
+ x2r = 1;
+ } else {
+ /* Clear to end of row. We pretend the console is 65536 characters wide, */
+ /* uv_tty_make_real_coord will clip it to the actual console width. */
+ x2 = 0xffff;
+ x2r = 0;
+ }
+
+ if (!entire_screen) {
+ /* Stay on our own row */
+ y1 = y2 = 0;
+ y1r = y2r = 1;
+ } else {
+ /* Apply columns direction to row */
+ y1 = x1;
+ y1r = x1r;
+ y2 = x2;
+ y2r = x2r;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
+ end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
+ count = (end.Y * info.dwSize.X + end.X) -
+ (start.Y * info.dwSize.X + start.X) + 1;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ start,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ info.wAttributes,
+ written,
+ start,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
+
+static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
+ unsigned short argc = handle->tty.wr.ansi_csi_argc;
+ unsigned short* argv = handle->tty.wr.ansi_csi_argv;
+ int i;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ char fg_color = -1, bg_color = -1;
+ char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
+
+ if (argc == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+ }
+
+ for (i = 0; i < argc; i++) {
+ short arg = argv[i];
+
+ if (arg == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+
+ } else if (arg == 1) {
+ /* Foreground bright on */
+ fg_bright = 1;
+
+ } else if (arg == 2) {
+ /* Both bright off */
+ fg_bright = 0;
+ bg_bright = 0;
+
+ } else if (arg == 5) {
+ /* Background bright on */
+ bg_bright = 1;
+
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
+ } else if (arg == 21 || arg == 22) {
+ /* Foreground bright off */
+ fg_bright = 0;
+
+ } else if (arg == 25) {
+ /* Background bright off */
+ bg_bright = 0;
+
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
+ } else if (arg >= 30 && arg <= 37) {
+ /* Set foreground color */
+ fg_color = arg - 30;
+
+ } else if (arg == 39) {
+ /* Default text color */
+ fg_color = uv_tty_default_fg_color;
+ fg_bright = uv_tty_default_fg_bright;
+
+ } else if (arg >= 40 && arg <= 47) {
+ /* Set background color */
+ bg_color = arg - 40;
+
+ } else if (arg == 49) {
+ /* Default background color */
+ bg_color = uv_tty_default_bg_color;
+ bg_bright = uv_tty_default_bg_bright;
+
+ } else if (arg >= 90 && arg <= 97) {
+ /* Set bold foreground color */
+ fg_bright = 1;
+ fg_color = arg - 90;
+
+ } else if (arg >= 100 && arg <= 107) {
+ /* Set bold background color */
+ bg_bright = 1;
+ bg_color = arg - 100;
+
+ }
+ }
+
+ if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
+ bg_bright == -1 && inverse == -1) {
+ /* Nothing changed */
+ return 0;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (fg_color != -1) {
+ info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
+ if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
+ if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
+ }
+
+ if (fg_bright != -1) {
+ if (fg_bright) {
+ info.wAttributes |= FOREGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~FOREGROUND_INTENSITY;
+ }
+ }
+
+ if (bg_color != -1) {
+ info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
+ if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
+ if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
+ if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
+ }
+
+ if (bg_bright != -1) {
+ if (bg_bright) {
+ info.wAttributes |= BACKGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~BACKGROUND_INTENSITY;
+ }
+ }
+
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ uv_tty_update_virtual_window(&info);
+
+ handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
+ handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+ handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
+
+ if (save_attributes) {
+ handle->tty.wr.saved_attributes = info.wAttributes &
+ (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_restore_state(uv_tty_t* handle,
+ unsigned char restore_attributes, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD new_attributes;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
+ if (uv_tty_move_caret(handle,
+ handle->tty.wr.saved_position.X,
+ 0,
+ handle->tty.wr.saved_position.Y,
+ 0,
+ error) != 0) {
+ return -1;
+ }
+ }
+
+ if (restore_attributes &&
+ (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ new_attributes = info.wAttributes;
+ new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ new_attributes |= handle->tty.wr.saved_attributes;
+
+ if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uv_tty_write_bufs(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ DWORD* error) {
+ /* We can only write 8k characters at a time. Windows can't handle */
+ /* much more characters in a single console write anyway. */
+ WCHAR utf16_buf[8192];
+ DWORD utf16_buf_used = 0;
+ unsigned int i;
+
+#define FLUSH_TEXT() \
+ do { \
+ if (utf16_buf_used > 0) { \
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
+ utf16_buf_used = 0; \
+ } \
+ } while (0)
+
+#define ENSURE_BUFFER_SPACE(wchars_needed) \
+ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
+ FLUSH_TEXT(); \
+ }
+
+ /* Cache for fast access */
+ unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
+ unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
+ unsigned char previous_eol = handle->tty.wr.previous_eol;
+ unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
+
+ /* Store the error here. If we encounter an error, stop trying to do i/o */
+ /* but keep parsing the buffer so we leave the parser in a consistent */
+ /* state. */
+ *error = ERROR_SUCCESS;
+
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ for (i = 0; i < nbufs; i++) {
+ uv_buf_t buf = bufs[i];
+ unsigned int j;
+
+ for (j = 0; j < buf.len; j++) {
+ unsigned char c = buf.base[j];
+
+ /* Run the character through the utf8 decoder We happily accept non */
+ /* shortest form encodings and invalid code points - there's no real */
+ /* harm that can be done. */
+ if (utf8_bytes_left == 0) {
+ /* Read utf-8 start byte */
+ DWORD first_zero_bit;
+ unsigned char not_c = ~c;
+#ifdef _MSC_VER /* msvc */
+ if (_BitScanReverse(&first_zero_bit, not_c)) {
+#else /* assume gcc */
+ if (c != 0) {
+ first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
+#endif
+ if (first_zero_bit == 7) {
+ /* Ascii - pass right through */
+ utf8_codepoint = (unsigned int) c;
+
+ } else if (first_zero_bit <= 5) {
+ /* Multibyte sequence */
+ utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
+ utf8_bytes_left = (char) (6 - first_zero_bit);
+
+ } else {
+ /* Invalid continuation */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else {
+ /* 0xff -- invalid */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else if ((c & 0xc0) == 0x80) {
+ /* Valid continuation of utf-8 multibyte sequence */
+ utf8_bytes_left--;
+ utf8_codepoint <<= 6;
+ utf8_codepoint |= ((unsigned int) c & 0x3f);
+
+ } else {
+ /* Start byte where continuation was expected. */
+ utf8_bytes_left = 0;
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ /* Patch buf offset so this character will be parsed again as a */
+ /* start byte. */
+ j--;
+ }
+
+ /* Maybe we need to parse more bytes to find a character. */
+ if (utf8_bytes_left != 0) {
+ continue;
+ }
+
+ /* Parse vt100/ansi escape codes */
+ if (ansi_parser_state == ANSI_NORMAL) {
+ switch (utf8_codepoint) {
+ case '\033':
+ ansi_parser_state = ANSI_ESCAPE_SEEN;
+ continue;
+
+ case 0233:
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+ }
+
+ } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
+ switch (utf8_codepoint) {
+ case '[':
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+
+ case '^':
+ case '_':
+ case 'P':
+ case ']':
+ /* Not supported, but we'll have to parse until we see a stop */
+ /* code, e.g. ESC \ or BEL. */
+ ansi_parser_state = ANSI_ST_CONTROL;
+ continue;
+
+ case '\033':
+ /* Ignore double escape. */
+ continue;
+
+ case 'c':
+ /* Full console reset. */
+ FLUSH_TEXT();
+ uv_tty_reset(handle, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '7':
+ /* Save the cursor position and text attributes. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '8':
+ /* Restore the cursor position and text attributes */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ default:
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
+ /* Single-char control. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+ } else {
+ /* Invalid - proceed as normal, */
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ }
+
+ } else if (ansi_parser_state & ANSI_CSI) {
+ if (!(ansi_parser_state & ANSI_IGNORE)) {
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
+ /* Parsing a numerical argument */
+
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
+ /* We were not currently parsing a number */
+
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ ansi_parser_state |= ANSI_IN_ARG;
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) utf8_codepoint - '0';
+ continue;
+ } else {
+ /* We were already parsing a number. Parse next digit. */
+ uint32_t value = 10 *
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
+
+ /* Check for overflow. */
+ if (value > UINT16_MAX) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) value + (utf8_codepoint - '0');
+ continue;
+ }
+
+ } else if (utf8_codepoint == ';') {
+ /* Denotes the end of an argument. */
+ if (ansi_parser_state & ANSI_IN_ARG) {
+ ansi_parser_state &= ~ANSI_IN_ARG;
+ continue;
+
+ } else {
+ /* If ANSI_IN_ARG is not set, add another argument and */
+ /* default it to 0. */
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
+ continue;
+ }
+
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->tty.wr.ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
+ (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
+ int x, y, d;
+
+ /* Command byte */
+ switch (utf8_codepoint) {
+ case 'A':
+ /* cursor up */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'B':
+ /* cursor down */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'C':
+ /* cursor forward */
+ FLUSH_TEXT();
+ x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'D':
+ /* cursor back */
+ FLUSH_TEXT();
+ x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'E':
+ /* cursor next line */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'F':
+ /* cursor previous line */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'G':
+ /* cursor horizontal move absolute */
+ FLUSH_TEXT();
+ x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, 0, 1, error);
+ break;
+
+ case 'H':
+ case 'f':
+ /* cursor move absolute */
+ FLUSH_TEXT();
+ y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+ ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, y, 0, error);
+ break;
+
+ case 'J':
+ /* Erase screen */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 1, error);
+ }
+ break;
+
+ case 'K':
+ /* Erase line */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 0, error);
+ }
+ break;
+
+ case 'm':
+ /* Set style */
+ FLUSH_TEXT();
+ uv_tty_set_style(handle, error);
+ break;
+
+ case 's':
+ /* Save the cursor position. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 0, error);
+ break;
+
+ case 'u':
+ /* Restore the cursor position */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 0, error);
+ break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
+ }
+
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ } else {
+ /* We don't support commands that use private mode characters or */
+ /* intermediaries. Ignore the rest of the sequence. */
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+ } else {
+ /* We're ignoring this command. Stop only on command character. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ continue;
+ }
+
+ } else if (ansi_parser_state & ANSI_ST_CONTROL) {
+ /* Unsupported control code */
+ /* Ignore everything until we see BEL or ESC \ */
+ if (ansi_parser_state & ANSI_IN_STRING) {
+ if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
+ if (utf8_codepoint == '"') {
+ ansi_parser_state &= ~ANSI_IN_STRING;
+ } else if (utf8_codepoint == '\\') {
+ ansi_parser_state |= ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
+ (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
+ /* End of sequence */
+ ansi_parser_state = ANSI_NORMAL;
+ } else if (utf8_codepoint == '\033') {
+ /* Escape character */
+ ansi_parser_state |= ANSI_ESCAPE_SEEN;
+ } else if (utf8_codepoint == '"') {
+ /* String starting */
+ ansi_parser_state |= ANSI_IN_STRING;
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ } else {
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ }
+ }
+ continue;
+ } else {
+ /* Inconsistent state */
+ abort();
+ }
+
+ /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
+ /* windows console doesn't really support UTF-16, so just emit the */
+ /* replacement character. */
+ if (utf8_codepoint > 0xffff) {
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
+ /* EOL conversion - emit \r\n when we see \n. */
+
+ if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
+ /* \n was not preceded by \r; print \r\n. */
+ ENSURE_BUFFER_SPACE(2);
+ utf16_buf[utf16_buf_used++] = L'\r';
+ utf16_buf[utf16_buf_used++] = L'\n';
+ } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
+ /* \n was followed by \r; do not print the \r, since */
+ /* the source was either \r\n\r (so the second \r is */
+ /* redundant) or was \n\r (so the \n was processed */
+ /* by the last case and an \r automatically inserted). */
+ } else {
+ /* \r without \n; print \r as-is. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ }
+
+ previous_eol = (char) utf8_codepoint;
+
+ } else if (utf8_codepoint <= 0xffff) {
+ /* Encode character into utf-16 buffer. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ previous_eol = 0;
+ }
+ }
+ }
+
+ /* Flush remaining characters */
+ FLUSH_TEXT();
+
+ /* Copy cached values back to struct. */
+ handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
+ handle->tty.wr.utf8_codepoint = utf8_codepoint;
+ handle->tty.wr.previous_eol = previous_eol;
+ handle->tty.wr.ansi_parser_state = ansi_parser_state;
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ if (*error == STATUS_SUCCESS) {
+ return 0;
+ } else {
+ return -1;
+ }
+
+#undef FLUSH_TEXT
+}
+
+
+int uv_tty_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ DWORD error;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ req->u.io.queued_bytes = 0;
+
+ if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, error);
+ }
+
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+
+ return 0;
+}
+
+
+int uv__tty_try_write(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ DWORD error;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
+ return uv_translate_sys_error(error);
+
+ return uv__count_bufs(bufs, nbufs);
+}
+
+
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ handle->write_queue_size -= req->u.io.queued_bytes;
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_tty_close(uv_tty_t* handle) {
+ assert(handle->u.fd == -1 || handle->u.fd > 2);
+ if (handle->u.fd == -1)
+ CloseHandle(handle->handle);
+ else
+ close(handle->u.fd);
+
+ if (handle->flags & UV_HANDLE_READING)
+ uv_tty_read_stop(handle);
+
+ handle->u.fd = -1;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(handle->loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ /* TTY shutdown is really just a no-op */
+ if (handle->stream.conn.shutdown_req->cb) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
+ } else {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
+ }
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ /* The console handle duplicate used for line reading should be destroyed */
+ /* by uv_tty_read_stop. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_line_handle == NULL);
+
+ /* The wait handle used for raw reading should be unregistered when the */
+ /* wait callback runs. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_raw_wait == NULL);
+
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req) {
+ abort();
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req) {
+ abort();
+}
+
+
+int uv_tty_reset_mode(void) {
+ /* Not necessary to do anything. */
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/udp.c b/3rdparty/libuv/src/win/udp.c
new file mode 100644
index 00000000000..24792ec067e
--- /dev/null
+++ b/3rdparty/libuv/src/win/udp.c
@@ -0,0 +1,926 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active udp streams for which to preallocate udp read buffers.
+ */
+const unsigned int uv_active_udp_streams_threshold = 0;
+
+/* A zero-size buffer for use by uv_udp_read */
+static char uv_zero_[] = "";
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
+ int family) {
+ DWORD yes = 1;
+ WSAPROTOCOL_INFOW info;
+ int opt_len;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
+ return GetLastError();
+ }
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ return GetLastError();
+ }
+
+ if (pSetFileCompletionNotificationModes) {
+ /* All known Windows that support SetFileCompletionNotificationModes */
+ /* have a bug that makes it impossible to use this function in */
+ /* conjunction with datagram sockets. We can work around that but only */
+ /* if the user is using the default UDP driver (AFD) and has no other */
+ /* LSPs stacked on top. Here we check whether that is the case. */
+ opt_len = (int) sizeof info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &info,
+ &opt_len) == SOCKET_ERROR) {
+ return GetLastError();
+ }
+
+ if (info.ProtocolChain.ChainLen == 1) {
+ if (pSetFileCompletionNotificationModes((HANDLE)socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ handle->func_wsarecv = uv_wsarecv_workaround;
+ handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->activecnt = 0;
+ handle->func_wsarecv = WSARecv;
+ handle->func_wsarecvfrom = WSARecvFrom;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
+ handle->recv_req.type = UV_UDP_RECV;
+ handle->recv_req.data = handle;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_udp_recv_stop(handle);
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static int uv_udp_maybe_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int r;
+ int err;
+ DWORD no = 0;
+
+ if (handle->flags & UV_HANDLE_BOUND)
+ return 0;
+
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
+ /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ DWORD yes = 1;
+ /* Set SO_REUSEADDR on the socket. */
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (char*) &yes,
+ sizeof yes) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ return err;
+ }
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
+ /* On windows IPV6ONLY is on by default. */
+ /* If the user doesn't specify it libuv turns it off. */
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (char*) &no,
+ sizeof no);
+ }
+
+ r = bind(handle->socket, addr, addrlen);
+ if (r == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_req_t* req;
+ uv_buf_t buf;
+ DWORD bytes, flags;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->recv_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
+ if (handle->recv_buffer.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
+ return;
+ }
+ assert(handle->recv_buffer.base != NULL);
+
+ buf = handle->recv_buffer;
+ memset(&handle->recv_from, 0, sizeof handle->recv_from);
+ handle->recv_from_len = sizeof handle->recv_from;
+ flags = 0;
+
+ result = handle->func_wsarecvfrom(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &handle->recv_from,
+ &handle->recv_from_len,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+
+ buf.base = (char*) uv_zero_;
+ buf.len = 0;
+ flags = MSG_PEEK;
+
+ result = handle->func_wsarecv(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+ }
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEALREADY;
+ }
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ loop->active_udp_streams++;
+
+ handle->recv_cb = recv_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* recv request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_udp_queue_recv(loop, handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->loop->active_udp_streams--;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ DWORD result, bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_UDP_SEND;
+ req->handle = handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ result = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ addr,
+ addrlen,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ /* Send failed due to an error. */
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+ int partial;
+
+ assert(handle->type == UV_UDP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ DWORD err = GET_REQ_SOCK_ERROR(req);
+ if (err == WSAEMSGSIZE) {
+ /* Not a real error, it just indicates that the received packet */
+ /* was bigger than the receive buffer. */
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* A previous sendto operation failed; ignore this error. If */
+ /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
+ /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
+ /* immediately queue a new receive. */
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ goto done;
+ }
+ } else {
+ /* A real error occurred. Report the error to the user only if we're */
+ /* currently reading. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_udp_recv_stop(handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->recv_buffer;
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ goto done;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* Successful read */
+ partial = !REQ_SUCCESS(req);
+ handle->recv_cb(handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->recv_buffer,
+ (const struct sockaddr*) &handle->recv_from,
+ partial ? UV_UDP_PARTIAL : 0);
+ } else if (handle->flags & UV_HANDLE_READING) {
+ DWORD bytes, err, flags;
+ struct sockaddr_storage from;
+ int from_len;
+
+ /* Do a nonblocking receive */
+ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ goto done;
+ }
+ assert(buf.base != NULL);
+
+ memset(&from, 0, sizeof from);
+ from_len = sizeof from;
+
+ flags = 0;
+
+ if (WSARecvFrom(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &from,
+ &from_len,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+
+ /* Message received */
+ handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEMSGSIZE) {
+ /* Message truncated */
+ handle->recv_cb(handle,
+ bytes,
+ &buf,
+ (const struct sockaddr*) &from,
+ UV_UDP_PARTIAL);
+ } else if (err == WSAEWOULDBLOCK) {
+ /* Kernel buffer empty */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
+ * that a previous sendto operation failed.
+ */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else {
+ /* Any other error that we want to report back to the user. */
+ uv_udp_recv_stop(handle);
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_udp_queue_recv(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req) {
+ int err;
+
+ assert(handle->type == UV_UDP);
+
+ assert(handle->send_queue_size >= req->u.io.queued_bytes);
+ assert(handle->send_queue_count >= 1);
+ handle->send_queue_size -= req->u.io.queued_bytes;
+ handle->send_queue_count--;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (!REQ_SUCCESS(req)) {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ int optname;
+ struct ip_mreq mreq;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ return UV_EINVAL;
+
+ /* If the socket is unbound, bind to inaddr_any. */
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ UV_UDP_REUSEADDR);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ int err;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
+ return UV_EINVAL;
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip6_any_,
+ sizeof(uv_addr_ip6_any_),
+ UV_UDP_REUSEADDR);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof(mreq));
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return UV_EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ else
+ return UV_EINVAL;
+}
+
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (char*) &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
+ BOOL optval = (BOOL) value;
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char*) &optval,
+ sizeof optval)) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_udp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily);
+ return uv_translate_sys_error(err);
+}
+
+
+#define SOCKOPT_SETTER(name, option4, option6, validate) \
+ int uv_udp_set_##name(uv_udp_t* handle, int value) { \
+ DWORD optval = (DWORD) value; \
+ \
+ if (!(validate(value))) { \
+ return UV_EINVAL; \
+ } \
+ \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
+ \
+ if (!(handle->flags & UV_HANDLE_IPV6)) { \
+ /* Set IPv4 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IP, \
+ option4, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } else { \
+ /* Set IPv6 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IPV6, \
+ option6, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } \
+ return 0; \
+ }
+
+#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
+#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
+#define VALIDATE_MULTICAST_LOOP(value) (1)
+
+SOCKOPT_SETTER(ttl,
+ IP_TTL,
+ IPV6_HOPLIMIT,
+ VALIDATE_TTL)
+SOCKOPT_SETTER(multicast_ttl,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ VALIDATE_MULTICAST_TTL)
+SOCKOPT_SETTER(multicast_loop,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ VALIDATE_MULTICAST_LOOP)
+
+#undef SOCKOPT_SETTER
+#undef VALIDATE_TTL
+#undef VALIDATE_MULTICAST_TTL
+#undef VALIDATE_MULTICAST_LOOP
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ const struct sockaddr* bind_addr;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ return UV_ENOSYS;
+}
diff --git a/3rdparty/libuv/src/win/util.c b/3rdparty/libuv/src/win/util.c
new file mode 100644
index 00000000000..cb247513046
--- /dev/null
+++ b/3rdparty/libuv/src/win/util.c
@@ -0,0 +1,1232 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <direct.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+
+#include "uv.h"
+#include "internal.h"
+
+#include <winsock2.h>
+#include <winperf.h>
+#include <iphlpapi.h>
+#include <psapi.h>
+#include <tlhelp32.h>
+#include <windows.h>
+#include <userenv.h>
+
+
+/*
+ * Max title length; the only thing MSDN tells us about the maximum length
+ * of the console title is that it is smaller than 64K. However in practice
+ * it is much smaller, and there is no way to figure out what the exact length
+ * of the title is or can be, at least not on XP. To make it even more
+ * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
+ * than the actual maximum length. So we make a conservative guess here;
+ * just don't put the novel you're writing in the title, unless the plot
+ * survives truncation.
+ */
+#define MAX_TITLE_LENGTH 8192
+
+/* The number of nanoseconds in one second. */
+#define UV__NANOSEC 1000000000
+
+
+/* Cached copy of the process title, plus a mutex guarding it. */
+static char *process_title;
+static CRITICAL_SECTION process_title_lock;
+
+/* Cached copy of the process id, written once. */
+static DWORD current_pid = 0;
+
+
+/* Interval (in seconds) of the high-resolution clock. */
+static double hrtime_interval_ = 0;
+
+
+/*
+ * One-time initialization code for functionality defined in util.c.
+ */
+void uv__util_init() {
+ LARGE_INTEGER perf_frequency;
+
+ /* Initialize process title access mutex. */
+ InitializeCriticalSection(&process_title_lock);
+
+ /* Retrieve high-resolution timer frequency
+ * and precompute its reciprocal.
+ */
+ if (QueryPerformanceFrequency(&perf_frequency)) {
+ hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
+ } else {
+ hrtime_interval_= 0;
+ }
+}
+
+
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
+ char* utf8Buffer, size_t utf8Size) {
+ return WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16Buffer,
+ utf16Size,
+ utf8Buffer,
+ utf8Size,
+ NULL,
+ NULL);
+}
+
+
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
+ size_t utf16Size) {
+ return MultiByteToWideChar(CP_UTF8,
+ 0,
+ utf8Buffer,
+ -1,
+ utf16Buffer,
+ utf16Size);
+}
+
+
+int uv_exepath(char* buffer, size_t* size_ptr) {
+ int utf8_len, utf16_buffer_len, utf16_len;
+ WCHAR* utf16_buffer;
+ int err;
+
+ if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
+ return UV_EINVAL;
+ }
+
+ if (*size_ptr > 32768) {
+ /* Windows paths can never be longer than this. */
+ utf16_buffer_len = 32768;
+ } else {
+ utf16_buffer_len = (int) *size_ptr;
+ }
+
+ utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
+ if (!utf16_buffer) {
+ return UV_ENOMEM;
+ }
+
+ /* Get the path as UTF-16. */
+ utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
+ if (utf16_len <= 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* Convert to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv__free(utf16_buffer);
+
+ /* utf8_len *does* include the terminating null at this point, but the */
+ /* returned size shouldn't. */
+ *size_ptr = utf8_len - 1;
+ return 0;
+
+ error:
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ DWORD utf16_len;
+ WCHAR utf16_buffer[MAX_PATH];
+ int r;
+
+ if (buffer == NULL || size == NULL) {
+ return UV_EINVAL;
+ }
+
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ /* This should be impossible; however the CRT has a code path to deal */
+ /* with this scenario, so I added a check anyway. */
+ return UV_EIO;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (r > (int) *size) {
+ *size = r -1;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size > INT_MAX ? INT_MAX : (int) *size,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *size = r - 1;
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ WCHAR utf16_buffer[MAX_PATH];
+ size_t utf16_len;
+ WCHAR drive_letter, env_var[4];
+
+ if (dir == NULL) {
+ return UV_EINVAL;
+ }
+
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ dir,
+ -1,
+ utf16_buffer,
+ MAX_PATH) == 0) {
+ DWORD error = GetLastError();
+ /* The maximum length of the current working directory is 260 chars, */
+ /* including terminating null. If it doesn't fit, the path name must be */
+ /* too long. */
+ if (error == ERROR_INSUFFICIENT_BUFFER) {
+ return UV_ENAMETOOLONG;
+ } else {
+ return uv_translate_sys_error(error);
+ }
+ }
+
+ if (!SetCurrentDirectoryW(utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Windows stores the drive-local path in an "hidden" environment variable, */
+ /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
+ /* update this, so we'll have to do it. */
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed. */
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ if (utf16_len < 2 || utf16_buffer[1] != L':') {
+ /* Doesn't look like a drive letter could be there - probably an UNC */
+ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+ drive_letter = 0;
+ } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
+ drive_letter = utf16_buffer[0];
+ } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
+ /* Convert to uppercase. */
+ drive_letter = utf16_buffer[0] - L'a' + L'A';
+ } else {
+ /* Not valid. */
+ drive_letter = 0;
+ }
+
+ if (drive_letter != 0) {
+ /* Construct the environment variable name and set it. */
+ env_var[0] = L'=';
+ env_var[1] = drive_letter;
+ env_var[2] = L':';
+ env_var[3] = L'\0';
+
+ if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ }
+
+ return 0;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ /* Can't be implemented */
+ avg[0] = avg[1] = avg[2] = 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullAvailPhys;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullTotalPhys;
+}
+
+
+int uv_parent_pid() {
+ int parent_pid = -1;
+ HANDLE handle;
+ PROCESSENTRY32 pe;
+ DWORD current_pid = GetCurrentProcessId();
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ if (Process32First(handle, &pe)) {
+ do {
+ if (pe.th32ProcessID == current_pid) {
+ parent_pid = pe.th32ParentProcessID;
+ break;
+ }
+ } while( Process32Next(handle, &pe));
+ }
+
+ CloseHandle(handle);
+ return parent_pid;
+}
+
+
+int uv_current_pid() {
+ if (current_pid == 0) {
+ current_pid = GetCurrentProcessId();
+ }
+ return current_pid;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int err;
+ int length;
+ WCHAR* title_w = NULL;
+
+ uv__once_init();
+
+ /* Find out how big the buffer for the wide-char title must be */
+ length = uv_utf8_to_utf16(title, NULL, 0);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Convert to wide-char string */
+ title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
+ if (!title_w) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ length = uv_utf8_to_utf16(title, title_w, length);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* If the title must be truncated insert a \0 terminator there */
+ if (length > MAX_TITLE_LENGTH) {
+ title_w[MAX_TITLE_LENGTH - 1] = L'\0';
+ }
+
+ if (!SetConsoleTitleW(title_w)) {
+ err = GetLastError();
+ goto done;
+ }
+
+ EnterCriticalSection(&process_title_lock);
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ LeaveCriticalSection(&process_title_lock);
+
+ err = 0;
+
+done:
+ uv__free(title_w);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__get_process_title() {
+ WCHAR title_w[MAX_TITLE_LENGTH];
+ int length;
+
+ if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
+ return -1;
+ }
+
+ /* Find out what the size of the buffer is that we need */
+ length = uv_utf16_to_utf8(title_w, -1, NULL, 0);
+ if (!length) {
+ return -1;
+ }
+
+ assert(!process_title);
+ process_title = (char*)uv__malloc(length);
+ if (!process_title) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Do utf16 -> utf8 conversion here */
+ if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) {
+ uv__free(process_title);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ uv__once_init();
+
+ EnterCriticalSection(&process_title_lock);
+ /*
+ * If the process_title was never read before nor explicitly set,
+ * we must query it with getConsoleTitleW
+ */
+ if (!process_title && uv__get_process_title() == -1) {
+ LeaveCriticalSection(&process_title_lock);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ assert(process_title);
+ strncpy(buffer, process_title, size);
+ LeaveCriticalSection(&process_title_lock);
+
+ return 0;
+}
+
+
+uint64_t uv_hrtime(void) {
+ uv__once_init();
+ return uv__hrtime(UV__NANOSEC);
+}
+
+uint64_t uv__hrtime(double scale) {
+ LARGE_INTEGER counter;
+
+ /* If the performance interval is zero, there's no support. */
+ if (hrtime_interval_ == 0) {
+ return 0;
+ }
+
+ if (!QueryPerformanceCounter(&counter)) {
+ return 0;
+ }
+
+ /* Because we have no guarantee about the order of magnitude of the
+ * performance counter interval, integer math could cause this computation
+ * to overflow. Therefore we resort to floating point math.
+ */
+ return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ HANDLE current_process;
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ current_process = GetCurrentProcess();
+
+ if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *rss = pmc.WorkingSetSize;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ BYTE stack_buffer[4096];
+ BYTE* malloced_buffer = NULL;
+ BYTE* buffer = (BYTE*) stack_buffer;
+ size_t buffer_size = sizeof(stack_buffer);
+ DWORD data_size;
+
+ PERF_DATA_BLOCK* data_block;
+ PERF_OBJECT_TYPE* object_type;
+ PERF_COUNTER_DEFINITION* counter_definition;
+
+ DWORD i;
+
+ for (;;) {
+ LONG result;
+
+ data_size = (DWORD) buffer_size;
+ result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
+ L"2",
+ NULL,
+ NULL,
+ buffer,
+ &data_size);
+ if (result == ERROR_SUCCESS) {
+ break;
+ } else if (result != ERROR_MORE_DATA) {
+ *uptime = 0;
+ return uv_translate_sys_error(result);
+ }
+
+ buffer_size *= 2;
+ /* Don't let the buffer grow infinitely. */
+ if (buffer_size > 1 << 20) {
+ goto internalError;
+ }
+
+ uv__free(malloced_buffer);
+
+ buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
+ if (malloced_buffer == NULL) {
+ *uptime = 0;
+ return UV_ENOMEM;
+ }
+ }
+
+ if (data_size < sizeof(*data_block))
+ goto internalError;
+
+ data_block = (PERF_DATA_BLOCK*) buffer;
+
+ if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
+ goto internalError;
+
+ if (data_size < data_block->HeaderLength + sizeof(*object_type))
+ goto internalError;
+
+ object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
+
+ if (object_type->NumInstances != PERF_NO_INSTANCES)
+ goto internalError;
+
+ counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
+ data_block->HeaderLength + object_type->HeaderLength);
+ for (i = 0; i < object_type->NumCounters; i++) {
+ if ((BYTE*) counter_definition + sizeof(*counter_definition) >
+ buffer + data_size) {
+ break;
+ }
+
+ if (counter_definition->CounterNameTitleIndex == 674 &&
+ counter_definition->CounterSize == sizeof(uint64_t)) {
+ if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
+ !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
+ goto internalError;
+ } else {
+ BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
+ counter_definition->CounterOffset;
+ uint64_t value = *((uint64_t*) address);
+ *uptime = (double) (object_type->PerfTime.QuadPart - value) /
+ (double) object_type->PerfFreq.QuadPart;
+ uv__free(malloced_buffer);
+ return 0;
+ }
+ }
+
+ counter_definition = (PERF_COUNTER_DEFINITION*)
+ ((BYTE*) counter_definition + counter_definition->ByteLength);
+ }
+
+ /* If we get here, the uptime value was not found. */
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_ENOSYS;
+
+ internalError:
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_EIO;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
+ uv_cpu_info_t* cpu_infos;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
+ DWORD sppi_size;
+ SYSTEM_INFO system_info;
+ DWORD cpu_count, r, i;
+ NTSTATUS status;
+ ULONG result_size;
+ int err;
+ uv_cpu_info_t* cpu_info;
+
+ cpu_infos = NULL;
+ cpu_count = 0;
+ sppi = NULL;
+
+ uv__once_init();
+
+ GetSystemInfo(&system_info);
+ cpu_count = system_info.dwNumberOfProcessors;
+
+ cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
+ if (cpu_infos == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ sppi_size = cpu_count * sizeof(*sppi);
+ sppi = uv__malloc(sppi_size);
+ if (sppi == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ sppi,
+ sppi_size,
+ &result_size);
+ if (!NT_SUCCESS(status)) {
+ err = pRtlNtStatusToDosError(status);
+ goto error;
+ }
+
+ assert(result_size == sppi_size);
+
+ for (i = 0; i < cpu_count; i++) {
+ WCHAR key_name[128];
+ HKEY processor_key;
+ DWORD cpu_speed;
+ DWORD cpu_speed_size = sizeof(cpu_speed);
+ WCHAR cpu_brand[256];
+ DWORD cpu_brand_size = sizeof(cpu_brand);
+ size_t len;
+
+ len = _snwprintf(key_name,
+ ARRAY_SIZE(key_name),
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
+ i);
+
+ assert(len > 0 && len < ARRAY_SIZE(key_name));
+
+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &processor_key);
+ if (r != ERROR_SUCCESS) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"~MHz",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_speed,
+ &cpu_speed_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"ProcessorNameString",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_brand,
+ &cpu_brand_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ RegCloseKey(processor_key);
+
+ cpu_info = &cpu_infos[i];
+ cpu_info->speed = cpu_speed;
+ cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
+ cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
+ sppi[i].IdleTime.QuadPart) / 10000;
+ cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
+ cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
+ cpu_info->cpu_times.nice = 0;
+
+
+ len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(len > 0);
+
+ /* Allocate 1 extra byte for the null terminator. */
+ cpu_info->model = uv__malloc(len + 1);
+ if (cpu_info->model == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ cpu_info->model,
+ len,
+ NULL,
+ NULL) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* Ensure that cpu_info->model is null terminated. */
+ cpu_info->model[len] = '\0';
+ }
+
+ uv__free(sppi);
+
+ *cpu_count_ptr = cpu_count;
+ *cpu_infos_ptr = cpu_infos;
+
+ return 0;
+
+ error:
+ /* This is safe because the cpu_infos array is zeroed on allocation. */
+ for (i = 0; i < cpu_count; i++)
+ uv__free(cpu_infos[i].model);
+
+ uv__free(cpu_infos);
+ uv__free(sppi);
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+static int is_windows_version_or_greater(DWORD os_major,
+ DWORD os_minor,
+ WORD service_pack_major,
+ WORD service_pack_minor) {
+ OSVERSIONINFOEX osvi;
+ DWORDLONG condition_mask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ /* Initialize the OSVERSIONINFOEX structure. */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = os_major;
+ osvi.dwMinorVersion = os_minor;
+ osvi.wServicePackMajor = service_pack_major;
+ osvi.wServicePackMinor = service_pack_minor;
+
+ /* Initialize the condition mask. */
+ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
+
+ /* Perform the test. */
+ return (int) VerifyVersionInfo(
+ &osvi,
+ VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+ condition_mask);
+}
+
+
+static int address_prefix_match(int family,
+ struct sockaddr* address,
+ struct sockaddr* prefix_address,
+ int prefix_len) {
+ uint8_t* address_data;
+ uint8_t* prefix_address_data;
+ int i;
+
+ assert(address->sa_family == family);
+ assert(prefix_address->sa_family == family);
+
+ if (family == AF_INET6) {
+ address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
+ } else {
+ address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
+ }
+
+ for (i = 0; i < prefix_len >> 3; i++) {
+ if (address_data[i] != prefix_address_data[i])
+ return 0;
+ }
+
+ if (prefix_len % 8)
+ return prefix_address_data[i] ==
+ (address_data[i] & (0xff << (8 - prefix_len % 8)));
+
+ return 1;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
+ int* count_ptr) {
+ IP_ADAPTER_ADDRESSES* win_address_buf;
+ ULONG win_address_buf_size;
+ IP_ADAPTER_ADDRESSES* adapter;
+
+ uv_interface_address_t* uv_address_buf;
+ char* name_buf;
+ size_t uv_address_buf_size;
+ uv_interface_address_t* uv_address;
+
+ int count;
+
+ int is_vista_or_greater;
+ ULONG flags;
+
+ is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
+ if (is_vista_or_greater) {
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER;
+ } else {
+ /* We need at least XP SP1. */
+ if (!is_windows_version_or_greater(5, 1, 1, 0))
+ return UV_ENOTSUP;
+
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
+ }
+
+
+ /* Fetch the size of the adapters reported by windows, and then get the */
+ /* list itself. */
+ win_address_buf_size = 0;
+ win_address_buf = NULL;
+
+ for (;;) {
+ ULONG r;
+
+ /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
+ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
+ /* win_address_buf_size. */
+ r = GetAdaptersAddresses(AF_UNSPEC,
+ flags,
+ NULL,
+ win_address_buf,
+ &win_address_buf_size);
+
+ if (r == ERROR_SUCCESS)
+ break;
+
+ uv__free(win_address_buf);
+
+ switch (r) {
+ case ERROR_BUFFER_OVERFLOW:
+ /* This happens when win_address_buf is NULL or too small to hold */
+ /* all adapters. */
+ win_address_buf = uv__malloc(win_address_buf_size);
+ if (win_address_buf == NULL)
+ return UV_ENOMEM;
+
+ continue;
+
+ case ERROR_NO_DATA: {
+ /* No adapters were found. */
+ uv_address_buf = uv__malloc(1);
+ if (uv_address_buf == NULL)
+ return UV_ENOMEM;
+
+ *count_ptr = 0;
+ *addresses_ptr = uv_address_buf;
+
+ return 0;
+ }
+
+ case ERROR_ADDRESS_NOT_ASSOCIATED:
+ return UV_EAGAIN;
+
+ case ERROR_INVALID_PARAMETER:
+ /* MSDN says:
+ * "This error is returned for any of the following conditions: the
+ * SizePointer parameter is NULL, the Address parameter is not
+ * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
+ * the parameters requested is greater than ULONG_MAX."
+ * Since the first two conditions are not met, it must be that the
+ * adapter data is too big.
+ */
+ return UV_ENOBUFS;
+
+ default:
+ /* Other (unspecified) errors can happen, but we don't have any */
+ /* special meaning for them. */
+ assert(r != ERROR_SUCCESS);
+ return uv_translate_sys_error(r);
+ }
+ }
+
+ /* Count the number of enabled interfaces and compute how much space is */
+ /* needed to store their info. */
+ count = 0;
+ uv_address_buf_size = 0;
+
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+
+ /* Interfaces that are not 'up' should not be reported. Also skip */
+ /* interfaces that have no associated unicast address, as to avoid */
+ /* allocating space for the name for this interface. */
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Compute the size of the interface name. */
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+ uv_address_buf_size += name_size;
+
+ /* Count the number of addresses associated with this interface, and */
+ /* compute the size. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ count++;
+ uv_address_buf_size += sizeof(uv_interface_address_t);
+ }
+ }
+
+ /* Allocate space to store interface data plus adapter names. */
+ uv_address_buf = uv__malloc(uv_address_buf_size);
+ if (uv_address_buf == NULL) {
+ uv__free(win_address_buf);
+ return UV_ENOMEM;
+ }
+
+ /* Compute the start of the uv_interface_address_t array, and the place in */
+ /* the buffer where the interface names will be stored. */
+ uv_address = uv_address_buf;
+ name_buf = (char*) (uv_address_buf + count);
+
+ /* Fill out the output buffer. */
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+ size_t max_name_size;
+
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Convert the interface name to UTF8. */
+ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
+ if (max_name_size > (size_t) INT_MAX)
+ max_name_size = INT_MAX;
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ name_buf,
+ (int) max_name_size,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ uv__free(uv_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Add an uv_interface_address_t element for every unicast address. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ struct sockaddr* sa;
+ ULONG prefix_len;
+
+ sa = unicast_address->Address.lpSockaddr;
+
+ /* XP has no OnLinkPrefixLength field. */
+ if (is_vista_or_greater) {
+ prefix_len =
+ ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
+ } else {
+ /* Prior to Windows Vista the FirstPrefix pointed to the list with
+ * single prefix for each IP address assigned to the adapter.
+ * Order of FirstPrefix does not match order of FirstUnicastAddress,
+ * so we need to find corresponding prefix.
+ */
+ IP_ADAPTER_PREFIX* prefix;
+ prefix_len = 0;
+
+ for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
+ /* We want the longest matching prefix. */
+ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
+ prefix->PrefixLength <= prefix_len)
+ continue;
+
+ if (address_prefix_match(sa->sa_family, sa,
+ prefix->Address.lpSockaddr, prefix->PrefixLength)) {
+ prefix_len = prefix->PrefixLength;
+ }
+ }
+
+ /* If there is no matching prefix information, return a single-host
+ * subnet mask (e.g. 255.255.255.255 for IPv4).
+ */
+ if (!prefix_len)
+ prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
+ }
+
+ memset(uv_address, 0, sizeof *uv_address);
+
+ uv_address->name = name_buf;
+
+ if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
+ memcpy(uv_address->phys_addr,
+ adapter->PhysicalAddress,
+ sizeof(uv_address->phys_addr));
+ }
+
+ uv_address->is_internal =
+ (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
+
+ if (sa->sa_family == AF_INET6) {
+ uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
+
+ uv_address->netmask.netmask6.sin6_family = AF_INET6;
+ memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
+ /* This check ensures that we don't write past the size of the data. */
+ if (prefix_len % 8) {
+ uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
+ 0xff << (8 - prefix_len % 8);
+ }
+
+ } else {
+ uv_address->address.address4 = *((struct sockaddr_in *) sa);
+
+ uv_address->netmask.netmask4.sin_family = AF_INET;
+ uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
+ htonl(0xffffffff << (32 - prefix_len)) : 0;
+ }
+
+ uv_address++;
+ }
+
+ name_buf += name_size;
+ }
+
+ uv__free(win_address_buf);
+
+ *addresses_ptr = uv_address_buf;
+ *count_ptr = count;
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ uv__free(addresses);
+}
+
+
+int uv_getrusage(uv_rusage_t *uv_rusage) {
+ FILETIME createTime, exitTime, kernelTime, userTime;
+ SYSTEMTIME kernelSystemTime, userSystemTime;
+ int ret;
+
+ ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&userTime, &userSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ memset(uv_rusage, 0, sizeof(*uv_rusage));
+
+ uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
+ userSystemTime.wMinute * 60 +
+ userSystemTime.wSecond;
+ uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
+ kernelSystemTime.wMinute * 60 +
+ kernelSystemTime.wSecond;
+ uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
+
+ return 0;
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ HANDLE token;
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ size_t len;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ /* Check if the USERPROFILE environment variable is set first */
+ len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH);
+
+ if (len == 0) {
+ r = GetLastError();
+ /* Don't return an error if USERPROFILE was not found */
+ if (r != ERROR_ENVVAR_NOT_FOUND)
+ return uv_translate_sys_error(r);
+ } else if (len > MAX_PATH) {
+ /* This should not be possible */
+ return UV_EIO;
+ } else {
+ goto convert_buffer;
+ }
+
+ /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ bufsize = MAX_PATH;
+ if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ r = GetLastError();
+ CloseHandle(token);
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_EIO;
+
+ return uv_translate_sys_error(r);
+ }
+
+ CloseHandle(token);
+
+convert_buffer:
+
+ /* Check how much space we need */
+ bufsize = uv_utf16_to_utf8(path, -1, NULL, 0);
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize - 1;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = uv_utf16_to_utf8(path, -1, buffer, *size);
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/winapi.c b/3rdparty/libuv/src/win/winapi.c
new file mode 100644
index 00000000000..26bd0648668
--- /dev/null
+++ b/3rdparty/libuv/src/win/winapi.c
@@ -0,0 +1,146 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Ntdll function pointers */
+sRtlNtStatusToDosError pRtlNtStatusToDosError;
+sNtDeviceIoControlFile pNtDeviceIoControlFile;
+sNtQueryInformationFile pNtQueryInformationFile;
+sNtSetInformationFile pNtSetInformationFile;
+sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+sNtQueryDirectoryFile pNtQueryDirectoryFile;
+sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+sCreateSymbolicLinkW pCreateSymbolicLinkW;
+sCancelIoEx pCancelIoEx;
+sInitializeConditionVariable pInitializeConditionVariable;
+sSleepConditionVariableCS pSleepConditionVariableCS;
+sSleepConditionVariableSRW pSleepConditionVariableSRW;
+sWakeAllConditionVariable pWakeAllConditionVariable;
+sWakeConditionVariable pWakeConditionVariable;
+sCancelSynchronousIo pCancelSynchronousIo;
+sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+void uv_winapi_init() {
+ HMODULE ntdll_module;
+ HMODULE kernel32_module;
+
+ ntdll_module = GetModuleHandleA("ntdll.dll");
+ if (ntdll_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
+ ntdll_module,
+ "RtlNtStatusToDosError");
+ if (pRtlNtStatusToDosError == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
+ ntdll_module,
+ "NtDeviceIoControlFile");
+ if (pNtDeviceIoControlFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtQueryInformationFile");
+ if (pNtQueryInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtSetInformationFile");
+ if (pNtSetInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
+ GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
+ GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
+ ntdll_module,
+ "NtQuerySystemInformation");
+ if (pNtQuerySystemInformation == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ kernel32_module = GetModuleHandleA("kernel32.dll");
+ if (kernel32_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
+ kernel32_module,
+ "GetQueuedCompletionStatusEx");
+
+ pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
+ GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
+
+ pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
+ GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
+
+ pCancelIoEx = (sCancelIoEx)
+ GetProcAddress(kernel32_module, "CancelIoEx");
+
+ pInitializeConditionVariable = (sInitializeConditionVariable)
+ GetProcAddress(kernel32_module, "InitializeConditionVariable");
+
+ pSleepConditionVariableCS = (sSleepConditionVariableCS)
+ GetProcAddress(kernel32_module, "SleepConditionVariableCS");
+
+ pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
+ GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
+
+ pWakeAllConditionVariable = (sWakeAllConditionVariable)
+ GetProcAddress(kernel32_module, "WakeAllConditionVariable");
+
+ pWakeConditionVariable = (sWakeConditionVariable)
+ GetProcAddress(kernel32_module, "WakeConditionVariable");
+
+ pCancelSynchronousIo = (sCancelSynchronousIo)
+ GetProcAddress(kernel32_module, "CancelSynchronousIo");
+
+ pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
+ GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
+}
diff --git a/3rdparty/libuv/src/win/winapi.h b/3rdparty/libuv/src/win/winapi.h
new file mode 100644
index 00000000000..122198a6d48
--- /dev/null
+++ b/3rdparty/libuv/src/win/winapi.h
@@ -0,0 +1,4710 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINAPI_H_
+#define UV_WIN_WINAPI_H_
+
+#include <windows.h>
+
+
+/*
+ * Ntdll headers
+ */
+#ifndef STATUS_SEVERITY_SUCCESS
+# define STATUS_SEVERITY_SUCCESS 0x0
+#endif
+
+#ifndef STATUS_SEVERITY_INFORMATIONAL
+# define STATUS_SEVERITY_INFORMATIONAL 0x1
+#endif
+
+#ifndef STATUS_SEVERITY_WARNING
+# define STATUS_SEVERITY_WARNING 0x2
+#endif
+
+#ifndef STATUS_SEVERITY_ERROR
+# define STATUS_SEVERITY_ERROR 0x3
+#endif
+
+#ifndef FACILITY_NTWIN32
+# define FACILITY_NTWIN32 0x7
+#endif
+
+#ifndef NT_SUCCESS
+# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0)
+#endif
+
+#ifndef NT_INFORMATION
+# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1)
+#endif
+
+#ifndef NT_WARNING
+# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2)
+#endif
+
+#ifndef NT_ERROR
+# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3)
+#endif
+
+#ifndef STATUS_SUCCESS
+# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_0
+# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_1
+# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L)
+#endif
+
+#ifndef STATUS_WAIT_2
+# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L)
+#endif
+
+#ifndef STATUS_WAIT_3
+# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L)
+#endif
+
+#ifndef STATUS_WAIT_63
+# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL)
+#endif
+
+#ifndef STATUS_ABANDONED
+# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_0
+# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_63
+# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL)
+#endif
+
+#ifndef STATUS_USER_APC
+# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L)
+#endif
+
+#ifndef STATUS_KERNEL_APC
+# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L)
+#endif
+
+#ifndef STATUS_ALERTED
+# define STATUS_ALERTED ((NTSTATUS) 0x00000101L)
+#endif
+
+#ifndef STATUS_TIMEOUT
+# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L)
+#endif
+
+#ifndef STATUS_PENDING
+# define STATUS_PENDING ((NTSTATUS) 0x00000103L)
+#endif
+
+#ifndef STATUS_REPARSE
+# define STATUS_REPARSE ((NTSTATUS) 0x00000104L)
+#endif
+
+#ifndef STATUS_MORE_ENTRIES
+# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L)
+#endif
+
+#ifndef STATUS_NOT_ALL_ASSIGNED
+# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L)
+#endif
+
+#ifndef STATUS_SOME_NOT_MAPPED
+# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L)
+#endif
+
+#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS
+# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L)
+#endif
+
+#ifndef STATUS_VOLUME_MOUNTED
+# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L)
+#endif
+
+#ifndef STATUS_RXACT_COMMITTED
+# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL)
+#endif
+
+#ifndef STATUS_NOTIFY_CLEANUP
+# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL)
+#endif
+
+#ifndef STATUS_NOTIFY_ENUM_DIR
+# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL)
+#endif
+
+#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT
+# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL)
+#endif
+
+#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_TRANSITION
+# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO
+# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE
+# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_GUARD_PAGE
+# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_PAGING_FILE
+# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L)
+#endif
+
+#ifndef STATUS_CACHE_PAGE_LOCKED
+# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L)
+#endif
+
+#ifndef STATUS_CRASH_DUMP
+# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L)
+#endif
+
+#ifndef STATUS_BUFFER_ALL_ZEROS
+# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L)
+#endif
+
+#ifndef STATUS_REPARSE_OBJECT
+# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L)
+#endif
+
+#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED
+# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L)
+#endif
+
+#ifndef STATUS_TRANSLATION_COMPLETE
+# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L)
+#endif
+
+#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L)
+#endif
+
+#ifndef STATUS_NOTHING_TO_TERMINATE
+# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L)
+#endif
+
+#ifndef STATUS_PROCESS_NOT_IN_JOB
+# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L)
+#endif
+
+#ifndef STATUS_PROCESS_IN_JOB
+# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L)
+#endif
+
+#ifndef STATUS_VOLSNAP_HIBERNATE_READY
+# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L)
+#endif
+
+#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L)
+#endif
+
+#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L)
+#endif
+
+#ifndef STATUS_INTERRUPT_STILL_CONNECTED
+# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L)
+#endif
+
+#ifndef STATUS_PROCESS_CLONED
+# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS
+# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_WRITERS
+# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL)
+#endif
+
+#ifndef STATUS_RESOURCEMANAGER_READ_ONLY
+# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_EMPTY
+# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_FULL
+# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA
+# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L)
+#endif
+
+#ifndef STATUS_RING_NEWLY_EMPTY
+# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L)
+#endif
+
+#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT
+# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L)
+#endif
+
+#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE
+# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L)
+#endif
+
+#ifndef STATUS_OPLOCK_HANDLE_CLOSED
+# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L)
+#endif
+
+#ifndef STATUS_WAIT_FOR_OPLOCK
+# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_EXISTS
+# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L)
+#endif
+
+#ifndef STATUS_THREAD_WAS_SUSPENDED
+# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L)
+#endif
+
+#ifndef STATUS_WORKING_SET_LIMIT_RANGE
+# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L)
+#endif
+
+#ifndef STATUS_IMAGE_NOT_AT_BASE
+# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L)
+#endif
+
+#ifndef STATUS_RXACT_STATE_CREATED
+# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L)
+#endif
+
+#ifndef STATUS_SEGMENT_NOTIFICATION
+# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L)
+#endif
+
+#ifndef STATUS_LOCAL_USER_SESSION_KEY
+# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L)
+#endif
+
+#ifndef STATUS_BAD_CURRENT_DIRECTORY
+# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L)
+#endif
+
+#ifndef STATUS_SERIAL_MORE_WRITES
+# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L)
+#endif
+
+#ifndef STATUS_REGISTRY_RECOVERED
+# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L)
+#endif
+
+#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP
+# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL)
+#endif
+
+#ifndef STATUS_FT_WRITE_RECOVERY
+# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL)
+#endif
+
+#ifndef STATUS_SERIAL_COUNTER_TIMEOUT
+# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL)
+#endif
+
+#ifndef STATUS_NULL_LM_PASSWORD
+# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL
+# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL)
+#endif
+
+#ifndef STATUS_RECEIVE_EXPEDITED
+# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED
+# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L)
+#endif
+
+#ifndef STATUS_EVENT_DONE
+# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L)
+#endif
+
+#ifndef STATUS_EVENT_PENDING
+# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L)
+#endif
+
+#ifndef STATUS_CHECKING_FILE_SYSTEM
+# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L)
+#endif
+
+#ifndef STATUS_FATAL_APP_EXIT
+# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L)
+#endif
+
+#ifndef STATUS_PREDEFINED_HANDLE
+# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L)
+#endif
+
+#ifndef STATUS_WAS_UNLOCKED
+# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L)
+#endif
+
+#ifndef STATUS_SERVICE_NOTIFICATION
+# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L)
+#endif
+
+#ifndef STATUS_WAS_LOCKED
+# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L)
+#endif
+
+#ifndef STATUS_LOG_HARD_ERROR
+# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL)
+#endif
+
+#ifndef STATUS_ALREADY_WIN32
+# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL)
+#endif
+
+#ifndef STATUS_WX86_UNSIMULATE
+# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL)
+#endif
+
+#ifndef STATUS_WX86_CONTINUE
+# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL)
+#endif
+
+#ifndef STATUS_WX86_SINGLE_STEP
+# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL)
+#endif
+
+#ifndef STATUS_WX86_BREAKPOINT
+# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CONTINUE
+# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE
+# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CHAIN
+# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L)
+#endif
+
+#ifndef STATUS_NO_YIELD_PERFORMED
+# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L)
+#endif
+
+#ifndef STATUS_TIMER_RESUME_IGNORED
+# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L)
+#endif
+
+#ifndef STATUS_ARBITRATION_UNHANDLED
+# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L)
+#endif
+
+#ifndef STATUS_CARDBUS_NOT_SUPPORTED
+# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L)
+#endif
+
+#ifndef STATUS_WX86_CREATEWX86TIB
+# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L)
+#endif
+
+#ifndef STATUS_MP_PROCESSOR_MISMATCH
+# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L)
+#endif
+
+#ifndef STATUS_HIBERNATED
+# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL)
+#endif
+
+#ifndef STATUS_RESUME_HIBERNATION
+# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL)
+#endif
+
+#ifndef STATUS_FIRMWARE_UPDATED
+# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL)
+#endif
+
+#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL)
+#endif
+
+#ifndef STATUS_MESSAGE_RETRIEVED
+# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL)
+#endif
+
+#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST
+# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L)
+#endif
+
+#ifndef STATUS_ACCESS_AUDIT_BY_POLICY
+# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L)
+#endif
+
+#ifndef STATUS_ABANDON_HIBERFILE
+# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L)
+#endif
+
+#ifndef STATUS_BIZRULES_NOT_ENABLED
+# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L)
+#endif
+
+#ifndef STATUS_GUARD_PAGE_VIOLATION
+# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT
+# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L)
+#endif
+
+#ifndef STATUS_BREAKPOINT
+# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L)
+#endif
+
+#ifndef STATUS_SINGLE_STEP
+# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L)
+#endif
+
+#ifndef STATUS_BUFFER_OVERFLOW
+# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L)
+#endif
+
+#ifndef STATUS_NO_MORE_FILES
+# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM_DEBUGGER
+# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L)
+#endif
+
+#ifndef STATUS_HANDLES_CLOSED
+# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL)
+#endif
+
+#ifndef STATUS_NO_INHERITANCE
+# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL)
+#endif
+
+#ifndef STATUS_GUID_SUBSTITUTION_MADE
+# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL)
+#endif
+
+#ifndef STATUS_PARTIAL_COPY
+# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL)
+#endif
+
+#ifndef STATUS_DEVICE_PAPER_EMPTY
+# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL)
+#endif
+
+#ifndef STATUS_DEVICE_POWERED_OFF
+# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL)
+#endif
+
+#ifndef STATUS_DEVICE_OFF_LINE
+# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L)
+#endif
+
+#ifndef STATUS_DEVICE_BUSY
+# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L)
+#endif
+
+#ifndef STATUS_NO_MORE_EAS
+# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L)
+#endif
+
+#ifndef STATUS_INVALID_EA_NAME
+# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L)
+#endif
+
+#ifndef STATUS_EA_LIST_INCONSISTENT
+# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L)
+#endif
+
+#ifndef STATUS_INVALID_EA_FLAG
+# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L)
+#endif
+
+#ifndef STATUS_VERIFY_REQUIRED
+# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L)
+#endif
+
+#ifndef STATUS_EXTRANEOUS_INFORMATION
+# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_NECESSARY
+# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L)
+#endif
+
+#ifndef STATUS_NO_MORE_ENTRIES
+# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL)
+#endif
+
+#ifndef STATUS_FILEMARK_DETECTED
+# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL)
+#endif
+
+#ifndef STATUS_MEDIA_CHANGED
+# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL)
+#endif
+
+#ifndef STATUS_BUS_RESET
+# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL)
+#endif
+
+#ifndef STATUS_END_OF_MEDIA
+# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL)
+#endif
+
+#ifndef STATUS_BEGINNING_OF_MEDIA
+# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL)
+#endif
+
+#ifndef STATUS_MEDIA_CHECK
+# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L)
+#endif
+
+#ifndef STATUS_SETMARK_DETECTED
+# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L)
+#endif
+
+#ifndef STATUS_NO_DATA_DETECTED
+# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L)
+#endif
+
+#ifndef STATUS_SERVER_HAS_OPEN_HANDLES
+# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L)
+#endif
+
+#ifndef STATUS_ALREADY_DISCONNECTED
+# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L)
+#endif
+
+#ifndef STATUS_LONGJUMP
+# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L)
+#endif
+
+#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED
+# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L)
+#endif
+
+#ifndef STATUS_PLUGPLAY_QUERY_VETOED
+# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L)
+#endif
+
+#ifndef STATUS_UNWIND_CONSOLIDATE
+# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L)
+#endif
+
+#ifndef STATUS_REGISTRY_HIVE_RECOVERED
+# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INSECURE
+# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL)
+#endif
+
+#ifndef STATUS_STOPPED_ON_SYMLINK
+# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL)
+#endif
+
+#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK
+# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL)
+#endif
+
+#ifndef STATUS_NO_ACE_CONDITION
+# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL)
+#endif
+
+#ifndef STATUS_UNSUCCESSFUL
+# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
+#endif
+
+#ifndef STATUS_NOT_IMPLEMENTED
+# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L)
+#endif
+
+#ifndef STATUS_INVALID_INFO_CLASS
+# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L)
+#endif
+
+#ifndef STATUS_INFO_LENGTH_MISMATCH
+# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)
+#endif
+
+#ifndef STATUS_ACCESS_VIOLATION
+# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L)
+#endif
+
+#ifndef STATUS_IN_PAGE_ERROR
+# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA
+# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L)
+#endif
+
+#ifndef STATUS_INVALID_HANDLE
+# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_STACK
+# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_PC
+# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL)
+#endif
+
+#ifndef STATUS_INVALID_CID
+# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL)
+#endif
+
+#ifndef STATUS_TIMER_NOT_CANCELED
+# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER
+# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DEVICE
+# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_FILE
+# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_REQUEST
+# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L)
+#endif
+
+#ifndef STATUS_END_OF_FILE
+# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L)
+#endif
+
+#ifndef STATUS_WRONG_VOLUME
+# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L)
+#endif
+
+#ifndef STATUS_NO_MEDIA_IN_DEVICE
+# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_MEDIA
+# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_SECTOR
+# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L)
+#endif
+
+#ifndef STATUS_MORE_PROCESSING_REQUIRED
+# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L)
+#endif
+
+#ifndef STATUS_NO_MEMORY
+# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L)
+#endif
+
+#ifndef STATUS_CONFLICTING_ADDRESSES
+# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_VIEW
+# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_FREE_VM
+# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DELETE_SECTION
+# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL)
+#endif
+
+#ifndef STATUS_INVALID_SYSTEM_SERVICE
+# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL)
+#endif
+
+#ifndef STATUS_ILLEGAL_INSTRUCTION
+# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_SEQUENCE
+# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL)
+#endif
+
+#ifndef STATUS_INVALID_VIEW_SIZE
+# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL)
+#endif
+
+#ifndef STATUS_INVALID_FILE_FOR_SECTION
+# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L)
+#endif
+
+#ifndef STATUS_ALREADY_COMMITTED
+# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L)
+#endif
+
+#ifndef STATUS_ACCESS_DENIED
+# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L)
+#endif
+
+#ifndef STATUS_BUFFER_TOO_SMALL
+# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L)
+#endif
+
+#ifndef STATUS_OBJECT_TYPE_MISMATCH
+# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L)
+#endif
+
+#ifndef STATUS_NONCONTINUABLE_EXCEPTION
+# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L)
+#endif
+
+#ifndef STATUS_INVALID_DISPOSITION
+# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L)
+#endif
+
+#ifndef STATUS_UNWIND
+# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L)
+#endif
+
+#ifndef STATUS_BAD_STACK
+# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L)
+#endif
+
+#ifndef STATUS_INVALID_UNWIND_TARGET
+# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L)
+#endif
+
+#ifndef STATUS_NOT_LOCKED
+# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL)
+#endif
+
+#ifndef STATUS_PARITY_ERROR
+# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DECOMMIT_VM
+# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL)
+#endif
+
+#ifndef STATUS_NOT_COMMITTED
+# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL)
+#endif
+
+#ifndef STATUS_INVALID_PORT_ATTRIBUTES
+# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL)
+#endif
+
+#ifndef STATUS_PORT_MESSAGE_TOO_LONG
+# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_MIX
+# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L)
+#endif
+
+#ifndef STATUS_INVALID_QUOTA_LOWER
+# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L)
+#endif
+
+#ifndef STATUS_DISK_CORRUPT_ERROR
+# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_INVALID
+# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_NOT_FOUND
+# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_COLLISION
+# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L)
+#endif
+
+#ifndef STATUS_PORT_DISCONNECTED
+# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L)
+#endif
+
+#ifndef STATUS_DEVICE_ALREADY_ATTACHED
+# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_INVALID
+# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_NOT_FOUND
+# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD
+# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL)
+#endif
+
+#ifndef STATUS_DATA_OVERRUN
+# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL)
+#endif
+
+#ifndef STATUS_DATA_LATE_ERROR
+# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL)
+#endif
+
+#ifndef STATUS_DATA_ERROR
+# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL)
+#endif
+
+#ifndef STATUS_CRC_ERROR
+# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL)
+#endif
+
+#ifndef STATUS_SECTION_TOO_BIG
+# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L)
+#endif
+
+#ifndef STATUS_PORT_CONNECTION_REFUSED
+# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L)
+#endif
+
+#ifndef STATUS_INVALID_PORT_HANDLE
+# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L)
+#endif
+
+#ifndef STATUS_SHARING_VIOLATION
+# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L)
+#endif
+
+#ifndef STATUS_QUOTA_EXCEEDED
+# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L)
+#endif
+
+#ifndef STATUS_INVALID_PAGE_PROTECTION
+# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L)
+#endif
+
+#ifndef STATUS_MUTANT_NOT_OWNED
+# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L)
+#endif
+
+#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED
+# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_SET
+# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_IMAGE
+# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L)
+#endif
+
+#ifndef STATUS_SUSPEND_COUNT_EXCEEDED
+# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL)
+#endif
+
+#ifndef STATUS_THREAD_IS_TERMINATING
+# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL)
+#endif
+
+#ifndef STATUS_BAD_WORKING_SET_LIMIT
+# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_FILE_MAP
+# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL)
+#endif
+
+#ifndef STATUS_SECTION_PROTECTION
+# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL)
+#endif
+
+#ifndef STATUS_EAS_NOT_SUPPORTED
+# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL)
+#endif
+
+#ifndef STATUS_EA_TOO_LARGE
+# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_EA_ENTRY
+# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L)
+#endif
+
+#ifndef STATUS_NO_EAS_ON_FILE
+# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L)
+#endif
+
+#ifndef STATUS_EA_CORRUPT_ERROR
+# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L)
+#endif
+
+#ifndef STATUS_FILE_LOCK_CONFLICT
+# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L)
+#endif
+
+#ifndef STATUS_LOCK_NOT_GRANTED
+# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L)
+#endif
+
+#ifndef STATUS_DELETE_PENDING
+# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L)
+#endif
+
+#ifndef STATUS_CTL_FILE_NOT_SUPPORTED
+# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L)
+#endif
+
+#ifndef STATUS_UNKNOWN_REVISION
+# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L)
+#endif
+
+#ifndef STATUS_REVISION_MISMATCH
+# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L)
+#endif
+
+#ifndef STATUS_INVALID_OWNER
+# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL)
+#endif
+
+#ifndef STATUS_INVALID_PRIMARY_GROUP
+# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL)
+#endif
+
+#ifndef STATUS_NO_IMPERSONATION_TOKEN
+# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL)
+#endif
+
+#ifndef STATUS_CANT_DISABLE_MANDATORY
+# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL)
+#endif
+
+#ifndef STATUS_NO_LOGON_SERVERS
+# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_LOGON_SESSION
+# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PRIVILEGE
+# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L)
+#endif
+
+#ifndef STATUS_PRIVILEGE_NOT_HELD
+# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L)
+#endif
+
+#ifndef STATUS_INVALID_ACCOUNT_NAME
+# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L)
+#endif
+
+#ifndef STATUS_USER_EXISTS
+# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L)
+#endif
+
+#ifndef STATUS_NO_SUCH_USER
+# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L)
+#endif
+
+#ifndef STATUS_GROUP_EXISTS
+# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L)
+#endif
+
+#ifndef STATUS_NO_SUCH_GROUP
+# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_GROUP
+# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_GROUP
+# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L)
+#endif
+
+#ifndef STATUS_LAST_ADMIN
+# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD
+# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_PASSWORD
+# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL)
+#endif
+
+#ifndef STATUS_PASSWORD_RESTRICTION
+# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL)
+#endif
+
+#ifndef STATUS_LOGON_FAILURE
+# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL)
+#endif
+
+#ifndef STATUS_ACCOUNT_RESTRICTION
+# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_HOURS
+# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL)
+#endif
+
+#ifndef STATUS_INVALID_WORKSTATION
+# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L)
+#endif
+
+#ifndef STATUS_PASSWORD_EXPIRED
+# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L)
+#endif
+
+#ifndef STATUS_ACCOUNT_DISABLED
+# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L)
+#endif
+
+#ifndef STATUS_NONE_MAPPED
+# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED
+# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L)
+#endif
+
+#ifndef STATUS_LUIDS_EXHAUSTED
+# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L)
+#endif
+
+#ifndef STATUS_INVALID_SUB_AUTHORITY
+# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L)
+#endif
+
+#ifndef STATUS_INVALID_ACL
+# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L)
+#endif
+
+#ifndef STATUS_INVALID_SID
+# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L)
+#endif
+
+#ifndef STATUS_INVALID_SECURITY_DESCR
+# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L)
+#endif
+
+#ifndef STATUS_PROCEDURE_NOT_FOUND
+# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_FORMAT
+# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL)
+#endif
+
+#ifndef STATUS_NO_TOKEN
+# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL)
+#endif
+
+#ifndef STATUS_BAD_INHERITANCE_ACL
+# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_LOCKED
+# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL)
+#endif
+
+#ifndef STATUS_DISK_FULL
+# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL)
+#endif
+
+#ifndef STATUS_SERVER_DISABLED
+# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L)
+#endif
+
+#ifndef STATUS_SERVER_NOT_DISABLED
+# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L)
+#endif
+
+#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED
+# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L)
+#endif
+
+#ifndef STATUS_GUIDS_EXHAUSTED
+# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L)
+#endif
+
+#ifndef STATUS_INVALID_ID_AUTHORITY
+# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L)
+#endif
+
+#ifndef STATUS_AGENTS_EXHAUSTED
+# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L)
+#endif
+
+#ifndef STATUS_INVALID_VOLUME_LABEL
+# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_EXTENDED
+# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_DATA
+# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L)
+#endif
+
+#ifndef STATUS_RESOURCE_DATA_NOT_FOUND
+# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L)
+#endif
+
+#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND
+# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL)
+#endif
+
+#ifndef STATUS_RESOURCE_NAME_NOT_FOUND
+# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL)
+#endif
+
+#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED
+# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL)
+#endif
+
+#ifndef STATUS_FLOAT_DENORMAL_OPERAND
+# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL)
+#endif
+
+#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO
+# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL)
+#endif
+
+#ifndef STATUS_FLOAT_INEXACT_RESULT
+# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL)
+#endif
+
+#ifndef STATUS_FLOAT_INVALID_OPERATION
+# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L)
+#endif
+
+#ifndef STATUS_FLOAT_OVERFLOW
+# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L)
+#endif
+
+#ifndef STATUS_FLOAT_STACK_CHECK
+# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L)
+#endif
+
+#ifndef STATUS_FLOAT_UNDERFLOW
+# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L)
+#endif
+
+#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO
+# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L)
+#endif
+
+#ifndef STATUS_INTEGER_OVERFLOW
+# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L)
+#endif
+
+#ifndef STATUS_PRIVILEGED_INSTRUCTION
+# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PAGING_FILES
+# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L)
+#endif
+
+#ifndef STATUS_FILE_INVALID
+# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L)
+#endif
+
+#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED
+# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCES
+# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL)
+#endif
+
+#ifndef STATUS_DFS_EXIT_PATH_FOUND
+# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL)
+#endif
+
+#ifndef STATUS_DEVICE_DATA_ERROR
+# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_CONNECTED
+# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL)
+#endif
+
+#ifndef STATUS_DEVICE_POWER_FAILURE
+# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL)
+#endif
+
+#ifndef STATUS_FREE_VM_NOT_AT_BASE
+# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL)
+#endif
+
+#ifndef STATUS_MEMORY_NOT_ALLOCATED
+# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L)
+#endif
+
+#ifndef STATUS_WORKING_SET_QUOTA
+# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L)
+#endif
+
+#ifndef STATUS_MEDIA_WRITE_PROTECTED
+# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_READY
+# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)
+#endif
+
+#ifndef STATUS_INVALID_GROUP_ATTRIBUTES
+# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L)
+#endif
+
+#ifndef STATUS_BAD_IMPERSONATION_LEVEL
+# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L)
+#endif
+
+#ifndef STATUS_CANT_OPEN_ANONYMOUS
+# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L)
+#endif
+
+#ifndef STATUS_BAD_VALIDATION_CLASS
+# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L)
+#endif
+
+#ifndef STATUS_BAD_TOKEN_TYPE
+# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L)
+#endif
+
+#ifndef STATUS_BAD_MASTER_BOOT_RECORD
+# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L)
+#endif
+
+#ifndef STATUS_INSTRUCTION_MISALIGNMENT
+# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL)
+#endif
+
+#ifndef STATUS_INSTANCE_NOT_AVAILABLE
+# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL)
+#endif
+
+#ifndef STATUS_PIPE_NOT_AVAILABLE
+# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL)
+#endif
+
+#ifndef STATUS_INVALID_PIPE_STATE
+# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL)
+#endif
+
+#ifndef STATUS_PIPE_BUSY
+# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL)
+#endif
+
+#ifndef STATUS_ILLEGAL_FUNCTION
+# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL)
+#endif
+
+#ifndef STATUS_PIPE_DISCONNECTED
+# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L)
+#endif
+
+#ifndef STATUS_PIPE_CLOSING
+# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L)
+#endif
+
+#ifndef STATUS_PIPE_CONNECTED
+# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L)
+#endif
+
+#ifndef STATUS_PIPE_LISTENING
+# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L)
+#endif
+
+#ifndef STATUS_INVALID_READ_MODE
+# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L)
+#endif
+
+#ifndef STATUS_IO_TIMEOUT
+# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L)
+#endif
+
+#ifndef STATUS_FILE_FORCED_CLOSED
+# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STARTED
+# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STOPPED
+# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L)
+#endif
+
+#ifndef STATUS_COULD_NOT_INTERPRET
+# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L)
+#endif
+
+#ifndef STATUS_FILE_IS_A_DIRECTORY
+# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED
+# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL)
+#endif
+
+#ifndef STATUS_REMOTE_NOT_LISTENING
+# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL)
+#endif
+
+#ifndef STATUS_DUPLICATE_NAME
+# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_PATH
+# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL)
+#endif
+
+#ifndef STATUS_NETWORK_BUSY
+# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL)
+#endif
+
+#ifndef STATUS_DEVICE_DOES_NOT_EXIST
+# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L)
+#endif
+
+#ifndef STATUS_TOO_MANY_COMMANDS
+# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L)
+#endif
+
+#ifndef STATUS_ADAPTER_HARDWARE_ERROR
+# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L)
+#endif
+
+#ifndef STATUS_INVALID_NETWORK_RESPONSE
+# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_NETWORK_ERROR
+# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L)
+#endif
+
+#ifndef STATUS_BAD_REMOTE_ADAPTER
+# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L)
+#endif
+
+#ifndef STATUS_PRINT_QUEUE_FULL
+# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L)
+#endif
+
+#ifndef STATUS_NO_SPOOL_SPACE
+# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L)
+#endif
+
+#ifndef STATUS_PRINT_CANCELLED
+# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L)
+#endif
+
+#ifndef STATUS_NETWORK_NAME_DELETED
+# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L)
+#endif
+
+#ifndef STATUS_NETWORK_ACCESS_DENIED
+# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL)
+#endif
+
+#ifndef STATUS_BAD_DEVICE_TYPE
+# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_NAME
+# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NAMES
+# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SESSIONS
+# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL)
+#endif
+
+#ifndef STATUS_SHARING_PAUSED
+# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL)
+#endif
+
+#ifndef STATUS_REQUEST_NOT_ACCEPTED
+# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_PAUSED
+# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L)
+#endif
+
+#ifndef STATUS_NET_WRITE_FAULT
+# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L)
+#endif
+
+#ifndef STATUS_PROFILING_AT_LIMIT
+# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L)
+#endif
+
+#ifndef STATUS_NOT_SAME_DEVICE
+# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L)
+#endif
+
+#ifndef STATUS_FILE_RENAMED
+# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L)
+#endif
+
+#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED
+# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L)
+#endif
+
+#ifndef STATUS_NO_SECURITY_ON_OBJECT
+# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L)
+#endif
+
+#ifndef STATUS_CANT_WAIT
+# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L)
+#endif
+
+#ifndef STATUS_PIPE_EMPTY
+# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L)
+#endif
+
+#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO
+# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL)
+#endif
+
+#ifndef STATUS_CANT_TERMINATE_SELF
+# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL)
+#endif
+
+#ifndef STATUS_INVALID_SERVER_STATE
+# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_STATE
+# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_ROLE
+# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DOMAIN
+# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL)
+#endif
+
+#ifndef STATUS_DOMAIN_EXISTS
+# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L)
+#endif
+
+#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED
+# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L)
+#endif
+
+#ifndef STATUS_OPLOCK_NOT_GRANTED
+# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L)
+#endif
+
+#ifndef STATUS_INVALID_OPLOCK_PROTOCOL
+# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_CORRUPTION
+# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L)
+#endif
+
+#ifndef STATUS_INTERNAL_ERROR
+# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L)
+#endif
+
+#ifndef STATUS_GENERIC_NOT_MAPPED
+# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L)
+#endif
+
+#ifndef STATUS_BAD_DESCRIPTOR_FORMAT
+# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L)
+#endif
+
+#ifndef STATUS_INVALID_USER_BUFFER
+# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_IO_ERROR
+# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR
+# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR
+# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR
+# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL)
+#endif
+
+#ifndef STATUS_NOT_LOGON_PROCESS
+# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_EXISTS
+# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_1
+# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_2
+# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_3
+# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_4
+# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_5
+# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_6
+# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_7
+# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_8
+# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_9
+# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_10
+# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_11
+# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_12
+# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_NOT_STARTED
+# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_STARTED
+# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW
+# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PACKAGE
+# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL)
+#endif
+
+#ifndef STATUS_BAD_FUNCTION_TABLE
+# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL)
+#endif
+
+#ifndef STATUS_VARIABLE_NOT_FOUND
+# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L)
+#endif
+
+#ifndef STATUS_DIRECTORY_NOT_EMPTY
+# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L)
+#endif
+
+#ifndef STATUS_FILE_CORRUPT_ERROR
+# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L)
+#endif
+
+#ifndef STATUS_NOT_A_DIRECTORY
+# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L)
+#endif
+
+#ifndef STATUS_BAD_LOGON_SESSION_STATE
+# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_COLLISION
+# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L)
+#endif
+
+#ifndef STATUS_NAME_TOO_LONG
+# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L)
+#endif
+
+#ifndef STATUS_FILES_OPEN
+# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L)
+#endif
+
+#ifndef STATUS_CONNECTION_IN_USE
+# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L)
+#endif
+
+#ifndef STATUS_MESSAGE_NOT_FOUND
+# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_TERMINATING
+# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_TYPE
+# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL)
+#endif
+
+#ifndef STATUS_NO_GUID_TRANSLATION
+# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL)
+#endif
+
+#ifndef STATUS_CANNOT_IMPERSONATE
+# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED
+# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_PRESENT
+# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL)
+#endif
+
+#ifndef STATUS_ABIOS_LID_NOT_EXIST
+# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L)
+#endif
+
+#ifndef STATUS_ABIOS_LID_ALREADY_OWNED
+# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_LID_OWNER
+# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_COMMAND
+# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_LID
+# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L)
+#endif
+
+#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
+# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_SELECTOR
+# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L)
+#endif
+
+#ifndef STATUS_NO_LDT
+# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_SIZE
+# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_OFFSET
+# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_DESCRIPTOR
+# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NE_FORMAT
+# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL)
+#endif
+
+#ifndef STATUS_RXACT_INVALID_STATE
+# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_FAILURE
+# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL)
+#endif
+
+#ifndef STATUS_MAPPED_FILE_SIZE_ZERO
+# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL)
+#endif
+
+#ifndef STATUS_TOO_MANY_OPENED_FILES
+# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL)
+#endif
+
+#ifndef STATUS_CANCELLED
+# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
+#endif
+
+#ifndef STATUS_CANNOT_DELETE
+# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L)
+#endif
+
+#ifndef STATUS_INVALID_COMPUTER_NAME
+# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L)
+#endif
+
+#ifndef STATUS_FILE_DELETED
+# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L)
+#endif
+
+#ifndef STATUS_SPECIAL_ACCOUNT
+# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L)
+#endif
+
+#ifndef STATUS_SPECIAL_GROUP
+# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L)
+#endif
+
+#ifndef STATUS_SPECIAL_USER
+# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L)
+#endif
+
+#ifndef STATUS_MEMBERS_PRIMARY_GROUP
+# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L)
+#endif
+
+#ifndef STATUS_FILE_CLOSED
+# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L)
+#endif
+
+#ifndef STATUS_TOO_MANY_THREADS
+# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L)
+#endif
+
+#ifndef STATUS_THREAD_NOT_IN_PROCESS
+# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL)
+#endif
+
+#ifndef STATUS_TOKEN_ALREADY_IN_USE
+# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED
+# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL)
+#endif
+
+#ifndef STATUS_COMMITMENT_LIMIT
+# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_LE_FORMAT
+# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NOT_MZ
+# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_PROTECT
+# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_16
+# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L)
+#endif
+
+#ifndef STATUS_LOGON_SERVER_CONFLICT
+# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L)
+#endif
+
+#ifndef STATUS_TIME_DIFFERENCE_AT_DC
+# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L)
+#endif
+
+#ifndef STATUS_SYNCHRONIZATION_REQUIRED
+# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L)
+#endif
+
+#ifndef STATUS_DLL_NOT_FOUND
+# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L)
+#endif
+
+#ifndef STATUS_OPEN_FAILED
+# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L)
+#endif
+
+#ifndef STATUS_IO_PRIVILEGE_FAILED
+# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L)
+#endif
+
+#ifndef STATUS_ORDINAL_NOT_FOUND
+# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L)
+#endif
+
+#ifndef STATUS_ENTRYPOINT_NOT_FOUND
+# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L)
+#endif
+
+#ifndef STATUS_CONTROL_C_EXIT
+# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL)
+#endif
+
+#ifndef STATUS_LOCAL_DISCONNECT
+# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL)
+#endif
+
+#ifndef STATUS_REMOTE_DISCONNECT
+# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL)
+#endif
+
+#ifndef STATUS_REMOTE_RESOURCES
+# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL)
+#endif
+
+#ifndef STATUS_LINK_FAILED
+# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL)
+#endif
+
+#ifndef STATUS_LINK_TIMEOUT
+# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL)
+#endif
+
+#ifndef STATUS_INVALID_CONNECTION
+# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS
+# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED
+# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L)
+#endif
+
+#ifndef STATUS_MISSING_SYSTEMFILE
+# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L)
+#endif
+
+#ifndef STATUS_UNHANDLED_EXCEPTION
+# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L)
+#endif
+
+#ifndef STATUS_APP_INIT_FAILURE
+# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L)
+#endif
+
+#ifndef STATUS_PAGEFILE_CREATE_FAILED
+# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L)
+#endif
+
+#ifndef STATUS_NO_PAGEFILE
+# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L)
+#endif
+
+#ifndef STATUS_INVALID_LEVEL
+# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD_CORE
+# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L)
+#endif
+
+#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT
+# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL)
+#endif
+
+#ifndef STATUS_PIPE_BROKEN
+# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL)
+#endif
+
+#ifndef STATUS_REGISTRY_CORRUPT
+# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL)
+#endif
+
+#ifndef STATUS_REGISTRY_IO_FAILED
+# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL)
+#endif
+
+#ifndef STATUS_NO_EVENT_PAIR
+# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_VOLUME
+# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL)
+#endif
+
+#ifndef STATUS_SERIAL_NO_DEVICE_INITED
+# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L)
+#endif
+
+#ifndef STATUS_NO_SUCH_ALIAS
+# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_ALIAS
+# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_ALIAS
+# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L)
+#endif
+
+#ifndef STATUS_ALIAS_EXISTS
+# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L)
+#endif
+
+#ifndef STATUS_LOGON_NOT_GRANTED
+# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L)
+#endif
+
+#ifndef STATUS_TOO_MANY_SECRETS
+# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L)
+#endif
+
+#ifndef STATUS_SECRET_TOO_LONG
+# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_ERROR
+# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L)
+#endif
+
+#ifndef STATUS_FULLSCREEN_MODE
+# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L)
+#endif
+
+#ifndef STATUS_TOO_MANY_CONTEXT_IDS
+# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL)
+#endif
+
+#ifndef STATUS_LOGON_TYPE_NOT_GRANTED
+# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL)
+#endif
+
+#ifndef STATUS_NOT_REGISTRY_FILE
+# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL)
+#endif
+
+#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL)
+#endif
+
+#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL)
+#endif
+
+#ifndef STATUS_FT_MISSING_MEMBER
+# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY
+# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L)
+#endif
+
+#ifndef STATUS_ILLEGAL_CHARACTER
+# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L)
+#endif
+
+#ifndef STATUS_UNMAPPABLE_CHARACTER
+# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L)
+#endif
+
+#ifndef STATUS_UNDEFINED_CHARACTER
+# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L)
+#endif
+
+#ifndef STATUS_FLOPPY_VOLUME
+# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L)
+#endif
+
+#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND
+# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L)
+#endif
+
+#ifndef STATUS_FLOPPY_WRONG_CYLINDER
+# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L)
+#endif
+
+#ifndef STATUS_FLOPPY_UNKNOWN_ERROR
+# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L)
+#endif
+
+#ifndef STATUS_FLOPPY_BAD_REGISTERS
+# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L)
+#endif
+
+#ifndef STATUS_DISK_RECALIBRATE_FAILED
+# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L)
+#endif
+
+#ifndef STATUS_DISK_OPERATION_FAILED
+# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL)
+#endif
+
+#ifndef STATUS_DISK_RESET_FAILED
+# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL)
+#endif
+
+#ifndef STATUS_SHARED_IRQ_BUSY
+# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL)
+#endif
+
+#ifndef STATUS_FT_ORPHANING
+# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL)
+#endif
+
+#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL)
+#endif
+
+#ifndef STATUS_PARTITION_FAILURE
+# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L)
+#endif
+
+#ifndef STATUS_INVALID_BLOCK_LENGTH
+# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_PARTITIONED
+# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_LOCK_MEDIA
+# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA
+# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L)
+#endif
+
+#ifndef STATUS_EOM_OVERFLOW
+# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L)
+#endif
+
+#ifndef STATUS_NO_MEDIA
+# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L)
+#endif
+
+#ifndef STATUS_NO_SUCH_MEMBER
+# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL)
+#endif
+
+#ifndef STATUS_INVALID_MEMBER
+# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL)
+#endif
+
+#ifndef STATUS_KEY_DELETED
+# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL)
+#endif
+
+#ifndef STATUS_NO_LOG_SPACE
+# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SIDS
+# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL)
+#endif
+
+#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL)
+#endif
+
+#ifndef STATUS_KEY_HAS_CHILDREN
+# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L)
+#endif
+
+#ifndef STATUS_CHILD_MUST_BE_VOLATILE
+# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L)
+#endif
+
+#ifndef STATUS_DEVICE_CONFIGURATION_ERROR
+# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L)
+#endif
+
+#ifndef STATUS_DRIVER_INTERNAL_ERROR
+# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_STATE
+# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L)
+#endif
+
+#ifndef STATUS_IO_DEVICE_ERROR
+# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L)
+#endif
+
+#ifndef STATUS_DEVICE_PROTOCOL_ERROR
+# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L)
+#endif
+
+#ifndef STATUS_BACKUP_CONTROLLER
+# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L)
+#endif
+
+#ifndef STATUS_LOG_FILE_FULL
+# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L)
+#endif
+
+#ifndef STATUS_TOO_LATE
+# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L)
+#endif
+
+#ifndef STATUS_NO_TRUST_LSA_SECRET
+# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL)
+#endif
+
+#ifndef STATUS_NO_TRUST_SAM_ACCOUNT
+# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL)
+#endif
+
+#ifndef STATUS_TRUSTED_DOMAIN_FAILURE
+# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL)
+#endif
+
+#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE
+# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CORRUPT
+# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL)
+#endif
+
+#ifndef STATUS_EVENTLOG_CANT_START
+# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL)
+#endif
+
+#ifndef STATUS_TRUST_FAILURE
+# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L)
+#endif
+
+#ifndef STATUS_MUTANT_LIMIT_EXCEEDED
+# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L)
+#endif
+
+#ifndef STATUS_NETLOGON_NOT_STARTED
+# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L)
+#endif
+
+#ifndef STATUS_ACCOUNT_EXPIRED
+# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L)
+#endif
+
+#ifndef STATUS_POSSIBLE_DEADLOCK
+# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L)
+#endif
+
+#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT
+# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L)
+#endif
+
+#ifndef STATUS_REMOTE_SESSION_LIMIT
+# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CHANGED
+# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L)
+#endif
+
+#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L)
+#endif
+
+#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L)
+#endif
+
+#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL)
+#endif
+
+#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT
+# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL)
+#endif
+
+#ifndef STATUS_FS_DRIVER_REQUIRED
+# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL)
+#endif
+
+#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL)
+#endif
+
+#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT
+# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_RANGE
+# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L)
+#endif
+
+#ifndef STATUS_INVALID_ACE_CONDITION
+# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L)
+#endif
+
+#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L)
+#endif
+
+#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L)
+#endif
+
+#ifndef STATUS_NETWORK_OPEN_RESTRICTION
+# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L)
+#endif
+
+#ifndef STATUS_NO_USER_SESSION_KEY
+# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L)
+#endif
+
+#ifndef STATUS_USER_SESSION_DELETED
+# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L)
+#endif
+
+#ifndef STATUS_RESOURCE_LANG_NOT_FOUND
+# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L)
+#endif
+
+#ifndef STATUS_INSUFF_SERVER_RESOURCES
+# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L)
+#endif
+
+#ifndef STATUS_INVALID_BUFFER_SIZE
+# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_COMPONENT
+# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_WILDCARD
+# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L)
+#endif
+
+#ifndef STATUS_TOO_MANY_ADDRESSES
+# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_EXISTS
+# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL)
+#endif
+
+#ifndef STATUS_ADDRESS_CLOSED
+# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL)
+#endif
+
+#ifndef STATUS_CONNECTION_DISCONNECTED
+# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL)
+#endif
+
+#ifndef STATUS_CONNECTION_RESET
+# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NODES
+# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL)
+#endif
+
+#ifndef STATUS_TRANSACTION_ABORTED
+# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL)
+#endif
+
+#ifndef STATUS_TRANSACTION_TIMED_OUT
+# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_RELEASE
+# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_MATCH
+# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L)
+#endif
+
+#ifndef STATUS_TRANSACTION_RESPONDED
+# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_ID
+# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_TYPE
+# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L)
+#endif
+
+#ifndef STATUS_NOT_SERVER_SESSION
+# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L)
+#endif
+
+#ifndef STATUS_NOT_CLIENT_SESSION
+# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L)
+#endif
+
+#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE
+# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L)
+#endif
+
+#ifndef STATUS_DEBUG_ATTACH_FAILED
+# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L)
+#endif
+
+#ifndef STATUS_SYSTEM_PROCESS_TERMINATED
+# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL)
+#endif
+
+#ifndef STATUS_DATA_NOT_ACCEPTED
+# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL)
+#endif
+
+#ifndef STATUS_NO_BROWSER_SERVERS_FOUND
+# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL)
+#endif
+
+#ifndef STATUS_VDM_HARD_ERROR
+# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL)
+#endif
+
+#ifndef STATUS_DRIVER_CANCEL_TIMEOUT
+# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL)
+#endif
+
+#ifndef STATUS_REPLY_MESSAGE_MISMATCH
+# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL)
+#endif
+
+#ifndef STATUS_MAPPED_ALIGNMENT
+# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L)
+#endif
+
+#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH
+# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA
+# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L)
+#endif
+
+#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L)
+#endif
+
+#ifndef STATUS_PASSWORD_MUST_CHANGE
+# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L)
+#endif
+
+#ifndef STATUS_NOT_FOUND
+# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
+#endif
+
+#ifndef STATUS_NOT_TINY_STREAM
+# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L)
+#endif
+
+#ifndef STATUS_RECOVERY_FAILURE
+# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW_READ
+# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L)
+#endif
+
+#ifndef STATUS_FAIL_CHECK
+# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L)
+#endif
+
+#ifndef STATUS_DUPLICATE_OBJECTID
+# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL)
+#endif
+
+#ifndef STATUS_OBJECTID_EXISTS
+# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL)
+#endif
+
+#ifndef STATUS_CONVERT_TO_LARGE
+# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL)
+#endif
+
+#ifndef STATUS_RETRY
+# define STATUS_RETRY ((NTSTATUS) 0xC000022DL)
+#endif
+
+#ifndef STATUS_FOUND_OUT_OF_SCOPE
+# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL)
+#endif
+
+#ifndef STATUS_ALLOCATE_BUCKET
+# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL)
+#endif
+
+#ifndef STATUS_PROPSET_NOT_FOUND
+# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L)
+#endif
+
+#ifndef STATUS_MARSHALL_OVERFLOW
+# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L)
+#endif
+
+#ifndef STATUS_INVALID_VARIANT
+# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L)
+#endif
+
+#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L)
+#endif
+
+#ifndef STATUS_ACCOUNT_LOCKED_OUT
+# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L)
+#endif
+
+#ifndef STATUS_HANDLE_NOT_CLOSABLE
+# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L)
+#endif
+
+#ifndef STATUS_CONNECTION_REFUSED
+# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L)
+#endif
+
+#ifndef STATUS_GRACEFUL_DISCONNECT
+# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED
+# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L)
+#endif
+
+#ifndef STATUS_ADDRESS_NOT_ASSOCIATED
+# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L)
+#endif
+
+#ifndef STATUS_CONNECTION_INVALID
+# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL)
+#endif
+
+#ifndef STATUS_CONNECTION_ACTIVE
+# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL)
+#endif
+
+#ifndef STATUS_NETWORK_UNREACHABLE
+# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL)
+#endif
+
+#ifndef STATUS_HOST_UNREACHABLE
+# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL)
+#endif
+
+#ifndef STATUS_PROTOCOL_UNREACHABLE
+# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL)
+#endif
+
+#ifndef STATUS_PORT_UNREACHABLE
+# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL)
+#endif
+
+#ifndef STATUS_REQUEST_ABORTED
+# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L)
+#endif
+
+#ifndef STATUS_CONNECTION_ABORTED
+# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L)
+#endif
+
+#ifndef STATUS_BAD_COMPRESSION_BUFFER
+# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L)
+#endif
+
+#ifndef STATUS_USER_MAPPED_FILE
+# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L)
+#endif
+
+#ifndef STATUS_AUDIT_FAILED
+# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L)
+#endif
+
+#ifndef STATUS_TIMER_RESOLUTION_NOT_SET
+# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L)
+#endif
+
+#ifndef STATUS_CONNECTION_COUNT_LIMIT
+# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L)
+#endif
+
+#ifndef STATUS_LOGIN_TIME_RESTRICTION
+# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L)
+#endif
+
+#ifndef STATUS_LOGIN_WKSTA_RESTRICTION
+# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L)
+#endif
+
+#ifndef STATUS_IMAGE_MP_UP_MISMATCH
+# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_LOGON_INFO
+# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L)
+#endif
+
+#ifndef STATUS_BAD_DLL_ENTRYPOINT
+# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L)
+#endif
+
+#ifndef STATUS_BAD_SERVICE_ENTRYPOINT
+# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L)
+#endif
+
+#ifndef STATUS_LPC_REPLY_LOST
+# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT1
+# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT2
+# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L)
+#endif
+
+#ifndef STATUS_REGISTRY_QUOTA_LIMIT
+# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L)
+#endif
+
+#ifndef STATUS_PATH_NOT_COVERED
+# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L)
+#endif
+
+#ifndef STATUS_NO_CALLBACK_ACTIVE
+# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L)
+#endif
+
+#ifndef STATUS_LICENSE_QUOTA_EXCEEDED
+# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L)
+#endif
+
+#ifndef STATUS_PWD_TOO_SHORT
+# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL)
+#endif
+
+#ifndef STATUS_PWD_TOO_RECENT
+# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL)
+#endif
+
+#ifndef STATUS_PWD_HISTORY_CONFLICT
+# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL)
+#endif
+
+#ifndef STATUS_PLUGPLAY_NO_DEVICE
+# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_COMPRESSION
+# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL)
+#endif
+
+#ifndef STATUS_INVALID_HW_PROFILE
+# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L)
+#endif
+
+#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L)
+#endif
+
+#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND
+# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L)
+#endif
+
+#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L)
+#endif
+
+#ifndef STATUS_RESOURCE_NOT_OWNED
+# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LINKS
+# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L)
+#endif
+
+#ifndef STATUS_QUOTA_LIST_INCONSISTENT
+# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L)
+#endif
+
+#ifndef STATUS_FILE_IS_OFFLINE
+# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L)
+#endif
+
+#ifndef STATUS_EVALUATION_EXPIRATION
+# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L)
+#endif
+
+#ifndef STATUS_ILLEGAL_DLL_RELOCATION
+# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L)
+#endif
+
+#ifndef STATUS_LICENSE_VIOLATION
+# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED_LOGOFF
+# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL)
+#endif
+
+#ifndef STATUS_DRIVER_UNABLE_TO_LOAD
+# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL)
+#endif
+
+#ifndef STATUS_DFS_UNAVAILABLE
+# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL)
+#endif
+
+#ifndef STATUS_VOLUME_DISMOUNTED
+# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL)
+#endif
+
+#ifndef STATUS_WX86_INTERNAL_ERROR
+# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL)
+#endif
+
+#ifndef STATUS_WX86_FLOAT_STACK_CHECK
+# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L)
+#endif
+
+#ifndef STATUS_VALIDATE_CONTINUE
+# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L)
+#endif
+
+#ifndef STATUS_NO_MATCH
+# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L)
+#endif
+
+#ifndef STATUS_NO_MORE_MATCHES
+# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L)
+#endif
+
+#ifndef STATUS_NOT_A_REPARSE_POINT
+# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_INVALID
+# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_MISMATCH
+# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_DATA_INVALID
+# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED
+# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L)
+#endif
+
+#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED
+# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L)
+#endif
+
+#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT
+# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L)
+#endif
+
+#ifndef STATUS_RANGE_LIST_CONFLICT
+# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L)
+#endif
+
+#ifndef STATUS_SOURCE_ELEMENT_EMPTY
+# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L)
+#endif
+
+#ifndef STATUS_DESTINATION_ELEMENT_FULL
+# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L)
+#endif
+
+#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS
+# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L)
+#endif
+
+#ifndef STATUS_MAGAZINE_NOT_PRESENT
+# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L)
+#endif
+
+#ifndef STATUS_REINITIALIZATION_NEEDED
+# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L)
+#endif
+
+#ifndef STATUS_DEVICE_REQUIRES_CLEANING
+# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L)
+#endif
+
+#ifndef STATUS_DEVICE_DOOR_OPEN
+# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L)
+#endif
+
+#ifndef STATUS_ENCRYPTION_FAILED
+# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL)
+#endif
+
+#ifndef STATUS_DECRYPTION_FAILED
+# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_FOUND
+# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL)
+#endif
+
+#ifndef STATUS_NO_RECOVERY_POLICY
+# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL)
+#endif
+
+#ifndef STATUS_NO_EFS
+# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL)
+#endif
+
+#ifndef STATUS_WRONG_EFS
+# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL)
+#endif
+
+#ifndef STATUS_NO_USER_KEYS
+# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L)
+#endif
+
+#ifndef STATUS_FILE_NOT_ENCRYPTED
+# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L)
+#endif
+
+#ifndef STATUS_NOT_EXPORT_FORMAT
+# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L)
+#endif
+
+#ifndef STATUS_FILE_ENCRYPTED
+# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM
+# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L)
+#endif
+
+#ifndef STATUS_WMI_GUID_NOT_FOUND
+# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L)
+#endif
+
+#ifndef STATUS_WMI_INSTANCE_NOT_FOUND
+# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L)
+#endif
+
+#ifndef STATUS_WMI_ITEMID_NOT_FOUND
+# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L)
+#endif
+
+#ifndef STATUS_WMI_TRY_AGAIN
+# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L)
+#endif
+
+#ifndef STATUS_SHARED_POLICY
+# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L)
+#endif
+
+#ifndef STATUS_POLICY_OBJECT_NOT_FOUND
+# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL)
+#endif
+
+#ifndef STATUS_POLICY_ONLY_IN_DS
+# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL)
+#endif
+
+#ifndef STATUS_VOLUME_NOT_UPGRADED
+# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE
+# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR
+# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL)
+#endif
+
+#ifndef STATUS_NO_TRACKING_SERVICE
+# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL)
+#endif
+
+#ifndef STATUS_SERVER_SID_MISMATCH
+# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L)
+#endif
+
+#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L)
+#endif
+
+#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L)
+#endif
+
+#ifndef STATUS_DS_BUSY
+# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L)
+#endif
+
+#ifndef STATUS_DS_UNAVAILABLE
+# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L)
+#endif
+
+#ifndef STATUS_DS_NO_RIDS_ALLOCATED
+# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L)
+#endif
+
+#ifndef STATUS_DS_NO_MORE_RIDS
+# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L)
+#endif
+
+#ifndef STATUS_DS_INCORRECT_ROLE_OWNER
+# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L)
+#endif
+
+#ifndef STATUS_DS_RIDMGR_INIT_ERROR
+# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL)
+#endif
+
+#ifndef STATUS_DS_OBJ_CLASS_VIOLATION
+# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_NON_LEAF
+# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_RDN
+# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS
+# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL)
+#endif
+
+#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED
+# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL)
+#endif
+
+#ifndef STATUS_DS_GC_NOT_AVAILABLE
+# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L)
+#endif
+
+#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED
+# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L)
+#endif
+
+#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT
+# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L)
+#endif
+
+#ifndef STATUS_CANT_ENABLE_DENY_ONLY
+# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
+# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
+# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L)
+#endif
+
+#ifndef STATUS_DEVICE_REMOVED
+# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L)
+#endif
+
+#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS
+# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L)
+#endif
+
+#ifndef STATUS_JOURNAL_NOT_ACTIVE
+# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L)
+#endif
+
+#ifndef STATUS_NOINTERFACE
+# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L)
+#endif
+
+#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED
+# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_SLEEP
+# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L)
+#endif
+
+#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED
+# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L)
+#endif
+
+#ifndef STATUS_CORRUPT_SYSTEM_FILE
+# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR
+# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L)
+#endif
+
+#ifndef STATUS_WMI_READ_ONLY
+# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L)
+#endif
+
+#ifndef STATUS_WMI_SET_FAILURE
+# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L)
+#endif
+
+#ifndef STATUS_COMMITMENT_MINIMUM
+# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L)
+#endif
+
+#ifndef STATUS_REG_NAT_CONSUMPTION
+# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L)
+#endif
+
+#ifndef STATUS_TRANSPORT_FULL
+# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE
+# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL)
+#endif
+
+#ifndef STATUS_ONLY_IF_CONNECTED
+# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL)
+#endif
+
+#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION
+# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL)
+#endif
+
+#ifndef STATUS_PNP_RESTART_ENUMERATION
+# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL)
+#endif
+
+#ifndef STATUS_JOURNAL_ENTRY_DELETED
+# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID
+# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L)
+#endif
+
+#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L)
+#endif
+
+#ifndef STATUS_PNP_REBOOT_REQUIRED
+# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L)
+#endif
+
+#ifndef STATUS_POWER_STATE_INVALID
+# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L)
+#endif
+
+#ifndef STATUS_DS_INVALID_GROUP_TYPE
+# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L)
+#endif
+
+#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL)
+#endif
+
+#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL)
+#endif
+
+#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS
+# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL)
+#endif
+
+#ifndef STATUS_WMI_NOT_SUPPORTED
+# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_POWER
+# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD
+# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY
+# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L)
+#endif
+
+#ifndef STATUS_DS_CANT_START
+# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE
+# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L)
+#endif
+
+#ifndef STATUS_SAM_INIT_FAILURE
+# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L)
+#endif
+
+#ifndef STATUS_DS_GC_REQUIRED
+# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L)
+#endif
+
+#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L)
+#endif
+
+#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L)
+#endif
+
+#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L)
+#endif
+
+#ifndef STATUS_MULTIPLE_FAULT_VIOLATION
+# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L)
+#endif
+
+#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L)
+#endif
+
+#ifndef STATUS_CANNOT_MAKE
+# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL)
+#endif
+
+#ifndef STATUS_SYSTEM_SHUTDOWN
+# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE_CONSOLE
+# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL)
+#endif
+
+#ifndef STATUS_UNFINISHED_CONTEXT_DELETED
+# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL)
+#endif
+
+#ifndef STATUS_NO_TGT_REPLY
+# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL)
+#endif
+
+#ifndef STATUS_OBJECTID_NOT_FOUND
+# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L)
+#endif
+
+#ifndef STATUS_NO_IP_ADDRESSES
+# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L)
+#endif
+
+#ifndef STATUS_WRONG_CREDENTIAL_HANDLE
+# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L)
+#endif
+
+#ifndef STATUS_CRYPTO_SYSTEM_INVALID
+# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L)
+#endif
+
+#ifndef STATUS_MAX_REFERRALS_EXCEEDED
+# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L)
+#endif
+
+#ifndef STATUS_MUST_BE_KDC
+# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L)
+#endif
+
+#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PRINCIPALS
+# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L)
+#endif
+
+#ifndef STATUS_NO_PA_DATA
+# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L)
+#endif
+
+#ifndef STATUS_PKINIT_NAME_MISMATCH
+# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L)
+#endif
+
+#ifndef STATUS_SMARTCARD_LOGON_REQUIRED
+# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL)
+#endif
+
+#ifndef STATUS_KDC_INVALID_REQUEST
+# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL)
+#endif
+
+#ifndef STATUS_KDC_UNABLE_TO_REFER
+# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL)
+#endif
+
+#ifndef STATUS_KDC_UNKNOWN_ETYPE
+# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL)
+#endif
+
+#ifndef STATUS_SHUTDOWN_IN_PROGRESS
+# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL)
+#endif
+
+#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED_ON_SBS
+# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L)
+#endif
+
+#ifndef STATUS_WMI_GUID_DISCONNECTED
+# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_DISABLED
+# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_ENABLED
+# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L)
+#endif
+
+#ifndef STATUS_MFT_TOO_FRAGMENTED
+# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L)
+#endif
+
+#ifndef STATUS_COPY_PROTECTION_FAILURE
+# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L)
+#endif
+
+#ifndef STATUS_CSS_AUTHENTICATION_FAILURE
+# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_PRESENT
+# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED
+# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L)
+#endif
+
+#ifndef STATUS_CSS_SCRAMBLED_SECTOR
+# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L)
+#endif
+
+#ifndef STATUS_CSS_REGION_MISMATCH
+# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL)
+#endif
+
+#ifndef STATUS_CSS_RESETS_EXHAUSTED
+# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL)
+#endif
+
+#ifndef STATUS_PKINIT_FAILURE
+# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L)
+#endif
+
+#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L)
+#endif
+
+#ifndef STATUS_NO_KERB_KEY
+# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L)
+#endif
+
+#ifndef STATUS_HOST_DOWN
+# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_PREAUTH
+# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L)
+#endif
+
+#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG
+# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L)
+#endif
+
+#ifndef STATUS_PORT_NOT_SET
+# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L)
+#endif
+
+#ifndef STATUS_DEBUGGER_INACTIVE
+# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L)
+#endif
+
+#ifndef STATUS_DS_VERSION_CHECK_FAILURE
+# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L)
+#endif
+
+#ifndef STATUS_AUDITING_DISABLED
+# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L)
+#endif
+
+#ifndef STATUS_PRENT4_MACHINE_ACCOUNT
+# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L)
+#endif
+
+#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_32
+# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_64
+# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL)
+#endif
+
+#ifndef STATUS_BAD_BINDINGS
+# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL)
+#endif
+
+#ifndef STATUS_NETWORK_SESSION_EXPIRED
+# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL)
+#endif
+
+#ifndef STATUS_APPHELP_BLOCK
+# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL)
+#endif
+
+#ifndef STATUS_ALL_SIDS_FILTERED
+# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL)
+#endif
+
+#ifndef STATUS_NOT_SAFE_MODE_DRIVER
+# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L)
+#endif
+
+#ifndef STATUS_FAILED_DRIVER_ENTRY
+# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L)
+#endif
+
+#ifndef STATUS_DEVICE_ENUMERATION_ERROR
+# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L)
+#endif
+
+#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED
+# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L)
+#endif
+
+#ifndef STATUS_MCA_OCCURED
+# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED_CRITICAL
+# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED
+# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL)
+#endif
+
+#ifndef STATUS_DRIVER_DATABASE_ERROR
+# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL)
+#endif
+
+#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE
+# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL)
+#endif
+
+#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL
+# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL)
+#endif
+
+#ifndef STATUS_DS_SHUTTING_DOWN
+# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L)
+#endif
+
+#ifndef STATUS_NO_SECRETS
+# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L)
+#endif
+
+#ifndef STATUS_FAILED_STACK_SWITCH
+# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L)
+#endif
+
+#ifndef STATUS_HEAP_CORRUPTION
+# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L)
+#endif
+
+#ifndef STATUS_SMARTCARD_WRONG_PIN
+# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_BLOCKED
+# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CARD
+# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER
+# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CERTIFICATE
+# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEYSET
+# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L)
+#endif
+
+#ifndef STATUS_SMARTCARD_IO_ERROR
+# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L)
+#endif
+
+#ifndef STATUS_DOWNGRADE_DETECTED
+# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_REVOKED
+# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED
+# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_C
+# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL)
+#endif
+
+#ifndef STATUS_PKINIT_CLIENT_FAILURE
+# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_EXPIRED
+# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL)
+#endif
+
+#ifndef STATUS_SMARTCARD_SILENT_CONTEXT
+# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL)
+#endif
+
+#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L)
+#endif
+
+#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L)
+#endif
+
+#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L)
+#endif
+
+#ifndef STATUS_DS_NAME_NOT_UNIQUE
+# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L)
+#endif
+
+#ifndef STATUS_DS_DUPLICATE_ID_FOUND
+# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L)
+#endif
+
+#ifndef STATUS_DS_GROUP_CONVERSION_ERROR
+# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L)
+#endif
+
+#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE
+# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L)
+#endif
+
+#ifndef STATUS_USER2USER_REQUIRED
+# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L)
+#endif
+
+#ifndef STATUS_STACK_BUFFER_OVERRUN
+# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L)
+#endif
+
+#ifndef STATUS_NO_S4U_PROT_SUPPORT
+# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL)
+#endif
+
+#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE
+# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_KDC
+# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC
+# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL)
+#endif
+
+#ifndef STATUS_KDC_CERT_EXPIRED
+# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL)
+#endif
+
+#ifndef STATUS_KDC_CERT_REVOKED
+# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL)
+#endif
+
+#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED
+# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L)
+#endif
+
+#ifndef STATUS_HIBERNATION_FAILURE
+# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L)
+#endif
+
+#ifndef STATUS_DELAY_LOAD_FAILED
+# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L)
+#endif
+
+#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED
+# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L)
+#endif
+
+#ifndef STATUS_VDM_DISALLOWED
+# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L)
+#endif
+
+#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD
+# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L)
+#endif
+
+#ifndef STATUS_INVALID_CRUNTIME_PARAMETER
+# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L)
+#endif
+
+#ifndef STATUS_NTLM_BLOCKED
+# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L)
+#endif
+
+#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL)
+#endif
+
+#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL)
+#endif
+
+#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME
+# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL)
+#endif
+
+#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
+# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL)
+#endif
+
+#ifndef STATUS_ASSERTION_FAILURE
+# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L)
+#endif
+
+#ifndef STATUS_VERIFIER_STOP
+# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L)
+#endif
+
+#ifndef STATUS_CALLBACK_POP_STACK
+# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L)
+#endif
+
+#ifndef STATUS_HIVE_UNLOADED
+# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L)
+#endif
+
+#ifndef STATUS_COMPRESSION_DISABLED
+# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L)
+#endif
+
+#ifndef STATUS_FILE_SYSTEM_LIMITATION
+# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_HASH
+# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L)
+#endif
+
+#ifndef STATUS_NOT_CAPABLE
+# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L)
+#endif
+
+#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE
+# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL)
+#endif
+
+#ifndef STATUS_IMPLEMENTATION_LIMIT
+# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL)
+#endif
+
+#ifndef STATUS_ELEVATION_REQUIRED
+# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL)
+#endif
+
+#ifndef STATUS_NO_SECURITY_CONTEXT
+# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL)
+#endif
+
+#ifndef STATUS_PKU2U_CERT_FAILURE
+# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL)
+#endif
+
+#ifndef STATUS_BEYOND_VDL
+# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L)
+#endif
+
+#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L)
+#endif
+
+#ifndef STATUS_PTE_CHANGED
+# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L)
+#endif
+
+#ifndef STATUS_PURGE_FAILED
+# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L)
+#endif
+
+#ifndef STATUS_CRED_REQUIRES_CONFIRMATION
+# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L)
+#endif
+
+#ifndef STATUS_INVALID_LABEL
+# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L)
+#endif
+
+#ifndef STATUS_DRIVER_PROCESS_TERMINATED
+# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L)
+#endif
+
+#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE
+# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L)
+#endif
+
+#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND
+# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L)
+#endif
+
+#ifndef STATUS_RESTART_BOOT_APPLICATION
+# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES
+# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_NAME
+# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_INDEX
+# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L)
+#endif
+
+#ifndef STATUS_THREAD_ALREADY_IN_TASK
+# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L)
+#endif
+
+#ifndef STATUS_CALLBACK_BYPASS
+# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L)
+#endif
+
+#ifndef STATUS_FAIL_FAST_EXCEPTION
+# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L)
+#endif
+
+#ifndef STATUS_IMAGE_CERT_REVOKED
+# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L)
+#endif
+
+#ifndef STATUS_PORT_CLOSED
+# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L)
+#endif
+
+#ifndef STATUS_MESSAGE_LOST
+# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L)
+#endif
+
+#ifndef STATUS_INVALID_MESSAGE
+# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L)
+#endif
+
+#ifndef STATUS_REQUEST_CANCELED
+# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L)
+#endif
+
+#ifndef STATUS_RECURSIVE_DISPATCH
+# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L)
+#endif
+
+#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L)
+#endif
+
+#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE
+# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L)
+#endif
+
+#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED
+# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L)
+#endif
+
+#ifndef STATUS_RESOURCE_IN_USE
+# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L)
+#endif
+
+#ifndef STATUS_HARDWARE_MEMORY_ERROR
+# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L)
+#endif
+
+#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION
+# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL)
+#endif
+
+#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL)
+#endif
+
+#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L)
+#endif
+
+#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING
+# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_PROTECTED
+# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L)
+#endif
+
+#ifndef STATUS_MCA_EXCEPTION
+# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L)
+#endif
+
+#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L)
+#endif
+
+#ifndef STATUS_SYMLINK_CLASS_DISABLED
+# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L)
+#endif
+
+#ifndef STATUS_INVALID_IDN_NORMALIZATION
+# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L)
+#endif
+
+#ifndef STATUS_NO_UNICODE_TRANSLATION
+# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L)
+#endif
+
+#ifndef STATUS_ALREADY_REGISTERED
+# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L)
+#endif
+
+#ifndef STATUS_CONTEXT_MISMATCH
+# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL)
+#endif
+
+#ifndef STATUS_INVALID_THREAD
+# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION
+# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK
+# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LANG
+# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK
+# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L)
+#endif
+
+#ifndef STATUS_DISK_REPAIR_DISABLED
+# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L)
+#endif
+
+#ifndef STATUS_DISK_QUOTA_EXCEEDED
+# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L)
+#endif
+
+#ifndef STATUS_DATA_LOST_REPAIR
+# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L)
+#endif
+
+#ifndef STATUS_CONTENT_BLOCKED
+# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L)
+#endif
+
+#ifndef STATUS_BAD_CLUSTERS
+# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L)
+#endif
+
+#ifndef STATUS_VOLUME_DIRTY
+# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L)
+#endif
+
+#ifndef STATUS_FILE_CHECKED_OUT
+# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L)
+#endif
+
+#ifndef STATUS_CHECKOUT_REQUIRED
+# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L)
+#endif
+
+#ifndef STATUS_BAD_FILE_TYPE
+# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L)
+#endif
+
+#ifndef STATUS_FILE_TOO_LARGE
+# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L)
+#endif
+
+#ifndef STATUS_FORMS_AUTH_REQUIRED
+# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L)
+#endif
+
+#ifndef STATUS_VIRUS_INFECTED
+# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L)
+#endif
+
+#ifndef STATUS_VIRUS_DELETED
+# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L)
+#endif
+
+#ifndef STATUS_BAD_MCFG_TABLE
+# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L)
+#endif
+
+#ifndef STATUS_CANNOT_BREAK_OPLOCK
+# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L)
+#endif
+
+#ifndef STATUS_WOW_ASSERTION
+# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L)
+#endif
+
+#ifndef STATUS_INVALID_SIGNATURE
+# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L)
+#endif
+
+#ifndef STATUS_HMAC_NOT_SUPPORTED
+# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L)
+#endif
+
+#ifndef STATUS_AUTH_TAG_MISMATCH
+# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L)
+#endif
+
+#ifndef STATUS_IPSEC_QUEUE_OVERFLOW
+# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L)
+#endif
+
+#ifndef STATUS_ND_QUEUE_OVERFLOW
+# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L)
+#endif
+
+#ifndef STATUS_HOPLIMIT_EXCEEDED
+# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L)
+#endif
+
+#ifndef STATUS_PROTOCOL_NOT_SUPPORTED
+# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L)
+#endif
+
+#ifndef STATUS_FASTPATH_REJECTED
+# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L)
+#endif
+
+#ifndef STATUS_XML_PARSE_ERROR
+# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L)
+#endif
+
+#ifndef STATUS_XMLDSIG_ERROR
+# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L)
+#endif
+
+#ifndef STATUS_WRONG_COMPARTMENT
+# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L)
+#endif
+
+#ifndef STATUS_AUTHIP_FAILURE
+# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L)
+#endif
+
+#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L)
+#endif
+
+#ifndef STATUS_DS_OID_NOT_FOUND
+# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L)
+#endif
+
+#ifndef STATUS_HASH_NOT_SUPPORTED
+# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L)
+#endif
+
+#ifndef STATUS_HASH_NOT_PRESENT
+# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
+#endif
+
+/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
+/* DDK got it wrong! */
+#ifdef NTSTATUS_FROM_WIN32
+# undef NTSTATUS_FROM_WIN32
+#endif
+#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \
+ ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \
+ (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
+
+#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY
+# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100
+#endif
+#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY
+# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200
+#endif
+#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
+# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400
+#endif
+#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800
+#endif
+#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000
+#endif
+#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
+#endif
+
+/* from winternl.h */
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+/* from ntifs.h */
+#ifndef DEVICE_TYPE
+# define DEVICE_TYPE DWORD
+#endif
+
+/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
+ * not.
+ */
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+ } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#endif
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ } DUMMYUNIONNAME;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileAttributeCacheInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_DIRECTORY_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
+
+typedef struct _FILE_BOTH_DIR_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ CCHAR ShortNameLength;
+ WCHAR ShortName[12];
+ WCHAR FileName[1];
+} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
+
+typedef struct _FILE_BASIC_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef struct _FILE_STANDARD_INFORMATION {
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG NumberOfLinks;
+ BOOLEAN DeletePending;
+ BOOLEAN Directory;
+} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
+
+typedef struct _FILE_INTERNAL_INFORMATION {
+ LARGE_INTEGER IndexNumber;
+} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
+
+typedef struct _FILE_EA_INFORMATION {
+ ULONG EaSize;
+} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
+
+typedef struct _FILE_ACCESS_INFORMATION {
+ ACCESS_MASK AccessFlags;
+} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
+
+typedef struct _FILE_POSITION_INFORMATION {
+ LARGE_INTEGER CurrentByteOffset;
+} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
+
+typedef struct _FILE_MODE_INFORMATION {
+ ULONG Mode;
+} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
+
+typedef struct _FILE_ALIGNMENT_INFORMATION {
+ ULONG AlignmentRequirement;
+} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef struct _FILE_END_OF_FILE_INFORMATION {
+ LARGE_INTEGER EndOfFile;
+} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
+
+typedef struct _FILE_ALL_INFORMATION {
+ FILE_BASIC_INFORMATION BasicInformation;
+ FILE_STANDARD_INFORMATION StandardInformation;
+ FILE_INTERNAL_INFORMATION InternalInformation;
+ FILE_EA_INFORMATION EaInformation;
+ FILE_ACCESS_INFORMATION AccessInformation;
+ FILE_POSITION_INFORMATION PositionInformation;
+ FILE_MODE_INFORMATION ModeInformation;
+ FILE_ALIGNMENT_INFORMATION AlignmentInformation;
+ FILE_NAME_INFORMATION NameInformation;
+} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
+
+typedef struct _FILE_DISPOSITION_INFORMATION {
+ BOOLEAN DeleteFile;
+} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
+
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+
+typedef enum _FS_INFORMATION_CLASS {
+ FileFsVolumeInformation = 1,
+ FileFsLabelInformation = 2,
+ FileFsSizeInformation = 3,
+ FileFsDeviceInformation = 4,
+ FileFsAttributeInformation = 5,
+ FileFsControlInformation = 6,
+ FileFsFullSizeInformation = 7,
+ FileFsObjectIdInformation = 8,
+ FileFsDriverPathInformation = 9,
+ FileFsVolumeFlagsInformation = 10,
+ FileFsSectorSizeInformation = 11
+} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
+
+typedef struct _FILE_FS_VOLUME_INFORMATION {
+ LARGE_INTEGER VolumeCreationTime;
+ ULONG VolumeSerialNumber;
+ ULONG VolumeLabelLength;
+ BOOLEAN SupportsObjects;
+ WCHAR VolumeLabel[1];
+} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;
+
+typedef struct _FILE_FS_LABEL_INFORMATION {
+ ULONG VolumeLabelLength;
+ WCHAR VolumeLabel[1];
+} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;
+
+typedef struct _FILE_FS_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER AvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_DEVICE_INFORMATION {
+ DEVICE_TYPE DeviceType;
+ ULONG Characteristics;
+} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
+
+typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
+ ULONG FileSystemAttributes;
+ LONG MaximumComponentNameLength;
+ ULONG FileSystemNameLength;
+ WCHAR FileSystemName[1];
+} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
+
+typedef struct _FILE_FS_CONTROL_INFORMATION {
+ LARGE_INTEGER FreeSpaceStartFiltering;
+ LARGE_INTEGER FreeSpaceThreshold;
+ LARGE_INTEGER FreeSpaceStopFiltering;
+ LARGE_INTEGER DefaultQuotaThreshold;
+ LARGE_INTEGER DefaultQuotaLimit;
+ ULONG FileSystemControlFlags;
+} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
+
+typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER CallerAvailableAllocationUnits;
+ LARGE_INTEGER ActualAvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_OBJECTID_INFORMATION {
+ UCHAR ObjectId[16];
+ UCHAR ExtendedInfo[48];
+} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;
+
+typedef struct _FILE_FS_DRIVER_PATH_INFORMATION {
+ BOOLEAN DriverInPath;
+ ULONG DriverNameLength;
+ WCHAR DriverName[1];
+} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;
+
+typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION {
+ ULONG Flags;
+} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;
+
+typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
+ ULONG LogicalBytesPerSector;
+ ULONG PhysicalBytesPerSectorForAtomicity;
+ ULONG PhysicalBytesPerSectorForPerformance;
+ ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
+ ULONG Flags;
+ ULONG ByteOffsetForSectorAlignment;
+ ULONG ByteOffsetForPartitionAlignment;
+} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
+
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+#ifndef SystemProcessorPerformanceInformation
+# define SystemProcessorPerformanceInformation 8
+#endif
+
+#ifndef FILE_DEVICE_FILE_SYSTEM
+# define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#endif
+
+#ifndef FILE_DEVICE_NETWORK
+# define FILE_DEVICE_NETWORK 0x00000012
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef METHOD_IN_DIRECT
+# define METHOD_IN_DIRECT 1
+#endif
+
+#ifndef METHOD_OUT_DIRECT
+# define METHOD_OUT_DIRECT 2
+#endif
+
+#ifndef METHOD_NEITHER
+#define METHOD_NEITHER 3
+#endif
+
+#ifndef METHOD_DIRECT_TO_HARDWARE
+# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
+#endif
+
+#ifndef METHOD_DIRECT_FROM_HARDWARE
+# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0
+#endif
+
+#ifndef FILE_SPECIAL_ACCESS
+# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
+#endif
+
+#ifndef FILE_READ_ACCESS
+# define FILE_READ_ACCESS 0x0001
+#endif
+
+#ifndef FILE_WRITE_ACCESS
+# define FILE_WRITE_ACCESS 0x0002
+#endif
+
+#ifndef CTL_CODE
+# define CTL_CODE(device_type, function, method, access) \
+ (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method))
+#endif
+
+#ifndef FSCTL_SET_REPARSE_POINT
+# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 41, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 42, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+#endif
+
+#ifndef FSCTL_DELETE_REPARSE_POINT
+# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 43, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+
+typedef VOID (NTAPI *PIO_APC_ROUTINE)
+ (PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG Reserved);
+
+typedef ULONG (NTAPI *sRtlNtStatusToDosError)
+ (NTSTATUS Status);
+
+typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG IoControlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferLength,
+ PVOID OutputBuffer,
+ ULONG OutputBufferLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtSetInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FsInformation,
+ ULONG Length,
+ FS_INFORMATION_CLASS FsInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
+ (UINT SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass,
+ BOOLEAN ReturnSingleEntry,
+ PUNICODE_STRING FileName,
+ BOOLEAN RestartScan
+ );
+
+/*
+ * Kernel32 headers
+ */
+#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
+#endif
+
+#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE
+# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _OVERLAPPED_ENTRY {
+ ULONG_PTR lpCompletionKey;
+ LPOVERLAPPED lpOverlapped;
+ ULONG_PTR Internal;
+ DWORD dwNumberOfBytesTransferred;
+ } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
+#endif
+
+/* from wincon.h */
+#ifndef ENABLE_INSERT_MODE
+# define ENABLE_INSERT_MODE 0x20
+#endif
+
+#ifndef ENABLE_QUICK_EDIT_MODE
+# define ENABLE_QUICK_EDIT_MODE 0x40
+#endif
+
+#ifndef ENABLE_EXTENDED_FLAGS
+# define ENABLE_EXTENDED_FLAGS 0x80
+#endif
+
+/* from winerror.h */
+#ifndef ERROR_SYMLINK_NOT_SUPPORTED
+# define ERROR_SYMLINK_NOT_SUPPORTED 1464
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_FOUND
+# define ERROR_MUI_FILE_NOT_FOUND 15100
+#endif
+
+#ifndef ERROR_MUI_INVALID_FILE
+# define ERROR_MUI_INVALID_FILE 15101
+#endif
+
+#ifndef ERROR_MUI_INVALID_RC_CONFIG
+# define ERROR_MUI_INVALID_RC_CONFIG 15102
+#endif
+
+#ifndef ERROR_MUI_INVALID_LOCALE_NAME
+# define ERROR_MUI_INVALID_LOCALE_NAME 15103
+#endif
+
+#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_LOADED
+# define ERROR_MUI_FILE_NOT_LOADED 15105
+#endif
+
+typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
+ (HANDLE CompletionPort,
+ LPOVERLAPPED_ENTRY lpCompletionPortEntries,
+ ULONG ulCount,
+ PULONG ulNumEntriesRemoved,
+ DWORD dwMilliseconds,
+ BOOL fAlertable);
+
+typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
+ (HANDLE FileHandle,
+ UCHAR Flags);
+
+typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
+ (LPCWSTR lpSymlinkFileName,
+ LPCWSTR lpTargetFileName,
+ DWORD dwFlags);
+
+typedef BOOL (WINAPI* sCancelIoEx)
+ (HANDLE hFile,
+ LPOVERLAPPED lpOverlapped);
+
+typedef VOID (WINAPI* sInitializeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sSleepConditionVariableCS)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef BOOL (WINAPI* sSleepConditionVariableSRW)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PSRWLOCK SRWLock,
+ DWORD dwMilliseconds,
+ ULONG Flags);
+
+typedef VOID (WINAPI* sWakeAllConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef VOID (WINAPI* sWakeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sCancelSynchronousIo)
+ (HANDLE hThread);
+
+typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
+ (HANDLE hFile,
+ LPWSTR lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+/* Ntdll function pointers */
+extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
+extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
+extern sNtQueryInformationFile pNtQueryInformationFile;
+extern sNtSetInformationFile pNtSetInformationFile;
+extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
+extern sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
+extern sCancelIoEx pCancelIoEx;
+extern sInitializeConditionVariable pInitializeConditionVariable;
+extern sSleepConditionVariableCS pSleepConditionVariableCS;
+extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
+extern sWakeAllConditionVariable pWakeAllConditionVariable;
+extern sWakeConditionVariable pWakeConditionVariable;
+extern sCancelSynchronousIo pCancelSynchronousIo;
+extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+#endif /* UV_WIN_WINAPI_H_ */
diff --git a/3rdparty/libuv/src/win/winsock.c b/3rdparty/libuv/src/win/winsock.c
new file mode 100644
index 00000000000..d2e667e9f75
--- /dev/null
+++ b/3rdparty/libuv/src/win/winsock.c
@@ -0,0 +1,561 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+int uv_tcp_non_ifs_lsp_ipv4;
+int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+struct sockaddr_in uv_addr_ip4_any_;
+struct sockaddr_in6 uv_addr_ip6_any_;
+
+
+/*
+ * Retrieves the pointer to a winsock extension function.
+ */
+static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+ void **target) {
+ int result;
+ DWORD bytes;
+
+ result = WSAIoctl(socket,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid,
+ sizeof(guid),
+ (void*)target,
+ sizeof(*target),
+ &bytes,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR) {
+ *target = NULL;
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
+ const GUID wsaid_acceptex = WSAID_ACCEPTEX;
+ return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
+}
+
+
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
+ const GUID wsaid_connectex = WSAID_CONNECTEX;
+ return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
+}
+
+
+static int error_means_no_support(DWORD error) {
+ return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
+ error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
+}
+
+
+void uv_winsock_init() {
+ WSADATA wsa_data;
+ int errorno;
+ SOCKET dummy;
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+
+ /* Initialize winsock */
+ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (errorno != 0) {
+ uv_fatal_error(errorno, "WSAStartup");
+ }
+
+ /* Set implicit binding address used by connectEx */
+ if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
+ abort();
+ }
+
+ if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
+ abort();
+ }
+
+ /* Detect non-IFS LSPs */
+ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv4 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+
+ /* Detect IPV6 support and non-IFS LSPs */
+ dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv6 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+}
+
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ return WSAENOBUFS;
+
+ case STATUS_TOO_MANY_ADDRESSES:
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ case STATUS_HOPLIMIT_EXCEEDED:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
+ (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
+}
+
+
+/*
+ * This function provides a workaround for a bug in the winsock implementation
+ * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
+ * used to avoid IOCP notifications of completed reads, WSARecv does not
+ * reliably indicate whether we can expect a completion package to be posted
+ * when the receive buffer is smaller than the received datagram.
+ *
+ * However it is desirable to use SetFileCompletionNotificationModes because
+ * it yields a massive performance increase.
+ *
+ * This function provides a workaround for that bug, but it only works for the
+ * specific case that we need it for. E.g. it assumes that the "avoid iocp"
+ * bit has been set, and supports only overlapped operation. It also requires
+ * the user to use the default msafd driver, doesn't work when other LSPs are
+ * stacked on top of it.
+ */
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+/* See description of uv_wsarecv_workaround. */
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_DATAGRAM_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || addr == NULL || addr_len == NULL ||
+ completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+ info.Address = addr;
+ info.AddressLength = addr_len;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE_DATAGRAM,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
+ IO_STATUS_BLOCK iosb;
+ IO_STATUS_BLOCK* iosb_ptr;
+ HANDLE event = NULL;
+ void* apc_context;
+ NTSTATUS status;
+ DWORD error;
+
+ if (overlapped != NULL) {
+ /* Overlapped operation. */
+ iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ event = overlapped->hEvent;
+
+ /* Do not report iocp completion if hEvent is tagged. */
+ if ((uintptr_t) event & 1) {
+ event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+ apc_context = NULL;
+ } else {
+ apc_context = overlapped;
+ }
+
+ } else {
+ /* Blocking operation. */
+ iosb_ptr = &iosb;
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return SOCKET_ERROR;
+ }
+ apc_context = NULL;
+ }
+
+ iosb_ptr->Status = STATUS_PENDING;
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ event,
+ NULL,
+ apc_context,
+ iosb_ptr,
+ IOCTL_AFD_POLL,
+ info_in,
+ sizeof *info_in,
+ info_out,
+ sizeof *info_out);
+
+ if (overlapped == NULL) {
+ /* If this is a blocking operation, wait for the event to become */
+ /* signaled, and then grab the real status from the io status block. */
+ if (status == STATUS_PENDING) {
+ DWORD r = WaitForSingleObject(event, INFINITE);
+
+ if (r == WAIT_FAILED) {
+ DWORD saved_error = GetLastError();
+ CloseHandle(event);
+ WSASetLastError(saved_error);
+ return SOCKET_ERROR;
+ }
+
+ status = iosb.Status;
+ }
+
+ CloseHandle(event);
+ }
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
diff --git a/3rdparty/libuv/src/win/winsock.h b/3rdparty/libuv/src/win/winsock.h
new file mode 100644
index 00000000000..7c007ab4934
--- /dev/null
+++ b/3rdparty/libuv/src/win/winsock.h
@@ -0,0 +1,190 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINSOCK_H_
+#define UV_WIN_WINSOCK_H_
+
+#include <winsock2.h>
+#include <iptypes.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include "winapi.h"
+
+
+/*
+ * MinGW is missing these too
+ */
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+#ifndef TCP_KEEPALIVE
+# define TCP_KEEPALIVE 3
+#endif
+
+#ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+#endif
+
+#ifndef IPV6_HOPLIMIT
+# define IPV6_HOPLIMIT 21
+#endif
+
+#ifndef SIO_BASE_HANDLE
+# define SIO_BASE_HANDLE 0x48000022
+#endif
+
+/*
+ * TDI defines that are only in the DDK.
+ * We only need receive flags so far.
+ */
+#ifndef TDI_RECEIVE_NORMAL
+ #define TDI_RECEIVE_BROADCAST 0x00000004
+ #define TDI_RECEIVE_MULTICAST 0x00000008
+ #define TDI_RECEIVE_PARTIAL 0x00000010
+ #define TDI_RECEIVE_NORMAL 0x00000020
+ #define TDI_RECEIVE_EXPEDITED 0x00000040
+ #define TDI_RECEIVE_PEEK 0x00000080
+ #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
+ #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
+ #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
+ #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
+ #define TDI_RECEIVE_CONTROL_INFO 0x00001000
+ #define TDI_RECEIVE_FORCE_INDICATION 0x00002000
+ #define TDI_RECEIVE_NO_PUSH 0x00004000
+#endif
+
+/*
+ * The "Auxiliary Function Driver" is the windows kernel-mode driver that does
+ * TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
+ * Having these definitions allows us to bypass winsock and make an AFD kernel
+ * call directly, avoiding a bug in winsock's recvfrom implementation.
+ */
+
+#define AFD_NO_FAST_IO 0x00000001
+#define AFD_OVERLAPPED 0x00000002
+#define AFD_IMMEDIATE 0x00000004
+
+#define AFD_POLL_RECEIVE_BIT 0
+#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
+#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
+#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
+#define AFD_POLL_SEND_BIT 2
+#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
+#define AFD_POLL_DISCONNECT_BIT 3
+#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
+#define AFD_POLL_ABORT_BIT 4
+#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
+#define AFD_POLL_LOCAL_CLOSE_BIT 5
+#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
+#define AFD_POLL_CONNECT_BIT 6
+#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
+#define AFD_POLL_ACCEPT_BIT 7
+#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
+#define AFD_POLL_CONNECT_FAIL_BIT 8
+#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
+#define AFD_POLL_QOS_BIT 9
+#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
+#define AFD_POLL_GROUP_QOS_BIT 10
+#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
+
+#define AFD_NUM_POLL_EVENTS 11
+#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
+
+typedef struct _AFD_RECV_DATAGRAM_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+ struct sockaddr* Address;
+ int* AddressLength;
+} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
+
+typedef struct _AFD_RECV_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+} AFD_RECV_INFO, *PAFD_RECV_INFO;
+
+
+#define _AFD_CONTROL_CODE(operation, method) \
+ ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
+
+#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
+
+#define AFD_RECEIVE 5
+#define AFD_RECEIVE_DATAGRAM 6
+#define AFD_POLL 9
+
+#define IOCTL_AFD_RECEIVE \
+ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
+
+#define IOCTL_AFD_RECEIVE_DATAGRAM \
+ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
+
+#define IOCTL_AFD_POLL \
+ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
+ /* FIXME: __C89_NAMELESS was removed */
+ /* __C89_NAMELESS */ union {
+ ULONGLONG Alignment;
+ /* __C89_NAMELESS */ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+ UINT8 OnLinkPrefixLength;
+} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
+
+#endif
+
+#endif /* UV_WIN_WINSOCK_H_ */
diff --git a/3rdparty/libuv/test/benchmark-async-pummel.c b/3rdparty/libuv/test/benchmark-async-pummel.c
new file mode 100644
index 00000000000..cca3de1062b
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-async-pummel.c
@@ -0,0 +1,119 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_PINGS (1000 * 1000)
+#define ACCESS_ONCE(type, var) (*(volatile type*) &(var))
+
+static unsigned int callbacks;
+static volatile int done;
+
+static const char running[] = "running";
+static const char stop[] = "stop";
+static const char stopped[] = "stopped";
+
+
+static void async_cb(uv_async_t* handle) {
+ if (++callbacks == NUM_PINGS) {
+ /* Tell the pummel thread to stop. */
+ ACCESS_ONCE(const char*, handle->data) = stop;
+
+ /* Wait for for the pummel thread to acknowledge that it has stoppped. */
+ while (ACCESS_ONCE(const char*, handle->data) != stopped)
+ uv_sleep(0);
+
+ uv_close((uv_handle_t*) handle, NULL);
+ }
+}
+
+
+static void pummel(void* arg) {
+ uv_async_t* handle = (uv_async_t*) arg;
+
+ while (ACCESS_ONCE(const char*, handle->data) == running)
+ uv_async_send(handle);
+
+ /* Acknowledge that we've seen handle->data change. */
+ ACCESS_ONCE(const char*, handle->data) = stopped;
+}
+
+
+static int test_async_pummel(int nthreads) {
+ uv_thread_t* tids;
+ uv_async_t handle;
+ uint64_t time;
+ int i;
+
+ tids = calloc(nthreads, sizeof(tids[0]));
+ ASSERT(tids != NULL);
+
+ ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb));
+ ACCESS_ONCE(const char*, handle.data) = running;
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_create(tids + i, pummel, &handle));
+
+ time = uv_hrtime();
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ time = uv_hrtime() - time;
+ done = 1;
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_join(tids + i));
+
+ printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n",
+ nthreads,
+ fmt(callbacks),
+ time / 1e9,
+ fmt(callbacks / (time / 1e9)));
+
+ free(tids);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(async_pummel_1) {
+ return test_async_pummel(1);
+}
+
+
+BENCHMARK_IMPL(async_pummel_2) {
+ return test_async_pummel(2);
+}
+
+
+BENCHMARK_IMPL(async_pummel_4) {
+ return test_async_pummel(4);
+}
+
+
+BENCHMARK_IMPL(async_pummel_8) {
+ return test_async_pummel(8);
+}
diff --git a/3rdparty/libuv/test/benchmark-async.c b/3rdparty/libuv/test/benchmark-async.c
new file mode 100644
index 00000000000..e44165f2b81
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-async.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_PINGS (1000 * 1000)
+
+struct ctx {
+ uv_loop_t loop;
+ uv_thread_t thread;
+ uv_async_t main_async; /* wake up main thread */
+ uv_async_t worker_async; /* wake up worker */
+ unsigned int nthreads;
+ unsigned int main_sent;
+ unsigned int main_seen;
+ unsigned int worker_sent;
+ unsigned int worker_seen;
+};
+
+
+static void worker_async_cb(uv_async_t* handle) {
+ struct ctx* ctx = container_of(handle, struct ctx, worker_async);
+
+ ASSERT(0 == uv_async_send(&ctx->main_async));
+ ctx->worker_sent++;
+ ctx->worker_seen++;
+
+ if (ctx->worker_sent >= NUM_PINGS)
+ uv_close((uv_handle_t*) &ctx->worker_async, NULL);
+}
+
+
+static void main_async_cb(uv_async_t* handle) {
+ struct ctx* ctx = container_of(handle, struct ctx, main_async);
+
+ ASSERT(0 == uv_async_send(&ctx->worker_async));
+ ctx->main_sent++;
+ ctx->main_seen++;
+
+ if (ctx->main_sent >= NUM_PINGS)
+ uv_close((uv_handle_t*) &ctx->main_async, NULL);
+}
+
+
+static void worker(void* arg) {
+ struct ctx* ctx = arg;
+ ASSERT(0 == uv_async_send(&ctx->main_async));
+ ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT));
+ uv_loop_close(&ctx->loop);
+}
+
+
+static int test_async(int nthreads) {
+ struct ctx* threads;
+ struct ctx* ctx;
+ uint64_t time;
+ int i;
+
+ threads = calloc(nthreads, sizeof(threads[0]));
+ ASSERT(threads != NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ ctx = threads + i;
+ ctx->nthreads = nthreads;
+ ASSERT(0 == uv_loop_init(&ctx->loop));
+ ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb));
+ ASSERT(0 == uv_async_init(uv_default_loop(),
+ &ctx->main_async,
+ main_async_cb));
+ ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx));
+ }
+
+ time = uv_hrtime();
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_join(&threads[i].thread));
+
+ time = uv_hrtime() - time;
+
+ for (i = 0; i < nthreads; i++) {
+ ctx = threads + i;
+ ASSERT(ctx->worker_sent == NUM_PINGS);
+ ASSERT(ctx->worker_seen == NUM_PINGS);
+ ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS);
+ ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS);
+ }
+
+ printf("async%d: %.2f sec (%s/sec)\n",
+ nthreads,
+ time / 1e9,
+ fmt(NUM_PINGS / (time / 1e9)));
+
+ free(threads);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(async1) {
+ return test_async(1);
+}
+
+
+BENCHMARK_IMPL(async2) {
+ return test_async(2);
+}
+
+
+BENCHMARK_IMPL(async4) {
+ return test_async(4);
+}
+
+
+BENCHMARK_IMPL(async8) {
+ return test_async(8);
+}
diff --git a/3rdparty/libuv/test/benchmark-fs-stat.c b/3rdparty/libuv/test/benchmark-fs-stat.c
new file mode 100644
index 00000000000..32d2589586c
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-fs-stat.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_SYNC_REQS (10 * 1e5)
+#define NUM_ASYNC_REQS (1 * (int) 1e5)
+#define MAX_CONCURRENT_REQS 32
+
+#define sync_stat(req, path) \
+ do { \
+ uv_fs_stat(NULL, (req), (path), NULL); \
+ uv_fs_req_cleanup((req)); \
+ } \
+ while (0)
+
+struct async_req {
+ const char* path;
+ uv_fs_t fs_req;
+ int* count;
+};
+
+
+static void warmup(const char* path) {
+ uv_fs_t reqs[MAX_CONCURRENT_REQS];
+ unsigned int i;
+
+ /* warm up the thread pool */
+ for (i = 0; i < ARRAY_SIZE(reqs); i++)
+ uv_fs_stat(uv_default_loop(), reqs + i, path, uv_fs_req_cleanup);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ /* warm up the OS dirent cache */
+ for (i = 0; i < 16; i++)
+ sync_stat(reqs + 0, path);
+}
+
+
+static void sync_bench(const char* path) {
+ uint64_t before;
+ uint64_t after;
+ uv_fs_t req;
+ int i;
+
+ /* do the sync benchmark */
+ before = uv_hrtime();
+
+ for (i = 0; i < NUM_SYNC_REQS; i++)
+ sync_stat(&req, path);
+
+ after = uv_hrtime();
+
+ printf("%s stats (sync): %.2fs (%s/s)\n",
+ fmt(1.0 * NUM_SYNC_REQS),
+ (after - before) / 1e9,
+ fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9)));
+ fflush(stdout);
+}
+
+
+static void stat_cb(uv_fs_t* fs_req) {
+ struct async_req* req = container_of(fs_req, struct async_req, fs_req);
+ uv_fs_req_cleanup(&req->fs_req);
+ if (*req->count == 0) return;
+ uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
+ (*req->count)--;
+}
+
+
+static void async_bench(const char* path) {
+ struct async_req reqs[MAX_CONCURRENT_REQS];
+ struct async_req* req;
+ uint64_t before;
+ uint64_t after;
+ int count;
+ int i;
+
+ for (i = 1; i <= MAX_CONCURRENT_REQS; i++) {
+ count = NUM_ASYNC_REQS;
+
+ for (req = reqs; req < reqs + i; req++) {
+ req->path = path;
+ req->count = &count;
+ uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
+ }
+
+ before = uv_hrtime();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ after = uv_hrtime();
+
+ printf("%s stats (%d concurrent): %.2fs (%s/s)\n",
+ fmt(1.0 * NUM_ASYNC_REQS),
+ i,
+ (after - before) / 1e9,
+ fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9)));
+ fflush(stdout);
+ }
+}
+
+
+/* This benchmark aims to measure the overhead of doing I/O syscalls from
+ * the thread pool. The stat() syscall was chosen because its results are
+ * easy for the operating system to cache, taking the actual I/O overhead
+ * out of the equation.
+ */
+BENCHMARK_IMPL(fs_stat) {
+ const char path[] = ".";
+ warmup(path);
+ sync_bench(path);
+ async_bench(path);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-getaddrinfo.c b/3rdparty/libuv/test/benchmark-getaddrinfo.c
new file mode 100644
index 00000000000..1dbc23ddba0
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-getaddrinfo.c
@@ -0,0 +1,92 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdlib.h>
+
+#define CONCURRENT_CALLS 10
+#define TOTAL_CALLS 10000
+
+static const char* name = "localhost";
+
+static uv_loop_t* loop;
+
+static uv_getaddrinfo_t handles[CONCURRENT_CALLS];
+
+static int calls_initiated = 0;
+static int calls_completed = 0;
+static int64_t start_time;
+static int64_t end_time;
+
+
+static void getaddrinfo_initiate(uv_getaddrinfo_t* handle);
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status,
+ struct addrinfo* res) {
+ ASSERT(status == 0);
+ calls_completed++;
+ if (calls_initiated < TOTAL_CALLS) {
+ getaddrinfo_initiate(handle);
+ }
+
+ uv_freeaddrinfo(res);
+}
+
+
+static void getaddrinfo_initiate(uv_getaddrinfo_t* handle) {
+ int r;
+
+ calls_initiated++;
+
+ r = uv_getaddrinfo(loop, handle, &getaddrinfo_cb, name, NULL, NULL);
+ ASSERT(r == 0);
+}
+
+
+BENCHMARK_IMPL(getaddrinfo) {
+ int i;
+
+ loop = uv_default_loop();
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+
+ for (i = 0; i < CONCURRENT_CALLS; i++) {
+ getaddrinfo_initiate(&handles[i]);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ uv_update_time(loop);
+ end_time = uv_now(loop);
+
+ ASSERT(calls_initiated == TOTAL_CALLS);
+ ASSERT(calls_completed == TOTAL_CALLS);
+
+ fprintf(stderr, "getaddrinfo: %.0f req/s\n",
+ (double) calls_completed / (double) (end_time - start_time) * 1000.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-list.h b/3rdparty/libuv/test/benchmark-list.h
new file mode 100644
index 00000000000..1e843071c01
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-list.h
@@ -0,0 +1,163 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+BENCHMARK_DECLARE (sizes)
+BENCHMARK_DECLARE (loop_count)
+BENCHMARK_DECLARE (loop_count_timed)
+BENCHMARK_DECLARE (ping_pongs)
+BENCHMARK_DECLARE (tcp_write_batch)
+BENCHMARK_DECLARE (tcp4_pound_100)
+BENCHMARK_DECLARE (tcp4_pound_1000)
+BENCHMARK_DECLARE (pipe_pound_100)
+BENCHMARK_DECLARE (pipe_pound_1000)
+BENCHMARK_DECLARE (tcp_pump100_client)
+BENCHMARK_DECLARE (tcp_pump1_client)
+BENCHMARK_DECLARE (pipe_pump100_client)
+BENCHMARK_DECLARE (pipe_pump1_client)
+
+BENCHMARK_DECLARE (tcp_multi_accept2)
+BENCHMARK_DECLARE (tcp_multi_accept4)
+BENCHMARK_DECLARE (tcp_multi_accept8)
+
+/* Run until X packets have been sent/received. */
+BENCHMARK_DECLARE (udp_pummel_1v1)
+BENCHMARK_DECLARE (udp_pummel_1v10)
+BENCHMARK_DECLARE (udp_pummel_1v100)
+BENCHMARK_DECLARE (udp_pummel_1v1000)
+BENCHMARK_DECLARE (udp_pummel_10v10)
+BENCHMARK_DECLARE (udp_pummel_10v100)
+BENCHMARK_DECLARE (udp_pummel_10v1000)
+BENCHMARK_DECLARE (udp_pummel_100v100)
+BENCHMARK_DECLARE (udp_pummel_100v1000)
+BENCHMARK_DECLARE (udp_pummel_1000v1000)
+
+/* Run until X seconds have elapsed. */
+BENCHMARK_DECLARE (udp_timed_pummel_1v1)
+BENCHMARK_DECLARE (udp_timed_pummel_1v10)
+BENCHMARK_DECLARE (udp_timed_pummel_1v100)
+BENCHMARK_DECLARE (udp_timed_pummel_1v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_10v10)
+BENCHMARK_DECLARE (udp_timed_pummel_10v100)
+BENCHMARK_DECLARE (udp_timed_pummel_10v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_100v100)
+BENCHMARK_DECLARE (udp_timed_pummel_100v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_1000v1000)
+
+BENCHMARK_DECLARE (getaddrinfo)
+BENCHMARK_DECLARE (fs_stat)
+BENCHMARK_DECLARE (async1)
+BENCHMARK_DECLARE (async2)
+BENCHMARK_DECLARE (async4)
+BENCHMARK_DECLARE (async8)
+BENCHMARK_DECLARE (async_pummel_1)
+BENCHMARK_DECLARE (async_pummel_2)
+BENCHMARK_DECLARE (async_pummel_4)
+BENCHMARK_DECLARE (async_pummel_8)
+BENCHMARK_DECLARE (spawn)
+BENCHMARK_DECLARE (thread_create)
+BENCHMARK_DECLARE (million_async)
+BENCHMARK_DECLARE (million_timers)
+HELPER_DECLARE (tcp4_blackhole_server)
+HELPER_DECLARE (tcp_pump_server)
+HELPER_DECLARE (pipe_pump_server)
+HELPER_DECLARE (tcp4_echo_server)
+HELPER_DECLARE (pipe_echo_server)
+HELPER_DECLARE (dns_server)
+
+TASK_LIST_START
+ BENCHMARK_ENTRY (sizes)
+ BENCHMARK_ENTRY (loop_count)
+ BENCHMARK_ENTRY (loop_count_timed)
+
+ BENCHMARK_ENTRY (ping_pongs)
+ BENCHMARK_HELPER (ping_pongs, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (tcp_write_batch)
+ BENCHMARK_HELPER (tcp_write_batch, tcp4_blackhole_server)
+
+ BENCHMARK_ENTRY (tcp_pump100_client)
+ BENCHMARK_HELPER (tcp_pump100_client, tcp_pump_server)
+
+ BENCHMARK_ENTRY (tcp_pump1_client)
+ BENCHMARK_HELPER (tcp_pump1_client, tcp_pump_server)
+
+ BENCHMARK_ENTRY (tcp4_pound_100)
+ BENCHMARK_HELPER (tcp4_pound_100, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (tcp4_pound_1000)
+ BENCHMARK_HELPER (tcp4_pound_1000, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (pipe_pump100_client)
+ BENCHMARK_HELPER (pipe_pump100_client, pipe_pump_server)
+
+ BENCHMARK_ENTRY (pipe_pump1_client)
+ BENCHMARK_HELPER (pipe_pump1_client, pipe_pump_server)
+
+ BENCHMARK_ENTRY (pipe_pound_100)
+ BENCHMARK_HELPER (pipe_pound_100, pipe_echo_server)
+
+ BENCHMARK_ENTRY (pipe_pound_1000)
+ BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server)
+
+ BENCHMARK_ENTRY (tcp_multi_accept2)
+ BENCHMARK_ENTRY (tcp_multi_accept4)
+ BENCHMARK_ENTRY (tcp_multi_accept8)
+
+ BENCHMARK_ENTRY (udp_pummel_1v1)
+ BENCHMARK_ENTRY (udp_pummel_1v10)
+ BENCHMARK_ENTRY (udp_pummel_1v100)
+ BENCHMARK_ENTRY (udp_pummel_1v1000)
+ BENCHMARK_ENTRY (udp_pummel_10v10)
+ BENCHMARK_ENTRY (udp_pummel_10v100)
+ BENCHMARK_ENTRY (udp_pummel_10v1000)
+ BENCHMARK_ENTRY (udp_pummel_100v100)
+ BENCHMARK_ENTRY (udp_pummel_100v1000)
+ BENCHMARK_ENTRY (udp_pummel_1000v1000)
+
+ BENCHMARK_ENTRY (udp_timed_pummel_1v1)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v10)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v10)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_100v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_100v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_1000v1000)
+
+ BENCHMARK_ENTRY (getaddrinfo)
+
+ BENCHMARK_ENTRY (fs_stat)
+
+ BENCHMARK_ENTRY (async1)
+ BENCHMARK_ENTRY (async2)
+ BENCHMARK_ENTRY (async4)
+ BENCHMARK_ENTRY (async8)
+ BENCHMARK_ENTRY (async_pummel_1)
+ BENCHMARK_ENTRY (async_pummel_2)
+ BENCHMARK_ENTRY (async_pummel_4)
+ BENCHMARK_ENTRY (async_pummel_8)
+
+ BENCHMARK_ENTRY (spawn)
+ BENCHMARK_ENTRY (thread_create)
+ BENCHMARK_ENTRY (million_async)
+ BENCHMARK_ENTRY (million_timers)
+TASK_LIST_END
diff --git a/3rdparty/libuv/test/benchmark-loop-count.c b/3rdparty/libuv/test/benchmark-loop-count.c
new file mode 100644
index 00000000000..970a94c2fec
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-loop-count.c
@@ -0,0 +1,92 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_TICKS (2 * 1000 * 1000)
+
+static unsigned long ticks;
+static uv_idle_t idle_handle;
+static uv_timer_t timer_handle;
+
+
+static void idle_cb(uv_idle_t* handle) {
+ if (++ticks == NUM_TICKS)
+ uv_idle_stop(handle);
+}
+
+
+static void idle2_cb(uv_idle_t* handle) {
+ ticks++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_idle_stop(&idle_handle);
+ uv_timer_stop(&timer_handle);
+}
+
+
+BENCHMARK_IMPL(loop_count) {
+ uv_loop_t* loop = uv_default_loop();
+ uint64_t ns;
+
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+
+ ns = uv_hrtime();
+ uv_run(loop, UV_RUN_DEFAULT);
+ ns = uv_hrtime() - ns;
+
+ ASSERT(ticks == NUM_TICKS);
+
+ fprintf(stderr, "loop_count: %d ticks in %.2fs (%.0f/s)\n",
+ NUM_TICKS,
+ ns / 1e9,
+ NUM_TICKS / (ns / 1e9));
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(loop_count_timed) {
+ uv_loop_t* loop = uv_default_loop();
+
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle2_cb);
+
+ uv_timer_init(loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 5000, 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ fprintf(stderr, "loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-million-async.c b/3rdparty/libuv/test/benchmark-million-async.c
new file mode 100644
index 00000000000..5395ed54bab
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-million-async.c
@@ -0,0 +1,112 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+struct async_container {
+ unsigned async_events;
+ unsigned handles_seen;
+ uv_async_t async_handles[1024 * 1024];
+};
+
+static volatile int done;
+static uv_thread_t thread_id;
+static struct async_container* container;
+
+
+static unsigned fastrand(void) {
+ static unsigned g = 0;
+ g = g * 214013 + 2531011;
+ return g;
+}
+
+
+static void thread_cb(void* arg) {
+ unsigned i;
+
+ while (done == 0) {
+ i = fastrand() % ARRAY_SIZE(container->async_handles);
+ uv_async_send(container->async_handles + i);
+ }
+}
+
+
+static void async_cb(uv_async_t* handle) {
+ container->async_events++;
+ handle->data = handle;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ unsigned i;
+
+ done = 1;
+ ASSERT(0 == uv_thread_join(&thread_id));
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ uv_async_t* handle = container->async_handles + i;
+
+ if (handle->data != NULL)
+ container->handles_seen++;
+
+ uv_close((uv_handle_t*) handle, NULL);
+ }
+
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+BENCHMARK_IMPL(million_async) {
+ uv_timer_t timer_handle;
+ uv_async_t* handle;
+ uv_loop_t* loop;
+ int timeout;
+ unsigned i;
+
+ loop = uv_default_loop();
+ timeout = 5000;
+
+ container = malloc(sizeof(*container));
+ ASSERT(container != NULL);
+ container->async_events = 0;
+ container->handles_seen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ handle = container->async_handles + i;
+ ASSERT(0 == uv_async_init(loop, handle, async_cb));
+ handle->data = NULL;
+ }
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0));
+ ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n",
+ fmt(container->async_events),
+ timeout / 1000.,
+ fmt(container->async_events / (timeout / 1000.)),
+ fmt(container->handles_seen));
+ free(container);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-million-timers.c b/3rdparty/libuv/test/benchmark-million-timers.c
new file mode 100644
index 00000000000..60a308bef13
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-million-timers.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#define NUM_TIMERS (10 * 1000 * 1000)
+
+static int timer_cb_called;
+static int close_cb_called;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ timer_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+BENCHMARK_IMPL(million_timers) {
+ uv_timer_t* timers;
+ uv_loop_t* loop;
+ uint64_t before_all;
+ uint64_t before_run;
+ uint64_t after_run;
+ uint64_t after_all;
+ int timeout;
+ int i;
+
+ timers = malloc(NUM_TIMERS * sizeof(timers[0]));
+ ASSERT(timers != NULL);
+
+ loop = uv_default_loop();
+ timeout = 0;
+
+ before_all = uv_hrtime();
+ for (i = 0; i < NUM_TIMERS; i++) {
+ if (i % 1000 == 0) timeout++;
+ ASSERT(0 == uv_timer_init(loop, timers + i));
+ ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0));
+ }
+
+ before_run = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ after_run = uv_hrtime();
+
+ for (i = 0; i < NUM_TIMERS; i++)
+ uv_close((uv_handle_t*) (timers + i), close_cb);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ after_all = uv_hrtime();
+
+ ASSERT(timer_cb_called == NUM_TIMERS);
+ ASSERT(close_cb_called == NUM_TIMERS);
+ free(timers);
+
+ fprintf(stderr, "%.2f seconds total\n", (after_all - before_all) / 1e9);
+ fprintf(stderr, "%.2f seconds init\n", (before_run - before_all) / 1e9);
+ fprintf(stderr, "%.2f seconds dispatch\n", (after_run - before_run) / 1e9);
+ fprintf(stderr, "%.2f seconds cleanup\n", (after_all - after_run) / 1e9);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-multi-accept.c b/3rdparty/libuv/test/benchmark-multi-accept.c
new file mode 100644
index 00000000000..2f32c0caf4a
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-multi-accept.c
@@ -0,0 +1,447 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#define IPC_PIPE_NAME TEST_PIPENAME
+#define NUM_CONNECTS (250 * 1000)
+
+union stream_handle {
+ uv_pipe_t pipe;
+ uv_tcp_t tcp;
+};
+
+/* Use as (uv_stream_t *) &handle_storage -- it's kind of clunky but it
+ * avoids aliasing warnings.
+ */
+typedef unsigned char handle_storage_t[sizeof(union stream_handle)];
+
+/* Used for passing around the listen handle, not part of the benchmark proper.
+ * We have an overabundance of server types here. It works like this:
+ *
+ * 1. The main thread starts an IPC pipe server.
+ * 2. The worker threads connect to the IPC server and obtain a listen handle.
+ * 3. The worker threads start accepting requests on the listen handle.
+ * 4. The main thread starts connecting repeatedly.
+ *
+ * Step #4 should perhaps be farmed out over several threads.
+ */
+struct ipc_server_ctx {
+ handle_storage_t server_handle;
+ unsigned int num_connects;
+ uv_pipe_t ipc_pipe;
+};
+
+struct ipc_peer_ctx {
+ handle_storage_t peer_handle;
+ uv_write_t write_req;
+};
+
+struct ipc_client_ctx {
+ uv_connect_t connect_req;
+ uv_stream_t* server_handle;
+ uv_pipe_t ipc_pipe;
+ char scratch[16];
+};
+
+/* Used in the actual benchmark. */
+struct server_ctx {
+ handle_storage_t server_handle;
+ unsigned int num_connects;
+ uv_async_t async_handle;
+ uv_thread_t thread_id;
+ uv_sem_t semaphore;
+};
+
+struct client_ctx {
+ handle_storage_t client_handle;
+ unsigned int num_connects;
+ uv_connect_t connect_req;
+ uv_idle_t idle_handle;
+};
+
+static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status);
+static void ipc_write_cb(uv_write_t* req, int status);
+static void ipc_close_cb(uv_handle_t* handle);
+static void ipc_connect_cb(uv_connect_t* req, int status);
+static void ipc_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf);
+static void ipc_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+
+static void sv_async_cb(uv_async_t* handle);
+static void sv_connection_cb(uv_stream_t* server_handle, int status);
+static void sv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf);
+static void sv_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+
+static void cl_connect_cb(uv_connect_t* req, int status);
+static void cl_idle_cb(uv_idle_t* handle);
+static void cl_close_cb(uv_handle_t* handle);
+
+static struct sockaddr_in listen_addr;
+
+
+static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) {
+ struct ipc_server_ctx* sc;
+ struct ipc_peer_ctx* pc;
+ uv_loop_t* loop;
+ uv_buf_t buf;
+
+ loop = ipc_pipe->loop;
+ buf = uv_buf_init("PING", 4);
+ sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
+ pc = calloc(1, sizeof(*pc));
+ ASSERT(pc != NULL);
+
+ if (ipc_pipe->type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle));
+ else if (ipc_pipe->type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle));
+ ASSERT(0 == uv_write2(&pc->write_req,
+ (uv_stream_t*) &pc->peer_handle,
+ &buf,
+ 1,
+ (uv_stream_t*) &sc->server_handle,
+ ipc_write_cb));
+
+ if (--sc->num_connects == 0)
+ uv_close((uv_handle_t*) ipc_pipe, NULL);
+}
+
+
+static void ipc_write_cb(uv_write_t* req, int status) {
+ struct ipc_peer_ctx* ctx;
+ ctx = container_of(req, struct ipc_peer_ctx, write_req);
+ uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb);
+}
+
+
+static void ipc_close_cb(uv_handle_t* handle) {
+ struct ipc_peer_ctx* ctx;
+ ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
+ free(ctx);
+}
+
+
+static void ipc_connect_cb(uv_connect_t* req, int status) {
+ struct ipc_client_ctx* ctx;
+ ctx = container_of(req, struct ipc_client_ctx, connect_req);
+ ASSERT(0 == status);
+ ASSERT(0 == uv_read_start((uv_stream_t*) &ctx->ipc_pipe,
+ ipc_alloc_cb,
+ ipc_read_cb));
+}
+
+
+static void ipc_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ struct ipc_client_ctx* ctx;
+ ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
+ buf->base = ctx->scratch;
+ buf->len = sizeof(ctx->scratch);
+}
+
+
+static void ipc_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ struct ipc_client_ctx* ctx;
+ uv_loop_t* loop;
+ uv_handle_type type;
+ uv_pipe_t* ipc_pipe;
+
+ ipc_pipe = (uv_pipe_t*) handle;
+ ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
+ loop = ipc_pipe->loop;
+
+ ASSERT(1 == uv_pipe_pending_count(ipc_pipe));
+ type = uv_pipe_pending_type(ipc_pipe);
+ if (type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle));
+ else if (type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(handle, ctx->server_handle));
+ uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL);
+}
+
+
+/* Set up an IPC pipe server that hands out listen sockets to the worker
+ * threads. It's kind of cumbersome for such a simple operation, maybe we
+ * should revive uv_import() and uv_export().
+ */
+static void send_listen_handles(uv_handle_type type,
+ unsigned int num_servers,
+ struct server_ctx* servers) {
+ struct ipc_server_ctx ctx;
+ uv_loop_t* loop;
+ unsigned int i;
+
+ loop = uv_default_loop();
+ ctx.num_connects = num_servers;
+
+ if (type == UV_TCP) {
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle));
+ ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle,
+ (const struct sockaddr*) &listen_addr,
+ 0));
+ }
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
+ ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME));
+ ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb));
+
+ for (i = 0; i < num_servers; i++)
+ uv_sem_post(&servers[i].semaphore);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ uv_close((uv_handle_t*) &ctx.server_handle, NULL);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ for (i = 0; i < num_servers; i++)
+ uv_sem_wait(&servers[i].semaphore);
+}
+
+
+static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) {
+ struct ipc_client_ctx ctx;
+
+ ctx.server_handle = server_handle;
+ ctx.server_handle->data = "server handle";
+
+ ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
+ uv_pipe_connect(&ctx.connect_req,
+ &ctx.ipc_pipe,
+ IPC_PIPE_NAME,
+ ipc_connect_cb);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+}
+
+
+static void server_cb(void *arg) {
+ struct server_ctx *ctx;
+ uv_loop_t loop;
+
+ ctx = arg;
+ ASSERT(0 == uv_loop_init(&loop));
+
+ ASSERT(0 == uv_async_init(&loop, &ctx->async_handle, sv_async_cb));
+ uv_unref((uv_handle_t*) &ctx->async_handle);
+
+ /* Wait until the main thread is ready. */
+ uv_sem_wait(&ctx->semaphore);
+ get_listen_handle(&loop, (uv_stream_t*) &ctx->server_handle);
+ uv_sem_post(&ctx->semaphore);
+
+ /* Now start the actual benchmark. */
+ ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle,
+ 128,
+ sv_connection_cb));
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+
+ uv_loop_close(&loop);
+}
+
+
+static void sv_async_cb(uv_async_t* handle) {
+ struct server_ctx* ctx;
+ ctx = container_of(handle, struct server_ctx, async_handle);
+ uv_close((uv_handle_t*) &ctx->server_handle, NULL);
+ uv_close((uv_handle_t*) &ctx->async_handle, NULL);
+}
+
+
+static void sv_connection_cb(uv_stream_t* server_handle, int status) {
+ handle_storage_t* storage;
+ struct server_ctx* ctx;
+
+ ctx = container_of(server_handle, struct server_ctx, server_handle);
+ ASSERT(status == 0);
+
+ storage = malloc(sizeof(*storage));
+ ASSERT(storage != NULL);
+
+ if (server_handle->type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage));
+ else if (server_handle->type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(server_handle, (uv_stream_t*) storage));
+ ASSERT(0 == uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb));
+ ctx->num_connects++;
+}
+
+
+static void sv_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[32];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void sv_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*) handle, (uv_close_cb) free);
+}
+
+
+static void cl_connect_cb(uv_connect_t* req, int status) {
+ struct client_ctx* ctx = container_of(req, struct client_ctx, connect_req);
+ uv_idle_start(&ctx->idle_handle, cl_idle_cb);
+ ASSERT(0 == status);
+}
+
+
+static void cl_idle_cb(uv_idle_t* handle) {
+ struct client_ctx* ctx = container_of(handle, struct client_ctx, idle_handle);
+ uv_close((uv_handle_t*) &ctx->client_handle, cl_close_cb);
+ uv_idle_stop(&ctx->idle_handle);
+}
+
+
+static void cl_close_cb(uv_handle_t* handle) {
+ struct client_ctx* ctx;
+
+ ctx = container_of(handle, struct client_ctx, client_handle);
+
+ if (--ctx->num_connects == 0) {
+ uv_close((uv_handle_t*) &ctx->idle_handle, NULL);
+ return;
+ }
+
+ ASSERT(0 == uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle));
+ ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
+ (uv_tcp_t*) &ctx->client_handle,
+ (const struct sockaddr*) &listen_addr,
+ cl_connect_cb));
+}
+
+
+static int test_tcp(unsigned int num_servers, unsigned int num_clients) {
+ struct server_ctx* servers;
+ struct client_ctx* clients;
+ uv_loop_t* loop;
+ uv_tcp_t* handle;
+ unsigned int i;
+ double time;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr));
+ loop = uv_default_loop();
+
+ servers = calloc(num_servers, sizeof(servers[0]));
+ clients = calloc(num_clients, sizeof(clients[0]));
+ ASSERT(servers != NULL);
+ ASSERT(clients != NULL);
+
+ /* We're making the assumption here that from the perspective of the
+ * OS scheduler, threads are functionally equivalent to and interchangeable
+ * with full-blown processes.
+ */
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ ASSERT(0 == uv_sem_init(&ctx->semaphore, 0));
+ ASSERT(0 == uv_thread_create(&ctx->thread_id, server_cb, ctx));
+ }
+
+ send_listen_handles(UV_TCP, num_servers, servers);
+
+ for (i = 0; i < num_clients; i++) {
+ struct client_ctx* ctx = clients + i;
+ ctx->num_connects = NUM_CONNECTS / num_clients;
+ handle = (uv_tcp_t*) &ctx->client_handle;
+ handle->data = "client handle";
+ ASSERT(0 == uv_tcp_init(loop, handle));
+ ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
+ handle,
+ (const struct sockaddr*) &listen_addr,
+ cl_connect_cb));
+ ASSERT(0 == uv_idle_init(loop, &ctx->idle_handle));
+ }
+
+ {
+ uint64_t t = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ t = uv_hrtime() - t;
+ time = t / 1e9;
+ }
+
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ uv_async_send(&ctx->async_handle);
+ ASSERT(0 == uv_thread_join(&ctx->thread_id));
+ uv_sem_destroy(&ctx->semaphore);
+ }
+
+ printf("accept%u: %.0f accepts/sec (%u total)\n",
+ num_servers,
+ NUM_CONNECTS / time,
+ NUM_CONNECTS);
+
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ printf(" thread #%u: %.0f accepts/sec (%u total, %.1f%%)\n",
+ i,
+ ctx->num_connects / time,
+ ctx->num_connects,
+ ctx->num_connects * 100.0 / NUM_CONNECTS);
+ }
+
+ free(clients);
+ free(servers);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept2) {
+ return test_tcp(2, 40);
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept4) {
+ return test_tcp(4, 40);
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept8) {
+ return test_tcp(8, 40);
+}
diff --git a/3rdparty/libuv/test/benchmark-ping-pongs.c b/3rdparty/libuv/test/benchmark-ping-pongs.c
new file mode 100644
index 00000000000..646a7df9447
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-ping-pongs.c
@@ -0,0 +1,221 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Run the benchmark for this many ms */
+#define TIME 5000
+
+
+typedef struct {
+ int pongs;
+ int state;
+ uv_tcp_t tcp;
+ uv_connect_t connect_req;
+ uv_shutdown_t shutdown_req;
+} pinger_t;
+
+typedef struct buf_s {
+ uv_buf_t uv_buf_t;
+ struct buf_s* next;
+} buf_t;
+
+
+static char PING[] = "PING\n";
+
+static uv_loop_t* loop;
+
+static buf_t* buf_freelist = NULL;
+static int pinger_shutdown_cb_called;
+static int completed_pingers = 0;
+static int64_t start_time;
+
+
+static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {
+ buf_t* ab;
+
+ ab = buf_freelist;
+ if (ab != NULL)
+ buf_freelist = ab->next;
+ else {
+ ab = malloc(size + sizeof(*ab));
+ ab->uv_buf_t.len = size;
+ ab->uv_buf_t.base = (char*) (ab + 1);
+ }
+
+ *buf = ab->uv_buf_t;
+}
+
+
+static void buf_free(const uv_buf_t* buf) {
+ buf_t* ab = (buf_t*) buf->base - 1;
+ ab->next = buf_freelist;
+ buf_freelist = ab;
+}
+
+
+static void pinger_close_cb(uv_handle_t* handle) {
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)handle->data;
+ fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
+ fflush(stderr);
+
+ free(pinger);
+
+ completed_pingers++;
+}
+
+
+static void pinger_write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ free(req);
+}
+
+
+static void pinger_write_ping(pinger_t* pinger) {
+ uv_write_t* req;
+ uv_buf_t buf;
+
+ buf = uv_buf_init(PING, sizeof(PING) - 1);
+
+ req = malloc(sizeof *req);
+ if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {
+ FATAL("uv_write failed");
+ }
+}
+
+
+static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ pinger_shutdown_cb_called++;
+
+ /*
+ * The close callback has not been triggered yet. We must wait for EOF
+ * until we close the connection.
+ */
+ ASSERT(completed_pingers == 0);
+}
+
+
+static void pinger_read_cb(uv_stream_t* tcp,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ssize_t i;
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)tcp->data;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ if (buf->base) {
+ buf_free(buf);
+ }
+
+ ASSERT(pinger_shutdown_cb_called == 1);
+ uv_close((uv_handle_t*)tcp, pinger_close_cb);
+
+ return;
+ }
+
+ /* Now we count the pings */
+ for (i = 0; i < nread; i++) {
+ ASSERT(buf->base[i] == PING[pinger->state]);
+ pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
+ if (pinger->state == 0) {
+ pinger->pongs++;
+ if (uv_now(loop) - start_time > TIME) {
+ uv_shutdown(&pinger->shutdown_req,
+ (uv_stream_t*) tcp,
+ pinger_shutdown_cb);
+ break;
+ } else {
+ pinger_write_ping(pinger);
+ }
+ }
+ }
+
+ buf_free(buf);
+}
+
+
+static void pinger_connect_cb(uv_connect_t* req, int status) {
+ pinger_t *pinger = (pinger_t*)req->handle->data;
+
+ ASSERT(status == 0);
+
+ pinger_write_ping(pinger);
+
+ if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {
+ FATAL("uv_read_start failed");
+ }
+}
+
+
+static void pinger_new(void) {
+ struct sockaddr_in client_addr;
+ struct sockaddr_in server_addr;
+ pinger_t *pinger;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(loop, &pinger->tcp);
+ ASSERT(!r);
+
+ pinger->tcp.data = pinger;
+
+ ASSERT(0 == uv_tcp_bind(&pinger->tcp,
+ (const struct sockaddr*) &client_addr,
+ 0));
+
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_connect_cb);
+ ASSERT(!r);
+}
+
+
+BENCHMARK_IMPL(ping_pongs) {
+ loop = uv_default_loop();
+
+ start_time = uv_now(loop);
+
+ pinger_new();
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-pound.c b/3rdparty/libuv/test/benchmark-pound.c
new file mode 100644
index 00000000000..79f36345037
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-pound.c
@@ -0,0 +1,351 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+/* Update this is you're going to run > 1000 concurrent requests. */
+#define MAX_CONNS 1000
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+#undef DEBUG
+#define DEBUG 0
+
+struct conn_rec_s;
+
+typedef void (*setup_fn)(int num, void* arg);
+typedef void (*make_connect_fn)(struct conn_rec_s* conn);
+typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg);
+
+/* Base class for tcp_conn_rec and pipe_conn_rec.
+ * The ordering of fields matters!
+ */
+typedef struct conn_rec_s {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_stream_t stream;
+} conn_rec;
+
+typedef struct {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_tcp_t stream;
+} tcp_conn_rec;
+
+typedef struct {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_pipe_t stream;
+} pipe_conn_rec;
+
+static char buffer[] = "QS";
+
+static uv_loop_t* loop;
+
+static tcp_conn_rec tcp_conns[MAX_CONNS];
+static pipe_conn_rec pipe_conns[MAX_CONNS];
+
+static uint64_t start; /* in ms */
+static int closed_streams;
+static int conns_failed;
+
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+static void connect_cb(uv_connect_t* conn_req, int status);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void close_cb(uv_handle_t* handle);
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void after_write(uv_write_t* req, int status) {
+ if (status != 0) {
+ fprintf(stderr, "write error %s\n", uv_err_name(status));
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ conns_failed++;
+ return;
+ }
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ conn_rec* conn;
+ uv_buf_t buf;
+ int r;
+
+ if (status != 0) {
+#if DEBUG
+ fprintf(stderr, "connect error %s\n", uv_err_name(status));
+#endif
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ conns_failed++;
+ return;
+ }
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ conn = (conn_rec*)req->data;
+ ASSERT(conn != NULL);
+
+#if DEBUG
+ printf("connect_cb %d\n", conn->i);
+#endif
+
+ r = uv_read_start(&conn->stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ buf.base = buffer;
+ buf.len = sizeof(buffer) - 1;
+
+ r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+
+ ASSERT(stream != NULL);
+
+#if DEBUG
+ printf("read_cb %d\n", p->i);
+#endif
+
+ uv_close((uv_handle_t*)stream, close_cb);
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ ;
+ } else if (nread == UV_ECONNRESET) {
+ conns_failed++;
+ } else {
+ fprintf(stderr, "read error %s\n", uv_err_name(nread));
+ ASSERT(0);
+ }
+ }
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ conn_rec* p = (conn_rec*)handle->data;
+
+ ASSERT(handle != NULL);
+ closed_streams++;
+
+#if DEBUG
+ printf("close_cb %d\n", p->i);
+#endif
+
+ if (uv_now(loop) - start < 10000) {
+ p->make_connect(p);
+ }
+}
+
+
+static void tcp_do_setup(int num, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ tcp_conns[i].i = i;
+ }
+}
+
+
+static void pipe_do_setup(int num, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ pipe_conns[i].i = i;
+ }
+}
+
+
+static void tcp_make_connect(conn_rec* p) {
+ struct sockaddr_in addr;
+ tcp_conn_rec* tp;
+ int r;
+
+ tp = (tcp_conn_rec*) p;
+
+ r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&tp->conn_req,
+ (uv_tcp_t*) &p->stream,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r) {
+ fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r));
+ ASSERT(0);
+ }
+
+#if DEBUG
+ printf("make connect %d\n", p->i);
+#endif
+
+ p->conn_req.data = p;
+ p->write_req.data = p;
+ p->stream.data = p;
+}
+
+
+static void pipe_make_connect(conn_rec* p) {
+ int r;
+
+ r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req,
+ (uv_pipe_t*) &p->stream,
+ TEST_PIPENAME,
+ connect_cb);
+
+#if DEBUG
+ printf("make connect %d\n", p->i);
+#endif
+
+ p->conn_req.data = p;
+ p->write_req.data = p;
+ p->stream.data = p;
+}
+
+
+static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ tcp_make_connect((conn_rec*)&tcp_conns[i]);
+ tcp_conns[i].make_connect = make_connect;
+ }
+
+ return 0;
+}
+
+
+static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ pipe_make_connect((conn_rec*)&pipe_conns[i]);
+ pipe_conns[i].make_connect = make_connect;
+ }
+
+ return 0;
+}
+
+
+static int pound_it(int concurrency,
+ const char* type,
+ setup_fn do_setup,
+ connect_fn do_connect,
+ make_connect_fn make_connect,
+ void* arg) {
+ double secs;
+ int r;
+ uint64_t start_time; /* in ns */
+ uint64_t end_time;
+
+ loop = uv_default_loop();
+
+ uv_update_time(loop);
+ start = uv_now(loop);
+
+ /* Run benchmark for at least five seconds. */
+ start_time = uv_hrtime();
+
+ do_setup(concurrency, arg);
+
+ r = do_connect(concurrency, make_connect, arg);
+ ASSERT(!r);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ end_time = uv_hrtime();
+
+ /* Number of fractional seconds it took to run the benchmark. */
+ secs = (double)(end_time - start_time) / NANOSEC;
+
+ fprintf(stderr, "%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
+ type,
+ concurrency,
+ closed_streams / secs,
+ conns_failed);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp4_pound_100) {
+ return pound_it(100,
+ "tcp",
+ tcp_do_setup,
+ tcp_do_connect,
+ tcp_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(tcp4_pound_1000) {
+ return pound_it(1000,
+ "tcp",
+ tcp_do_setup,
+ tcp_do_connect,
+ tcp_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(pipe_pound_100) {
+ return pound_it(100,
+ "pipe",
+ pipe_do_setup,
+ pipe_do_connect,
+ pipe_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(pipe_pound_1000) {
+ return pound_it(1000,
+ "pipe",
+ pipe_do_setup,
+ pipe_do_connect,
+ pipe_make_connect,
+ NULL);
+}
diff --git a/3rdparty/libuv/test/benchmark-pump.c b/3rdparty/libuv/test/benchmark-pump.c
new file mode 100644
index 00000000000..88f2dc5c658
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-pump.c
@@ -0,0 +1,476 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <math.h>
+#include <stdio.h>
+
+
+static int TARGET_CONNECTIONS;
+#define WRITE_BUFFER_SIZE 8192
+#define MAX_SIMULTANEOUS_CONNECTS 100
+
+#define PRINT_STATS 0
+#define STATS_INTERVAL 1000 /* msec */
+#define STATS_COUNT 5
+
+
+static void do_write(uv_stream_t*);
+static void maybe_connect_some();
+
+static uv_req_t* req_alloc();
+static void req_free(uv_req_t* uv_req);
+
+static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf);
+static void buf_free(const uv_buf_t* buf);
+
+static uv_loop_t* loop;
+
+static uv_tcp_t tcpServer;
+static uv_pipe_t pipeServer;
+static uv_stream_t* server;
+static struct sockaddr_in listen_addr;
+static struct sockaddr_in connect_addr;
+
+static int64_t start_time;
+
+static int max_connect_socket = 0;
+static int max_read_sockets = 0;
+static int read_sockets = 0;
+static int write_sockets = 0;
+
+static int64_t nrecv = 0;
+static int64_t nrecv_total = 0;
+static int64_t nsent = 0;
+static int64_t nsent_total = 0;
+
+static int stats_left = 0;
+
+static char write_buffer[WRITE_BUFFER_SIZE];
+
+/* Make this as large as you need. */
+#define MAX_WRITE_HANDLES 1000
+
+static stream_type type;
+
+static uv_tcp_t tcp_write_handles[MAX_WRITE_HANDLES];
+static uv_pipe_t pipe_write_handles[MAX_WRITE_HANDLES];
+
+static uv_timer_t timer_handle;
+
+
+static double gbit(int64_t bytes, int64_t passed_ms) {
+ double gbits = ((double)bytes / (1024 * 1024 * 1024)) * 8;
+ return gbits / ((double)passed_ms / 1000);
+}
+
+
+static void show_stats(uv_timer_t* handle) {
+ int64_t diff;
+ int i;
+
+#if PRINT_STATS
+ fprintf(stderr, "connections: %d, write: %.1f gbit/s\n",
+ write_sockets,
+ gbit(nsent, STATS_INTERVAL));
+ fflush(stderr);
+#endif
+
+ /* Exit if the show is over */
+ if (!--stats_left) {
+
+ uv_update_time(loop);
+ diff = uv_now(loop) - start_time;
+
+ fprintf(stderr, "%s_pump%d_client: %.1f gbit/s\n",
+ type == TCP ? "tcp" : "pipe",
+ write_sockets,
+ gbit(nsent_total, diff));
+ fflush(stderr);
+
+ for (i = 0; i < write_sockets; i++) {
+ if (type == TCP)
+ uv_close((uv_handle_t*) &tcp_write_handles[i], NULL);
+ else
+ uv_close((uv_handle_t*) &pipe_write_handles[i], NULL);
+ }
+
+ exit(0);
+ }
+
+ /* Reset read and write counters */
+ nrecv = 0;
+ nsent = 0;
+}
+
+
+static void read_show_stats(void) {
+ int64_t diff;
+
+ uv_update_time(loop);
+ diff = uv_now(loop) - start_time;
+
+ fprintf(stderr, "%s_pump%d_server: %.1f gbit/s\n",
+ type == TCP ? "tcp" : "pipe",
+ max_read_sockets,
+ gbit(nrecv_total, diff));
+ fflush(stderr);
+}
+
+
+
+static void read_sockets_close_cb(uv_handle_t* handle) {
+ free(handle);
+ read_sockets--;
+
+ /* If it's past the first second and everyone has closed their connection
+ * Then print stats.
+ */
+ if (uv_now(loop) - start_time > 1000 && read_sockets == 0) {
+ read_show_stats();
+ uv_close((uv_handle_t*)server, NULL);
+ }
+}
+
+
+static void start_stats_collection(void) {
+ int r;
+
+ /* Show-stats timer */
+ stats_left = STATS_COUNT;
+ r = uv_timer_init(loop, &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL);
+ ASSERT(r == 0);
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) {
+ if (nrecv_total == 0) {
+ ASSERT(start_time == 0);
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+ }
+
+ if (bytes < 0) {
+ uv_close((uv_handle_t*)stream, read_sockets_close_cb);
+ return;
+ }
+
+ buf_free(buf);
+
+ nrecv += bytes;
+ nrecv_total += bytes;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ req_free((uv_req_t*) req);
+
+ nsent += sizeof write_buffer;
+ nsent_total += sizeof write_buffer;
+
+ do_write((uv_stream_t*) req->handle);
+}
+
+
+static void do_write(uv_stream_t* stream) {
+ uv_write_t* req;
+ uv_buf_t buf;
+ int r;
+
+ buf.base = (char*) &write_buffer;
+ buf.len = sizeof write_buffer;
+
+ req = (uv_write_t*) req_alloc();
+ r = uv_write(req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int i;
+
+ if (status) {
+ fprintf(stderr, "%s", uv_strerror(status));
+ fflush(stderr);
+ }
+ ASSERT(status == 0);
+
+ write_sockets++;
+ req_free((uv_req_t*) req);
+
+ maybe_connect_some();
+
+ if (write_sockets == TARGET_CONNECTIONS) {
+ start_stats_collection();
+
+ /* Yay! start writing */
+ for (i = 0; i < write_sockets; i++) {
+ if (type == TCP)
+ do_write((uv_stream_t*) &tcp_write_handles[i]);
+ else
+ do_write((uv_stream_t*) &pipe_write_handles[i]);
+ }
+ }
+}
+
+
+static void maybe_connect_some(void) {
+ uv_connect_t* req;
+ uv_tcp_t* tcp;
+ uv_pipe_t* pipe;
+ int r;
+
+ while (max_connect_socket < TARGET_CONNECTIONS &&
+ max_connect_socket < write_sockets + MAX_SIMULTANEOUS_CONNECTS) {
+ if (type == TCP) {
+ tcp = &tcp_write_handles[max_connect_socket++];
+
+ r = uv_tcp_init(loop, tcp);
+ ASSERT(r == 0);
+
+ req = (uv_connect_t*) req_alloc();
+ r = uv_tcp_connect(req,
+ tcp,
+ (const struct sockaddr*) &connect_addr,
+ connect_cb);
+ ASSERT(r == 0);
+ } else {
+ pipe = &pipe_write_handles[max_connect_socket++];
+
+ r = uv_pipe_init(loop, pipe, 0);
+ ASSERT(r == 0);
+
+ req = (uv_connect_t*) req_alloc();
+ uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb);
+ }
+ }
+}
+
+
+static void connection_cb(uv_stream_t* s, int status) {
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(server == s);
+ ASSERT(status == 0);
+
+ if (type == TCP) {
+ stream = (uv_stream_t*)malloc(sizeof(uv_tcp_t));
+ r = uv_tcp_init(loop, (uv_tcp_t*)stream);
+ ASSERT(r == 0);
+ } else {
+ stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t));
+ r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
+ ASSERT(r == 0);
+ }
+
+ r = uv_accept(s, stream);
+ ASSERT(r == 0);
+
+ r = uv_read_start(stream, buf_alloc, read_cb);
+ ASSERT(r == 0);
+
+ read_sockets++;
+ max_read_sockets++;
+}
+
+
+/*
+ * Request allocator
+ */
+
+typedef struct req_list_s {
+ union uv_any_req uv_req;
+ struct req_list_s* next;
+} req_list_t;
+
+
+static req_list_t* req_freelist = NULL;
+
+
+static uv_req_t* req_alloc(void) {
+ req_list_t* req;
+
+ req = req_freelist;
+ if (req != NULL) {
+ req_freelist = req->next;
+ return (uv_req_t*) req;
+ }
+
+ req = (req_list_t*) malloc(sizeof *req);
+ return (uv_req_t*) req;
+}
+
+
+static void req_free(uv_req_t* uv_req) {
+ req_list_t* req = (req_list_t*) uv_req;
+
+ req->next = req_freelist;
+ req_freelist = req;
+}
+
+
+/*
+ * Buffer allocator
+ */
+
+typedef struct buf_list_s {
+ uv_buf_t uv_buf_t;
+ struct buf_list_s* next;
+} buf_list_t;
+
+
+static buf_list_t* buf_freelist = NULL;
+
+
+static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf_list_t* ab;
+
+ ab = buf_freelist;
+ if (ab != NULL)
+ buf_freelist = ab->next;
+ else {
+ ab = malloc(size + sizeof(*ab));
+ ab->uv_buf_t.len = size;
+ ab->uv_buf_t.base = (char*) (ab + 1);
+ }
+
+ *buf = ab->uv_buf_t;
+}
+
+
+static void buf_free(const uv_buf_t* buf) {
+ buf_list_t* ab = (buf_list_t*) buf->base - 1;
+ ab->next = buf_freelist;
+ buf_freelist = ab;
+}
+
+
+HELPER_IMPL(tcp_pump_server) {
+ int r;
+
+ type = TCP;
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr));
+
+ /* Server */
+ server = (uv_stream_t*)&tcpServer;
+ r = uv_tcp_init(loop, &tcpServer);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ return 0;
+}
+
+
+HELPER_IMPL(pipe_pump_server) {
+ int r;
+ type = PIPE;
+
+ loop = uv_default_loop();
+
+ /* Server */
+ server = (uv_stream_t*)&pipeServer;
+ r = uv_pipe_init(loop, &pipeServer, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&pipeServer, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void tcp_pump(int n) {
+ ASSERT(n <= MAX_WRITE_HANDLES);
+ TARGET_CONNECTIONS = n;
+ type = TCP;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr));
+
+ /* Start making connections */
+ maybe_connect_some();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+static void pipe_pump(int n) {
+ ASSERT(n <= MAX_WRITE_HANDLES);
+ TARGET_CONNECTIONS = n;
+ type = PIPE;
+
+ loop = uv_default_loop();
+
+ /* Start making connections */
+ maybe_connect_some();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+BENCHMARK_IMPL(tcp_pump100_client) {
+ tcp_pump(100);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp_pump1_client) {
+ tcp_pump(1);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(pipe_pump100_client) {
+ pipe_pump(100);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(pipe_pump1_client) {
+ pipe_pump(1);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-sizes.c b/3rdparty/libuv/test/benchmark-sizes.c
new file mode 100644
index 00000000000..9bf42f91537
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-sizes.c
@@ -0,0 +1,46 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+
+BENCHMARK_IMPL(sizes) {
+ fprintf(stderr, "uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t));
+ fprintf(stderr, "uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t));
+ fprintf(stderr, "uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t));
+ fprintf(stderr, "uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t));
+ fprintf(stderr, "uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t));
+ fprintf(stderr, "uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t));
+ fprintf(stderr, "uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t));
+ fprintf(stderr, "uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t));
+ fprintf(stderr, "uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t));
+ fprintf(stderr, "uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
+ fprintf(stderr, "uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
+ fprintf(stderr, "uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
+ fprintf(stderr, "uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
+ fprintf(stderr, "uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
+ fprintf(stderr, "uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
+ fprintf(stderr, "uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
+ fprintf(stderr, "uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t));
+ fflush(stderr);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-spawn.c b/3rdparty/libuv/test/benchmark-spawn.c
new file mode 100644
index 00000000000..ed9ad608f37
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-spawn.c
@@ -0,0 +1,164 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This benchmark spawns itself 1000 times. */
+
+#include "task.h"
+#include "uv.h"
+
+static uv_loop_t* loop;
+
+static int N = 1000;
+static int done;
+
+static uv_process_t process;
+static uv_process_options_t options;
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static uv_pipe_t out;
+
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+static int process_open;
+static int pipe_open;
+
+
+static void spawn(void);
+
+
+static void maybe_spawn(void) {
+ if (process_open == 0 && pipe_open == 0) {
+ done++;
+ if (done < N) {
+ spawn();
+ }
+ }
+}
+
+
+static void process_close_cb(uv_handle_t* handle) {
+ ASSERT(process_open == 1);
+ process_open = 0;
+ maybe_spawn();
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(exit_status == 42);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, process_close_cb);
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void pipe_close_cb(uv_handle_t* pipe) {
+ ASSERT(pipe_open == 1);
+ pipe_open = 0;
+ maybe_spawn();
+}
+
+
+static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
+ if (nread > 0) {
+ ASSERT(pipe_open == 1);
+ output_used += nread;
+ } else if (nread < 0) {
+ if (nread == UV_EOF) {
+ uv_close((uv_handle_t*)pipe, pipe_close_cb);
+ }
+ }
+}
+
+
+static void spawn(void) {
+ uv_stdio_container_t stdio[2];
+ int r;
+
+ ASSERT(process_open == 0);
+ ASSERT(pipe_open == 0);
+
+ args[0] = exepath;
+ args[1] = "spawn_helper";
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+
+ uv_pipe_init(loop, &out, 0);
+
+ options.stdio = stdio;
+ options.stdio_count = 2;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+
+ r = uv_spawn(loop, &process, &options);
+ ASSERT(r == 0);
+
+ process_open = 1;
+ pipe_open = 1;
+ output_used = 0;
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+}
+
+
+BENCHMARK_IMPL(spawn) {
+ int r;
+ static int64_t start_time, end_time;
+
+ loop = uv_default_loop();
+
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+
+ spawn();
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_update_time(loop);
+ end_time = uv_now(loop);
+
+ fprintf(stderr, "spawn: %.0f spawns/s\n",
+ (double) N / (double) (end_time - start_time) * 1000.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-tcp-write-batch.c b/3rdparty/libuv/test/benchmark-tcp-write-batch.c
new file mode 100644
index 00000000000..96921b70db5
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-tcp-write-batch.c
@@ -0,0 +1,144 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define WRITE_REQ_DATA "Hello, world."
+#define NUM_WRITE_REQS (1000 * 1000)
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req;
+
+
+static write_req* write_reqs;
+static uv_tcp_t tcp_client;
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ write_req* w;
+ int i;
+ int r;
+
+ ASSERT(req->handle == (uv_stream_t*)&tcp_client);
+
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ w = &write_reqs[i];
+ r = uv_write(&w->req, req->handle, &w->buf, 1, write_cb);
+ ASSERT(r == 0);
+ }
+
+ r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+
+ connect_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*)&tcp_client);
+ ASSERT(req->handle->write_queue_size == 0);
+
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ free(write_reqs);
+
+ shutdown_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&tcp_client);
+ close_cb_called++;
+}
+
+
+BENCHMARK_IMPL(tcp_write_batch) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uint64_t start;
+ uint64_t stop;
+ int i;
+ int r;
+
+ write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS);
+ ASSERT(write_reqs != NULL);
+
+ /* Prepare the data to write out. */
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ write_reqs[i].buf = uv_buf_init(WRITE_REQ_DATA,
+ sizeof(WRITE_REQ_DATA) - 1);
+ }
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, &tcp_client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ start = uv_hrtime();
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ stop = uv_hrtime();
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == NUM_WRITE_REQS);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ printf("%ld write requests in %.2fs.\n",
+ (long)NUM_WRITE_REQS,
+ (stop - start) / 1e9);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-thread.c b/3rdparty/libuv/test/benchmark-thread.c
new file mode 100644
index 00000000000..b37a7fd6d01
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-thread.c
@@ -0,0 +1,64 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_THREADS (20 * 1000)
+
+static volatile int num_threads;
+
+
+static void thread_entry(void* arg) {
+ ASSERT(arg == (void *) 42);
+ num_threads++;
+ /* FIXME write barrier? */
+}
+
+
+BENCHMARK_IMPL(thread_create) {
+ uint64_t start_time;
+ double duration;
+ uv_thread_t tid;
+ int i, r;
+
+ start_time = uv_hrtime();
+
+ for (i = 0; i < NUM_THREADS; i++) {
+ r = uv_thread_create(&tid, thread_entry, (void *) 42);
+ ASSERT(r == 0);
+
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+ }
+
+ duration = (uv_hrtime() - start_time) / 1e9;
+
+ ASSERT(num_threads == NUM_THREADS);
+
+ printf("%d threads created in %.2f seconds (%.0f/s)\n",
+ NUM_THREADS, duration, NUM_THREADS / duration);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-udp-pummel.c b/3rdparty/libuv/test/benchmark-udp-pummel.c
new file mode 100644
index 00000000000..68a2373d781
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-udp-pummel.c
@@ -0,0 +1,243 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN"
+
+#define TEST_DURATION 5000 /* ms */
+
+#define BASE_PORT 12345
+
+struct sender_state {
+ struct sockaddr_in addr;
+ uv_udp_send_t send_req;
+ uv_udp_t udp_handle;
+};
+
+struct receiver_state {
+ struct sockaddr_in addr;
+ uv_udp_t udp_handle;
+};
+
+/* not used in timed mode */
+static unsigned int packet_counter = (unsigned int) 1e6;
+
+static int n_senders_;
+static int n_receivers_;
+static uv_buf_t bufs[5];
+static struct sender_state senders[1024];
+static struct receiver_state receivers[1024];
+
+static unsigned int send_cb_called;
+static unsigned int recv_cb_called;
+static unsigned int close_cb_called;
+static int timed;
+static int exiting;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ struct sender_state* s;
+
+ ASSERT(req != NULL);
+
+ if (status != 0) {
+ ASSERT(status == UV_ECANCELED);
+ return;
+ }
+
+ if (exiting)
+ return;
+
+ s = container_of(req, struct sender_state, send_req);
+ ASSERT(req->handle == &s->udp_handle);
+
+ if (timed)
+ goto send;
+
+ if (packet_counter == 0) {
+ uv_close((uv_handle_t*)&s->udp_handle, NULL);
+ return;
+ }
+
+ packet_counter--;
+
+send:
+ ASSERT(0 == uv_udp_send(&s->send_req,
+ &s->udp_handle,
+ bufs,
+ ARRAY_SIZE(bufs),
+ (const struct sockaddr*) &s->addr,
+ send_cb));
+ send_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ if (nread == 0)
+ return;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_ECANCELED);
+ return;
+ }
+
+ ASSERT(addr->sa_family == AF_INET);
+ ASSERT(!memcmp(buf->base, EXPECTED, nread));
+
+ recv_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void timeout_cb(uv_timer_t* timer) {
+ int i;
+
+ exiting = 1;
+
+ for (i = 0; i < n_senders_; i++)
+ uv_close((uv_handle_t*)&senders[i].udp_handle, close_cb);
+
+ for (i = 0; i < n_receivers_; i++)
+ uv_close((uv_handle_t*)&receivers[i].udp_handle, close_cb);
+}
+
+
+static int pummel(unsigned int n_senders,
+ unsigned int n_receivers,
+ unsigned long timeout) {
+ uv_timer_t timer_handle;
+ uint64_t duration;
+ uv_loop_t* loop;
+ unsigned int i;
+
+ ASSERT(n_senders <= ARRAY_SIZE(senders));
+ ASSERT(n_receivers <= ARRAY_SIZE(receivers));
+
+ loop = uv_default_loop();
+
+ n_senders_ = n_senders;
+ n_receivers_ = n_receivers;
+
+ if (timeout) {
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0));
+ /* Timer should not keep loop alive. */
+ uv_unref((uv_handle_t*)&timer_handle);
+ timed = 1;
+ }
+
+ for (i = 0; i < n_receivers; i++) {
+ struct receiver_state* s = receivers + i;
+ struct sockaddr_in addr;
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr));
+ ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
+ ASSERT(0 == uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb));
+ uv_unref((uv_handle_t*)&s->udp_handle);
+ }
+
+ bufs[0] = uv_buf_init(EXPECTED + 0, 10);
+ bufs[1] = uv_buf_init(EXPECTED + 10, 10);
+ bufs[2] = uv_buf_init(EXPECTED + 20, 10);
+ bufs[3] = uv_buf_init(EXPECTED + 30, 10);
+ bufs[4] = uv_buf_init(EXPECTED + 40, 5);
+
+ for (i = 0; i < n_senders; i++) {
+ struct sender_state* s = senders + i;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1",
+ BASE_PORT + (i % n_receivers),
+ &s->addr));
+ ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
+ ASSERT(0 == uv_udp_send(&s->send_req,
+ &s->udp_handle,
+ bufs,
+ ARRAY_SIZE(bufs),
+ (const struct sockaddr*) &s->addr,
+ send_cb));
+ }
+
+ duration = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ duration = uv_hrtime() - duration;
+ /* convert from nanoseconds to milliseconds */
+ duration = duration / (uint64_t) 1e6;
+
+ printf("udp_pummel_%dv%d: %.0f/s received, %.0f/s sent. "
+ "%u received, %u sent in %.1f seconds.\n",
+ n_receivers,
+ n_senders,
+ recv_cb_called / (duration / 1000.0),
+ send_cb_called / (duration / 1000.0),
+ recv_cb_called,
+ send_cb_called,
+ duration / 1000.0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#define X(a, b) \
+ BENCHMARK_IMPL(udp_pummel_##a##v##b) { \
+ return pummel(a, b, 0); \
+ } \
+ BENCHMARK_IMPL(udp_timed_pummel_##a##v##b) { \
+ return pummel(a, b, TEST_DURATION); \
+ }
+
+X(1, 1)
+X(1, 10)
+X(1, 100)
+X(1, 1000)
+X(10, 10)
+X(10, 100)
+X(10, 1000)
+X(100, 10)
+X(100, 100)
+X(100, 1000)
+X(1000, 1000)
+
+#undef X
diff --git a/3rdparty/libuv/test/blackhole-server.c b/3rdparty/libuv/test/blackhole-server.c
new file mode 100644
index 00000000000..ad878b35c61
--- /dev/null
+++ b/3rdparty/libuv/test/blackhole-server.c
@@ -0,0 +1,121 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ uv_tcp_t handle;
+ uv_shutdown_t shutdown_req;
+} conn_rec;
+
+static uv_tcp_t tcp_server;
+
+static void connection_cb(uv_stream_t* stream, int status);
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connection_cb(uv_stream_t* stream, int status) {
+ conn_rec* conn;
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(stream == (uv_stream_t*)&tcp_server);
+
+ conn = malloc(sizeof *conn);
+ ASSERT(conn != NULL);
+
+ r = uv_tcp_init(stream->loop, &conn->handle);
+ ASSERT(r == 0);
+
+ r = uv_accept(stream, (uv_stream_t*)&conn->handle);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&conn->handle, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ conn_rec* conn;
+ int r;
+
+ if (nread >= 0)
+ return;
+
+ ASSERT(nread == UV_EOF);
+
+ conn = container_of(stream, conn_rec, handle);
+
+ r = uv_shutdown(&conn->shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ conn_rec* conn = container_of(req, conn_rec, shutdown_req);
+ uv_close((uv_handle_t*)&conn->handle, close_cb);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ conn_rec* conn = container_of(handle, conn_rec, handle);
+ free(conn);
+}
+
+
+HELPER_IMPL(tcp4_blackhole_server) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(0 && "Blackhole server dropped out of event loop.");
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/dns-server.c b/3rdparty/libuv/test/dns-server.c
new file mode 100644
index 00000000000..80052c70398
--- /dev/null
+++ b/3rdparty/libuv/test/dns-server.c
@@ -0,0 +1,340 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req_t;
+
+
+/* used to track multiple DNS requests received */
+typedef struct {
+ char* prevbuf_ptr;
+ int prevbuf_pos;
+ int prevbuf_rem;
+} dnsstate;
+
+
+/* modify handle to append dnsstate */
+typedef struct {
+ uv_tcp_t handle;
+ dnsstate state;
+} dnshandle;
+
+
+static uv_loop_t* loop;
+
+
+static uv_tcp_t server;
+
+
+static void after_write(uv_write_t* req, int status);
+static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
+static void on_close(uv_handle_t* peer);
+static void on_connection(uv_stream_t*, int status);
+
+#define WRITE_BUF_LEN (64*1024)
+#define DNSREC_LEN (4)
+
+#define LEN_OFFSET 0
+#define QUERYID_OFFSET 2
+
+static unsigned char DNSRsp[] = {
+ 0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0
+};
+
+static unsigned char qrecord[] = {
+ 5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1
+};
+
+static unsigned char arecord[] = {
+ 0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1
+};
+
+
+static void after_write(uv_write_t* req, int status) {
+ write_req_t* wr;
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ wr = (write_req_t*) req;
+
+ /* Free the read/write buffer and the request */
+ free(wr->buf.base);
+ free(wr);
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void addrsp(write_req_t* wr, char* hdr) {
+ char * dnsrsp;
+ short int rsplen;
+ short int* reclen;
+
+ rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
+
+ ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
+
+ dnsrsp = wr->buf.base + wr->buf.len;
+
+ /* copy stock response */
+ memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
+ memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
+ memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
+
+ /* overwrite with network order length and id from request header */
+ reclen = (short int*)dnsrsp;
+ *reclen = htons(rsplen-2);
+ dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
+ dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
+
+ wr->buf.len += rsplen;
+}
+
+static void process_req(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ write_req_t* wr;
+ dnshandle* dns = (dnshandle*)handle;
+ char hdrbuf[DNSREC_LEN];
+ int hdrbuf_remaining = DNSREC_LEN;
+ int rec_remaining = 0;
+ int readbuf_remaining;
+ char* dnsreq;
+ char* hdrstart;
+ int usingprev = 0;
+
+ wr = (write_req_t*) malloc(sizeof *wr);
+ wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
+ wr->buf.len = 0;
+
+ if (dns->state.prevbuf_ptr != NULL) {
+ dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
+ readbuf_remaining = dns->state.prevbuf_rem;
+ usingprev = 1;
+ } else {
+ dnsreq = buf->base;
+ readbuf_remaining = nread;
+ }
+ hdrstart = dnsreq;
+
+ while (dnsreq != NULL) {
+ /* something to process */
+ while (readbuf_remaining > 0) {
+ /* something to process in current buffer */
+ if (hdrbuf_remaining > 0) {
+ /* process len and id */
+ if (readbuf_remaining < hdrbuf_remaining) {
+ /* too little to get request header. save for next buffer */
+ memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
+ dnsreq,
+ readbuf_remaining);
+ hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
+ break;
+ } else {
+ /* save header */
+ memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
+ dnsreq,
+ hdrbuf_remaining);
+ dnsreq += hdrbuf_remaining;
+ readbuf_remaining -= hdrbuf_remaining;
+ hdrbuf_remaining = 0;
+
+ /* get record length */
+ rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1];
+ rec_remaining -= (DNSREC_LEN - 2);
+ }
+ }
+
+ if (rec_remaining <= readbuf_remaining) {
+ /* prepare reply */
+ addrsp(wr, hdrbuf);
+
+ /* move to next record */
+ dnsreq += rec_remaining;
+ hdrstart = dnsreq;
+ readbuf_remaining -= rec_remaining;
+ rec_remaining = 0;
+ hdrbuf_remaining = DNSREC_LEN;
+ } else {
+ /* otherwise this buffer is done. */
+ rec_remaining -= readbuf_remaining;
+ break;
+ }
+ }
+
+ /* If we had to use bytes from prev buffer, start processing the current
+ * one.
+ */
+ if (usingprev == 1) {
+ /* free previous buffer */
+ free(dns->state.prevbuf_ptr);
+ dnsreq = buf->base;
+ readbuf_remaining = nread;
+ usingprev = 0;
+ } else {
+ dnsreq = NULL;
+ }
+ }
+
+ /* send write buffer */
+ if (wr->buf.len > 0) {
+ if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
+ FATAL("uv_write failed");
+ }
+ }
+
+ if (readbuf_remaining > 0) {
+ /* save start of record position, so we can continue on next read */
+ dns->state.prevbuf_ptr = buf->base;
+ dns->state.prevbuf_pos = hdrstart - buf->base;
+ dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
+ } else {
+ /* nothing left in this buffer */
+ dns->state.prevbuf_ptr = NULL;
+ dns->state.prevbuf_pos = 0;
+ dns->state.prevbuf_rem = 0;
+ free(buf->base);
+ }
+}
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_shutdown_t* req;
+
+ if (nread < 0) {
+ /* Error or EOF */
+ ASSERT(nread == UV_EOF);
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ req = malloc(sizeof *req);
+ uv_shutdown(req, handle, after_shutdown);
+
+ return;
+ }
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+ /* process requests and send responses */
+ process_req(handle, nread, buf);
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+}
+
+
+static void buf_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ dnshandle* handle;
+ int r;
+
+ ASSERT(status == 0);
+
+ handle = (dnshandle*) malloc(sizeof *handle);
+ ASSERT(handle != NULL);
+
+ /* initialize read buffer state */
+ handle->state.prevbuf_ptr = 0;
+ handle->state.prevbuf_pos = 0;
+ handle->state.prevbuf_rem = 0;
+
+ r = uv_tcp_init(loop, (uv_tcp_t*)handle);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static int dns_start(int port) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
+
+ r = uv_tcp_init(loop, &server);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&server, 128, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+HELPER_IMPL(dns_server) {
+ loop = uv_default_loop();
+
+ if (dns_start(TEST_PORT_2))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/echo-server.c b/3rdparty/libuv/test/echo-server.c
new file mode 100644
index 00000000000..bfed67675dd
--- /dev/null
+++ b/3rdparty/libuv/test/echo-server.c
@@ -0,0 +1,378 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req_t;
+
+static uv_loop_t* loop;
+
+static int server_closed;
+static stream_type serverType;
+static uv_tcp_t tcpServer;
+static uv_udp_t udpServer;
+static uv_pipe_t pipeServer;
+static uv_handle_t* server;
+
+static void after_write(uv_write_t* req, int status);
+static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
+static void on_close(uv_handle_t* peer);
+static void on_server_close(uv_handle_t* handle);
+static void on_connection(uv_stream_t*, int status);
+
+
+static void after_write(uv_write_t* req, int status) {
+ write_req_t* wr;
+
+ /* Free the read/write buffer and the request */
+ wr = (write_req_t*) req;
+ free(wr->buf.base);
+ free(wr);
+
+ if (status == 0)
+ return;
+
+ fprintf(stderr,
+ "uv_write error: %s - %s\n",
+ uv_err_name(status),
+ uv_strerror(status));
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int i;
+ write_req_t *wr;
+ uv_shutdown_t* sreq;
+
+ if (nread < 0) {
+ /* Error or EOF */
+ ASSERT(nread == UV_EOF);
+
+ free(buf->base);
+ sreq = malloc(sizeof* sreq);
+ ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown));
+ return;
+ }
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ /*
+ * Scan for the letter Q which signals that we should quit the server.
+ * If we get QS it means close the stream.
+ */
+ if (!server_closed) {
+ for (i = 0; i < nread; i++) {
+ if (buf->base[i] == 'Q') {
+ if (i + 1 < nread && buf->base[i + 1] == 'S') {
+ free(buf->base);
+ uv_close((uv_handle_t*)handle, on_close);
+ return;
+ } else {
+ uv_close(server, on_server_close);
+ server_closed = 1;
+ }
+ }
+ }
+ }
+
+ wr = (write_req_t*) malloc(sizeof *wr);
+ ASSERT(wr != NULL);
+ wr->buf = uv_buf_init(buf->base, nread);
+
+ if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
+ FATAL("uv_write failed");
+ }
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+}
+
+
+static void echo_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_stream_t* stream;
+ int r;
+
+ if (status != 0) {
+ fprintf(stderr, "Connect error %s\n", uv_err_name(status));
+ }
+ ASSERT(status == 0);
+
+ switch (serverType) {
+ case TCP:
+ stream = malloc(sizeof(uv_tcp_t));
+ ASSERT(stream != NULL);
+ r = uv_tcp_init(loop, (uv_tcp_t*)stream);
+ ASSERT(r == 0);
+ break;
+
+ case PIPE:
+ stream = malloc(sizeof(uv_pipe_t));
+ ASSERT(stream != NULL);
+ r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
+ ASSERT(r == 0);
+ break;
+
+ default:
+ ASSERT(0 && "Bad serverType");
+ abort();
+ }
+
+ /* associate server with stream */
+ stream->data = server;
+
+ r = uv_accept(server, stream);
+ ASSERT(r == 0);
+
+ r = uv_read_start(stream, echo_alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static void on_server_close(uv_handle_t* handle) {
+ ASSERT(handle == server);
+}
+
+
+static void on_send(uv_udp_send_t* req, int status);
+
+
+static void on_recv(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ uv_udp_send_t* req;
+ uv_buf_t sndbuf;
+
+ ASSERT(nread > 0);
+ ASSERT(addr->sa_family == AF_INET);
+
+ req = malloc(sizeof(*req));
+ ASSERT(req != NULL);
+
+ sndbuf = *rcvbuf;
+ ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
+}
+
+
+static void on_send(uv_udp_send_t* req, int status) {
+ ASSERT(status == 0);
+ free(req);
+}
+
+
+static int tcp4_echo_start(int port) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
+
+ server = (uv_handle_t*)&tcpServer;
+ serverType = TCP;
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error %s\n", uv_err_name(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int tcp6_echo_start(int port) {
+ struct sockaddr_in6 addr6;
+ int r;
+
+ ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
+
+ server = (uv_handle_t*)&tcpServer;
+ serverType = TCP;
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ /* IPv6 is optional as not all platforms support it */
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
+ if (r) {
+ /* show message but return OK */
+ fprintf(stderr, "IPv6 not supported\n");
+ return 0;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int udp4_echo_start(int port) {
+ int r;
+
+ server = (uv_handle_t*)&udpServer;
+ serverType = UDP;
+
+ r = uv_udp_init(loop, &udpServer);
+ if (r) {
+ fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
+ if (r) {
+ fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int pipe_echo_start(char* pipeName) {
+ int r;
+
+#ifndef _WIN32
+ {
+ uv_fs_t req;
+ uv_fs_unlink(NULL, &req, pipeName, NULL);
+ uv_fs_req_cleanup(&req);
+ }
+#endif
+
+ server = (uv_handle_t*)&pipeServer;
+ serverType = PIPE;
+
+ r = uv_pipe_init(loop, &pipeServer, 0);
+ if (r) {
+ fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_pipe_bind(&pipeServer, pipeName);
+ if (r) {
+ fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
+ if (r) {
+ fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+HELPER_IMPL(tcp4_echo_server) {
+ loop = uv_default_loop();
+
+ if (tcp4_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(tcp6_echo_server) {
+ loop = uv_default_loop();
+
+ if (tcp6_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(pipe_echo_server) {
+ loop = uv_default_loop();
+
+ if (pipe_echo_start(TEST_PIPENAME))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(udp4_echo_server) {
+ loop = uv_default_loop();
+
+ if (udp4_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/fixtures/empty_file b/3rdparty/libuv/test/fixtures/empty_file
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/3rdparty/libuv/test/fixtures/empty_file
diff --git a/3rdparty/libuv/test/fixtures/load_error.node b/3rdparty/libuv/test/fixtures/load_error.node
new file mode 100644
index 00000000000..323fae03f46
--- /dev/null
+++ b/3rdparty/libuv/test/fixtures/load_error.node
@@ -0,0 +1 @@
+foobar
diff --git a/3rdparty/libuv/test/run-benchmarks.c b/3rdparty/libuv/test/run-benchmarks.c
new file mode 100644
index 00000000000..6e42623d54c
--- /dev/null
+++ b/3rdparty/libuv/test/run-benchmarks.c
@@ -0,0 +1,65 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "runner.h"
+#include "task.h"
+
+/* Actual benchmarks and helpers are defined in benchmark-list.h */
+#include "benchmark-list.h"
+
+
+static int maybe_run_test(int argc, char **argv);
+
+
+int main(int argc, char **argv) {
+ if (platform_init(argc, argv))
+ return EXIT_FAILURE;
+
+ switch (argc) {
+ case 1: return run_tests(1);
+ case 2: return maybe_run_test(argc, argv);
+ case 3: return run_test_part(argv[1], argv[2]);
+ default:
+ fprintf(stderr, "Too many arguments.\n");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+static int maybe_run_test(int argc, char **argv) {
+ if (strcmp(argv[1], "--list") == 0) {
+ print_tests(stdout);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "spawn_helper") == 0) {
+ printf("hello world\n");
+ return 42;
+ }
+
+ return run_test(argv[1], 1, 1);
+}
diff --git a/3rdparty/libuv/test/run-tests.c b/3rdparty/libuv/test/run-tests.c
new file mode 100644
index 00000000000..b4be01f6f95
--- /dev/null
+++ b/3rdparty/libuv/test/run-tests.c
@@ -0,0 +1,181 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "runner.h"
+#include "task.h"
+
+/* Actual tests and helpers are defined in test-list.h */
+#include "test-list.h"
+
+int ipc_helper(int listen_after_write);
+int ipc_helper_tcp_connection(void);
+int ipc_send_recv_helper(void);
+int ipc_helper_bind_twice(void);
+int stdio_over_pipes_helper(void);
+int spawn_stdin_stdout(void);
+
+static int maybe_run_test(int argc, char **argv);
+
+
+int main(int argc, char **argv) {
+ if (platform_init(argc, argv))
+ return EXIT_FAILURE;
+
+ argv = uv_setup_args(argc, argv);
+
+ switch (argc) {
+ case 1: return run_tests(0);
+ case 2: return maybe_run_test(argc, argv);
+ case 3: return run_test_part(argv[1], argv[2]);
+ default:
+ fprintf(stderr, "Too many arguments.\n");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+static int maybe_run_test(int argc, char **argv) {
+ if (strcmp(argv[1], "--list") == 0) {
+ print_tests(stdout);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) {
+ return ipc_helper(0);
+ }
+
+ if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) {
+ return ipc_helper(1);
+ }
+
+ if (strcmp(argv[1], "ipc_send_recv_helper") == 0) {
+ return ipc_send_recv_helper();
+ }
+
+ if (strcmp(argv[1], "ipc_helper_tcp_connection") == 0) {
+ return ipc_helper_tcp_connection();
+ }
+
+ if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
+ return ipc_helper_bind_twice();
+ }
+
+ if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
+ return stdio_over_pipes_helper();
+ }
+
+ if (strcmp(argv[1], "spawn_helper1") == 0) {
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper2") == 0) {
+ printf("hello world\n");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper3") == 0) {
+ char buffer[256];
+ ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin));
+ buffer[sizeof(buffer) - 1] = '\0';
+ fputs(buffer, stdout);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper4") == 0) {
+ /* Never surrender, never return! */
+ while (1) uv_sleep(10000);
+ }
+
+ if (strcmp(argv[1], "spawn_helper5") == 0) {
+ const char out[] = "fourth stdio!\n";
+#ifdef _WIN32
+ DWORD bytes;
+ WriteFile((HANDLE) _get_osfhandle(3), out, sizeof(out) - 1, &bytes, NULL);
+#else
+ {
+ ssize_t r;
+
+ do
+ r = write(3, out, sizeof(out) - 1);
+ while (r == -1 && errno == EINTR);
+
+ fsync(3);
+ }
+#endif
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper6") == 0) {
+ int r;
+
+ r = fprintf(stdout, "hello world\n");
+ ASSERT(r > 0);
+
+ r = fprintf(stderr, "hello errworld\n");
+ ASSERT(r > 0);
+
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper7") == 0) {
+ int r;
+ char *test;
+ /* Test if the test value from the parent is still set */
+ test = getenv("ENV_TEST");
+ ASSERT(test != NULL);
+
+ r = fprintf(stdout, "%s", test);
+ ASSERT(r > 0);
+
+ return 1;
+ }
+
+#ifndef _WIN32
+ if (strcmp(argv[1], "spawn_helper8") == 0) {
+ int fd;
+ ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd)));
+ ASSERT(fd > 2);
+ ASSERT(-1 == write(fd, "x", 1));
+
+ return 1;
+ }
+#endif /* !_WIN32 */
+
+ if (strcmp(argv[1], "spawn_helper9") == 0) {
+ return spawn_stdin_stdout();
+ }
+
+ return run_test(argv[1], 0, 1);
+}
diff --git a/3rdparty/libuv/test/runner-unix.c b/3rdparty/libuv/test/runner-unix.c
new file mode 100644
index 00000000000..2264d1e89d5
--- /dev/null
+++ b/3rdparty/libuv/test/runner-unix.c
@@ -0,0 +1,400 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "runner-unix.h"
+#include "runner.h"
+
+#include <limits.h>
+#include <stdint.h> /* uintptr_t */
+
+#include <errno.h>
+#include <unistd.h> /* readlink, usleep */
+#include <string.h> /* strdup */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char **argv) {
+ const char* tap;
+
+ tap = getenv("UV_TAP_OUTPUT");
+ tap_output = (tap != NULL && atoi(tap) > 0);
+
+ /* Disable stdio output buffering. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+ signal(SIGPIPE, SIG_IGN);
+
+ if (realpath(argv[0], executable_path) == NULL) {
+ perror("realpath");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
+/* Make sure that all stdio output of the processes is buffered up. */
+int process_start(char* name, char* part, process_info_t* p, int is_helper) {
+ FILE* stdout_file;
+ const char* arg;
+ char* args[16];
+ int n;
+ pid_t pid;
+
+ stdout_file = tmpfile();
+ if (!stdout_file) {
+ perror("tmpfile");
+ return -1;
+ }
+
+ p->terminated = 0;
+ p->status = 0;
+
+ pid = fork();
+
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* child */
+ arg = getenv("UV_USE_VALGRIND");
+ n = 0;
+
+ /* Disable valgrind for helpers, it complains about helpers leaking memory.
+ * They're killed after the test and as such never get a chance to clean up.
+ */
+ if (is_helper == 0 && arg != NULL && atoi(arg) != 0) {
+ args[n++] = "valgrind";
+ args[n++] = "--quiet";
+ args[n++] = "--leak-check=full";
+ args[n++] = "--show-reachable=yes";
+ args[n++] = "--error-exitcode=125";
+ }
+
+ args[n++] = executable_path;
+ args[n++] = name;
+ args[n++] = part;
+ args[n++] = NULL;
+
+ dup2(fileno(stdout_file), STDOUT_FILENO);
+ dup2(fileno(stdout_file), STDERR_FILENO);
+ execvp(args[0], args);
+ perror("execvp()");
+ _exit(127);
+ }
+
+ /* parent */
+ p->pid = pid;
+ p->name = strdup(name);
+ p->stdout_file = stdout_file;
+
+ return 0;
+}
+
+
+typedef struct {
+ int pipe[2];
+ process_info_t* vec;
+ int n;
+} dowait_args;
+
+
+/* This function is run inside a pthread. We do this so that we can possibly
+ * timeout.
+ */
+static void* dowait(void* data) {
+ dowait_args* args = data;
+
+ int i, r;
+ process_info_t* p;
+
+ for (i = 0; i < args->n; i++) {
+ p = (process_info_t*)(args->vec + i * sizeof(process_info_t));
+ if (p->terminated) continue;
+ r = waitpid(p->pid, &p->status, 0);
+ if (r < 0) {
+ perror("waitpid");
+ return NULL;
+ }
+ p->terminated = 1;
+ }
+
+ if (args->pipe[1] >= 0) {
+ /* Write a character to the main thread to notify it about this. */
+ ssize_t r;
+
+ do
+ r = write(args->pipe[1], "", 1);
+ while (r == -1 && errno == EINTR);
+ }
+
+ return NULL;
+}
+
+
+/* Wait for all `n` processes in `vec` to terminate. */
+/* Time out after `timeout` msec, or never if timeout == -1 */
+/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
+int process_wait(process_info_t* vec, int n, int timeout) {
+ int i;
+ int r;
+ int retval;
+ process_info_t* p;
+ dowait_args args;
+ pthread_t tid;
+ pthread_attr_t attr;
+ unsigned int elapsed_ms;
+ struct timeval timebase;
+ struct timeval tv;
+ fd_set fds;
+
+ args.vec = vec;
+ args.n = n;
+ args.pipe[0] = -1;
+ args.pipe[1] = -1;
+
+ /* The simple case is where there is no timeout */
+ if (timeout == -1) {
+ dowait(&args);
+ return 0;
+ }
+
+ /* Hard case. Do the wait with a timeout.
+ *
+ * Assumption: we are the only ones making this call right now. Otherwise
+ * we'd need to lock vec.
+ */
+
+ r = pipe((int*)&(args.pipe));
+ if (r) {
+ perror("pipe()");
+ return -1;
+ }
+
+ if (pthread_attr_init(&attr))
+ abort();
+
+ if (pthread_attr_setstacksize(&attr, 256 * 1024))
+ abort();
+
+ r = pthread_create(&tid, &attr, dowait, &args);
+
+ if (pthread_attr_destroy(&attr))
+ abort();
+
+ if (r) {
+ perror("pthread_create()");
+ retval = -1;
+ goto terminate;
+ }
+
+ if (gettimeofday(&timebase, NULL))
+ abort();
+
+ tv = timebase;
+ for (;;) {
+ /* Check that gettimeofday() doesn't jump back in time. */
+ assert(tv.tv_sec == timebase.tv_sec ||
+ (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec));
+
+ elapsed_ms =
+ (tv.tv_sec - timebase.tv_sec) * 1000 +
+ (tv.tv_usec / 1000) -
+ (timebase.tv_usec / 1000);
+
+ r = 0; /* Timeout. */
+ if (elapsed_ms >= (unsigned) timeout)
+ break;
+
+ tv.tv_sec = (timeout - elapsed_ms) / 1000;
+ tv.tv_usec = (timeout - elapsed_ms) % 1000 * 1000;
+
+ FD_ZERO(&fds);
+ FD_SET(args.pipe[0], &fds);
+
+ r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv);
+ if (!(r == -1 && errno == EINTR))
+ break;
+
+ if (gettimeofday(&tv, NULL))
+ abort();
+ }
+
+ if (r == -1) {
+ perror("select()");
+ retval = -1;
+
+ } else if (r) {
+ /* The thread completed successfully. */
+ retval = 0;
+
+ } else {
+ /* Timeout. Kill all the children. */
+ for (i = 0; i < n; i++) {
+ p = (process_info_t*)(vec + i * sizeof(process_info_t));
+ kill(p->pid, SIGTERM);
+ }
+ retval = -2;
+ }
+
+ if (pthread_join(tid, NULL))
+ abort();
+
+terminate:
+ close(args.pipe[0]);
+ close(args.pipe[1]);
+ return retval;
+}
+
+
+/* Returns the number of bytes in the stdio output buffer for process `p`. */
+long int process_output_size(process_info_t *p) {
+ /* Size of the p->stdout_file */
+ struct stat buf;
+
+ int r = fstat(fileno(p->stdout_file), &buf);
+ if (r < 0) {
+ return -1;
+ }
+
+ return (long)buf.st_size;
+}
+
+
+/* Copy the contents of the stdio output buffer to `fd`. */
+int process_copy_output(process_info_t *p, int fd) {
+ ssize_t nwritten;
+ char buf[1024];
+ int r;
+
+ r = fseek(p->stdout_file, 0, SEEK_SET);
+ if (r < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ /* TODO: what if the line is longer than buf */
+ while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
+ /* TODO: what if write doesn't write the whole buffer... */
+ nwritten = 0;
+
+ if (tap_output)
+ nwritten += write(fd, "#", 1);
+
+ nwritten += write(fd, buf, strlen(buf));
+
+ if (nwritten < 0) {
+ perror("write");
+ return -1;
+ }
+ }
+
+ if (ferror(p->stdout_file)) {
+ perror("read");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* Copy the last line of the stdio output buffer to `buffer` */
+int process_read_last_line(process_info_t *p,
+ char* buffer,
+ size_t buffer_len) {
+ char* ptr;
+
+ int r = fseek(p->stdout_file, 0, SEEK_SET);
+ if (r < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ buffer[0] = '\0';
+
+ while (fgets(buffer, buffer_len, p->stdout_file) != NULL) {
+ for (ptr = buffer; *ptr && *ptr != '\r' && *ptr != '\n'; ptr++);
+ *ptr = '\0';
+ }
+
+ if (ferror(p->stdout_file)) {
+ perror("read");
+ buffer[0] = '\0';
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Return the name that was specified when `p` was started by process_start */
+char* process_get_name(process_info_t *p) {
+ return p->name;
+}
+
+
+/* Terminate process `p`. */
+int process_terminate(process_info_t *p) {
+ return kill(p->pid, SIGTERM);
+}
+
+
+/* Return the exit code of process p. */
+/* On error, return -1. */
+int process_reap(process_info_t *p) {
+ if (WIFEXITED(p->status)) {
+ return WEXITSTATUS(p->status);
+ } else {
+ return p->status; /* ? */
+ }
+}
+
+
+/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
+void process_cleanup(process_info_t *p) {
+ fclose(p->stdout_file);
+ free(p->name);
+}
+
+
+/* Move the console cursor one line up and back to the first column. */
+void rewind_cursor(void) {
+ fprintf(stderr, "\033[2K\r");
+}
+
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec) {
+ usleep(msec * 1000);
+}
diff --git a/3rdparty/libuv/test/runner-unix.h b/3rdparty/libuv/test/runner-unix.h
new file mode 100644
index 00000000000..e21847f92c0
--- /dev/null
+++ b/3rdparty/libuv/test/runner-unix.h
@@ -0,0 +1,36 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEST_RUNNER_UNIX_H
+#define TEST_RUNNER_UNIX_H
+
+#include <sys/types.h>
+#include <stdio.h> /* FILE */
+
+typedef struct {
+ FILE* stdout_file;
+ pid_t pid;
+ char* name;
+ int status;
+ int terminated;
+} process_info_t;
+
+#endif /* TEST_RUNNER_UNIX_H */
diff --git a/3rdparty/libuv/test/runner-win.c b/3rdparty/libuv/test/runner-win.c
new file mode 100644
index 00000000000..97ef7599eb8
--- /dev/null
+++ b/3rdparty/libuv/test/runner-win.c
@@ -0,0 +1,371 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <process.h>
+#if !defined(__MINGW32__)
+# include <crtdbg.h>
+#endif
+
+
+#include "task.h"
+#include "runner.h"
+
+
+/*
+ * Define the stuff that MinGW doesn't have
+ */
+#ifndef GetFileSizeEx
+ WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile,
+ PLARGE_INTEGER lpFileSize);
+#endif
+
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char **argv) {
+ const char* tap;
+
+ tap = getenv("UV_TAP_OUTPUT");
+ tap_output = (tap != NULL && atoi(tap) > 0);
+
+ /* Disable the "application crashed" popup. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+#if !defined(__MINGW32__)
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+#endif
+
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+
+ /* Disable stdio output buffering. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ strcpy(executable_path, argv[0]);
+
+ return 0;
+}
+
+
+int process_start(char *name, char *part, process_info_t *p, int is_helper) {
+ HANDLE file = INVALID_HANDLE_VALUE;
+ HANDLE nul = INVALID_HANDLE_VALUE;
+ WCHAR path[MAX_PATH], filename[MAX_PATH];
+ WCHAR image[MAX_PATH + 1];
+ WCHAR args[MAX_PATH * 2];
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ DWORD result;
+
+ if (GetTempPathW(sizeof(path) / sizeof(WCHAR), (WCHAR*)&path) == 0)
+ goto error;
+ if (GetTempFileNameW((WCHAR*)&path, L"uv", 0, (WCHAR*)&filename) == 0)
+ goto error;
+
+ file = CreateFileW((WCHAR*)filename,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ goto error;
+
+ if (!SetHandleInformation(file, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ goto error;
+
+ nul = CreateFileA("nul",
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (nul == INVALID_HANDLE_VALUE)
+ goto error;
+
+ if (!SetHandleInformation(nul, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ goto error;
+
+ result = GetModuleFileNameW(NULL,
+ (WCHAR*) &image,
+ sizeof(image) / sizeof(WCHAR));
+ if (result == 0 || result == sizeof(image))
+ goto error;
+
+ if (part) {
+ if (_snwprintf((WCHAR*)args,
+ sizeof(args) / sizeof(WCHAR),
+ L"\"%s\" %S %S",
+ image,
+ name,
+ part) < 0) {
+ goto error;
+ }
+ } else {
+ if (_snwprintf((WCHAR*)args,
+ sizeof(args) / sizeof(WCHAR),
+ L"\"%s\" %S",
+ image,
+ name) < 0) {
+ goto error;
+ }
+ }
+
+ memset((void*)&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = nul;
+ si.hStdOutput = file;
+ si.hStdError = file;
+
+ if (!CreateProcessW(image, args, NULL, NULL, TRUE,
+ 0, NULL, NULL, &si, &pi))
+ goto error;
+
+ CloseHandle(pi.hThread);
+
+ SetHandleInformation(nul, HANDLE_FLAG_INHERIT, 0);
+ SetHandleInformation(file, HANDLE_FLAG_INHERIT, 0);
+
+ p->stdio_in = nul;
+ p->stdio_out = file;
+ p->process = pi.hProcess;
+ p->name = part;
+
+ return 0;
+
+error:
+ if (file != INVALID_HANDLE_VALUE)
+ CloseHandle(file);
+ if (nul != INVALID_HANDLE_VALUE)
+ CloseHandle(nul);
+
+ return -1;
+}
+
+
+/* Timeout is is msecs. Set timeout < 0 to never time out. */
+/* Returns 0 when all processes are terminated, -2 on timeout. */
+int process_wait(process_info_t *vec, int n, int timeout) {
+ int i;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ DWORD timeout_api, result;
+
+ /* If there's nothing to wait for, return immediately. */
+ if (n == 0)
+ return 0;
+
+ ASSERT(n <= MAXIMUM_WAIT_OBJECTS);
+
+ for (i = 0; i < n; i++)
+ handles[i] = vec[i].process;
+
+ if (timeout >= 0) {
+ timeout_api = (DWORD)timeout;
+ } else {
+ timeout_api = INFINITE;
+ }
+
+ result = WaitForMultipleObjects(n, handles, TRUE, timeout_api);
+
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n) {
+ /* All processes are terminated. */
+ return 0;
+ }
+ if (result == WAIT_TIMEOUT) {
+ return -2;
+ }
+ return -1;
+}
+
+
+long int process_output_size(process_info_t *p) {
+ LARGE_INTEGER size;
+ if (!GetFileSizeEx(p->stdio_out, &size))
+ return -1;
+ return (long int)size.QuadPart;
+}
+
+
+int process_copy_output(process_info_t *p, int fd) {
+ DWORD read;
+ char buf[1024];
+ char *line, *start;
+
+ if (SetFilePointer(p->stdio_out,
+ 0,
+ 0,
+ FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+ return -1;
+ }
+
+ if (tap_output)
+ write(fd, "#", 1);
+
+ while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) &&
+ read > 0) {
+ if (tap_output) {
+ start = buf;
+
+ while ((line = strchr(start, '\n')) != NULL) {
+ write(fd, start, line - start + 1);
+ write(fd, "#", 1);
+ start = line + 1;
+ }
+
+ if (start < buf + read)
+ write(fd, start, buf + read - start);
+ } else {
+ write(fd, buf, read);
+ }
+ }
+
+ if (tap_output)
+ write(fd, "\n", 1);
+
+ if (GetLastError() != ERROR_HANDLE_EOF)
+ return -1;
+
+ return 0;
+}
+
+
+int process_read_last_line(process_info_t *p,
+ char * buffer,
+ size_t buffer_len) {
+ DWORD size;
+ DWORD read;
+ DWORD start;
+ OVERLAPPED overlapped;
+
+ ASSERT(buffer_len > 0);
+
+ size = GetFileSize(p->stdio_out, NULL);
+ if (size == INVALID_FILE_SIZE)
+ return -1;
+
+ if (size == 0) {
+ buffer[0] = '\0';
+ return 1;
+ }
+
+ memset(&overlapped, 0, sizeof overlapped);
+ if (size >= buffer_len)
+ overlapped.Offset = size - buffer_len - 1;
+
+ if (!ReadFile(p->stdio_out, buffer, buffer_len - 1, &read, &overlapped))
+ return -1;
+
+ for (start = read - 1; start >= 0; start--) {
+ if (buffer[start] == '\n' || buffer[start] == '\r')
+ break;
+ }
+
+ if (start > 0)
+ memmove(buffer, buffer + start, read - start);
+
+ buffer[read - start] = '\0';
+
+ return 0;
+}
+
+
+char* process_get_name(process_info_t *p) {
+ return p->name;
+}
+
+
+int process_terminate(process_info_t *p) {
+ if (!TerminateProcess(p->process, 1))
+ return -1;
+ return 0;
+}
+
+
+int process_reap(process_info_t *p) {
+ DWORD exitCode;
+ if (!GetExitCodeProcess(p->process, &exitCode))
+ return -1;
+ return (int)exitCode;
+}
+
+
+void process_cleanup(process_info_t *p) {
+ CloseHandle(p->process);
+ CloseHandle(p->stdio_in);
+ CloseHandle(p->stdio_out);
+}
+
+
+static int clear_line() {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD coord;
+ DWORD written;
+
+ handle = (HANDLE)_get_osfhandle(fileno(stderr));
+ if (handle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (!GetConsoleScreenBufferInfo(handle, &info))
+ return -1;
+
+ coord = info.dwCursorPosition;
+ if (coord.Y <= 0)
+ return -1;
+
+ coord.X = 0;
+
+ if (!SetConsoleCursorPosition(handle, coord))
+ return -1;
+
+ if (!FillConsoleOutputCharacterW(handle,
+ 0x20,
+ info.dwSize.X,
+ coord,
+ &written)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void rewind_cursor() {
+ if (clear_line() == -1) {
+ /* If clear_line fails (stdout is not a console), print a newline. */
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec) {
+ Sleep(msec);
+}
diff --git a/3rdparty/libuv/test/runner-win.h b/3rdparty/libuv/test/runner-win.h
new file mode 100644
index 00000000000..8cc4c16eb22
--- /dev/null
+++ b/3rdparty/libuv/test/runner-win.h
@@ -0,0 +1,39 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Don't complain about write(), fileno() etc. being deprecated. */
+#pragma warning(disable : 4996)
+
+
+#include <winsock2.h>
+#include <windows.h>
+#include <stdio.h>
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+typedef struct {
+ HANDLE process;
+ HANDLE stdio_in;
+ HANDLE stdio_out;
+ char *name;
+} process_info_t;
diff --git a/3rdparty/libuv/test/runner.c b/3rdparty/libuv/test/runner.c
new file mode 100644
index 00000000000..c616d176445
--- /dev/null
+++ b/3rdparty/libuv/test/runner.c
@@ -0,0 +1,466 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "runner.h"
+#include "task.h"
+#include "uv.h"
+
+char executable_path[sizeof(executable_path)];
+
+int tap_output = 0;
+
+
+static void log_progress(int total,
+ int passed,
+ int failed,
+ int todos,
+ int skipped,
+ const char* name) {
+ int progress;
+
+ if (total == 0)
+ total = 1;
+
+ progress = 100 * (passed + failed + skipped + todos) / total;
+ fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
+ progress,
+ passed,
+ failed,
+ todos,
+ skipped,
+ name);
+ fflush(stderr);
+}
+
+
+const char* fmt(double d) {
+ static char buf[1024];
+ static char* p;
+ uint64_t v;
+
+ if (p == NULL)
+ p = buf;
+
+ p += 31;
+
+ if (p >= buf + sizeof(buf))
+ return "<buffer too small>";
+
+ v = (uint64_t) d;
+
+#if 0 /* works but we don't care about fractional precision */
+ if (d - v >= 0.01) {
+ *--p = '0' + (uint64_t) (d * 100) % 10;
+ *--p = '0' + (uint64_t) (d * 10) % 10;
+ *--p = '.';
+ }
+#endif
+
+ if (v == 0)
+ *--p = '0';
+
+ while (v) {
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = ',';
+ }
+
+ return p;
+}
+
+
+int run_tests(int benchmark_output) {
+ int total;
+ int passed;
+ int failed;
+ int todos;
+ int skipped;
+ int current;
+ int test_result;
+ task_entry_t* task;
+
+ /* Count the number of tests. */
+ total = 0;
+ for (task = TASKS; task->main; task++) {
+ if (!task->is_helper) {
+ total++;
+ }
+ }
+
+ if (tap_output) {
+ fprintf(stderr, "1..%d\n", total);
+ fflush(stderr);
+ }
+
+ /* Run all tests. */
+ passed = 0;
+ failed = 0;
+ todos = 0;
+ skipped = 0;
+ current = 1;
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper) {
+ continue;
+ }
+
+ if (!tap_output)
+ rewind_cursor();
+
+ if (!benchmark_output && !tap_output) {
+ log_progress(total, passed, failed, todos, skipped, task->task_name);
+ }
+
+ test_result = run_test(task->task_name, benchmark_output, current);
+ switch (test_result) {
+ case TEST_OK: passed++; break;
+ case TEST_TODO: todos++; break;
+ case TEST_SKIP: skipped++; break;
+ default: failed++;
+ }
+ current++;
+ }
+
+ if (!tap_output)
+ rewind_cursor();
+
+ if (!benchmark_output && !tap_output) {
+ log_progress(total, passed, failed, todos, skipped, "Done.\n");
+ }
+
+ return failed;
+}
+
+
+void log_tap_result(int test_count,
+ const char* test,
+ int status,
+ process_info_t* process) {
+ const char* result;
+ const char* directive;
+ char reason[1024];
+
+ switch (status) {
+ case TEST_OK:
+ result = "ok";
+ directive = "";
+ break;
+ case TEST_TODO:
+ result = "not ok";
+ directive = " # TODO ";
+ break;
+ case TEST_SKIP:
+ result = "ok";
+ directive = " # SKIP ";
+ break;
+ default:
+ result = "not ok";
+ directive = "";
+ }
+
+ if ((status == TEST_SKIP || status == TEST_TODO) &&
+ process_output_size(process) > 0) {
+ process_read_last_line(process, reason, sizeof reason);
+ } else {
+ reason[0] = '\0';
+ }
+
+ fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
+ fflush(stderr);
+}
+
+
+int run_test(const char* test,
+ int benchmark_output,
+ int test_count) {
+ char errmsg[1024] = "no error";
+ process_info_t processes[1024];
+ process_info_t *main_proc;
+ task_entry_t* task;
+ int process_count;
+ int result;
+ int status;
+ int i;
+
+ status = 255;
+ main_proc = NULL;
+ process_count = 0;
+
+#ifndef _WIN32
+ /* Clean up stale socket from previous run. */
+ remove(TEST_PIPENAME);
+ remove(TEST_PIPENAME_2);
+ remove(TEST_PIPENAME_3);
+#endif
+
+ /* If it's a helper the user asks for, start it directly. */
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper && strcmp(test, task->process_name) == 0) {
+ return task->main();
+ }
+ }
+
+ /* Start the helpers first. */
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) != 0) {
+ continue;
+ }
+
+ /* Skip the test itself. */
+ if (!task->is_helper) {
+ continue;
+ }
+
+ if (process_start(task->task_name,
+ task->process_name,
+ &processes[process_count],
+ 1 /* is_helper */) == -1) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "Process `%s` failed to start.",
+ task->process_name);
+ goto out;
+ }
+
+ process_count++;
+ }
+
+ /* Give the helpers time to settle. Race-y, fix this. */
+ uv_sleep(250);
+
+ /* Now start the test itself. */
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) != 0) {
+ continue;
+ }
+
+ if (task->is_helper) {
+ continue;
+ }
+
+ if (process_start(task->task_name,
+ task->process_name,
+ &processes[process_count],
+ 0 /* !is_helper */) == -1) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "Process `%s` failed to start.",
+ task->process_name);
+ goto out;
+ }
+
+ main_proc = &processes[process_count];
+ process_count++;
+ break;
+ }
+
+ if (main_proc == NULL) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "No test with that name: %s",
+ test);
+ goto out;
+ }
+
+ result = process_wait(main_proc, 1, task->timeout);
+ if (result == -1) {
+ FATAL("process_wait failed");
+ } else if (result == -2) {
+ /* Don't have to clean up the process, process_wait() has killed it. */
+ snprintf(errmsg,
+ sizeof errmsg,
+ "timeout");
+ goto out;
+ }
+
+ status = process_reap(main_proc);
+ if (status != TEST_OK) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "exit code %d",
+ status);
+ goto out;
+ }
+
+ if (benchmark_output) {
+ /* Give the helpers time to clean up their act. */
+ uv_sleep(1000);
+ }
+
+out:
+ /* Reap running processes except the main process, it's already dead. */
+ for (i = 0; i < process_count - 1; i++) {
+ process_terminate(&processes[i]);
+ }
+
+ if (process_count > 0 &&
+ process_wait(processes, process_count - 1, -1) < 0) {
+ FATAL("process_wait failed");
+ }
+
+ if (tap_output)
+ log_tap_result(test_count, test, status, &processes[i]);
+
+ /* Show error and output from processes if the test failed. */
+ if (status != 0 || task->show_output) {
+ if (tap_output) {
+ fprintf(stderr, "#");
+ } else if (status == TEST_TODO) {
+ fprintf(stderr, "\n`%s` todo\n", test);
+ } else if (status == TEST_SKIP) {
+ fprintf(stderr, "\n`%s` skipped\n", test);
+ } else if (status != 0) {
+ fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
+ } else {
+ fprintf(stderr, "\n");
+ }
+ fflush(stderr);
+
+ for (i = 0; i < process_count; i++) {
+ switch (process_output_size(&processes[i])) {
+ case -1:
+ fprintf(stderr, "Output from process `%s`: (unavailable)\n",
+ process_get_name(&processes[i]));
+ fflush(stderr);
+ break;
+
+ case 0:
+ fprintf(stderr, "Output from process `%s`: (no output)\n",
+ process_get_name(&processes[i]));
+ fflush(stderr);
+ break;
+
+ default:
+ fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
+ fflush(stderr);
+ process_copy_output(&processes[i], fileno(stderr));
+ break;
+ }
+ }
+
+ if (!tap_output) {
+ fprintf(stderr, "=============================================================\n");
+ }
+
+ /* In benchmark mode show concise output from the main process. */
+ } else if (benchmark_output) {
+ switch (process_output_size(main_proc)) {
+ case -1:
+ fprintf(stderr, "%s: (unavailable)\n", test);
+ fflush(stderr);
+ break;
+
+ case 0:
+ fprintf(stderr, "%s: (no output)\n", test);
+ fflush(stderr);
+ break;
+
+ default:
+ for (i = 0; i < process_count; i++) {
+ process_copy_output(&processes[i], fileno(stderr));
+ }
+ break;
+ }
+ }
+
+ /* Clean up all process handles. */
+ for (i = 0; i < process_count; i++) {
+ process_cleanup(&processes[i]);
+ }
+
+ return status;
+}
+
+
+/* Returns the status code of the task part
+ * or 255 if no matching task was not found.
+ */
+int run_test_part(const char* test, const char* part) {
+ task_entry_t* task;
+ int r;
+
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) == 0 &&
+ strcmp(part, task->process_name) == 0) {
+ r = task->main();
+ return r;
+ }
+ }
+
+ fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
+ fflush(stderr);
+ return 255;
+}
+
+
+static int compare_task(const void* va, const void* vb) {
+ const task_entry_t* a = va;
+ const task_entry_t* b = vb;
+ return strcmp(a->task_name, b->task_name);
+}
+
+
+static int find_helpers(const task_entry_t* task,
+ const task_entry_t** helpers) {
+ const task_entry_t* helper;
+ int n_helpers;
+
+ for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
+ if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
+ *helpers++ = helper;
+ n_helpers++;
+ }
+ }
+
+ return n_helpers;
+}
+
+
+void print_tests(FILE* stream) {
+ const task_entry_t* helpers[1024];
+ const task_entry_t* task;
+ int n_helpers;
+ int n_tasks;
+ int i;
+
+ for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
+ qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
+
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper) {
+ continue;
+ }
+
+ n_helpers = find_helpers(task, helpers);
+ if (n_helpers) {
+ printf("%-25s (helpers:", task->task_name);
+ for (i = 0; i < n_helpers; i++) {
+ printf(" %s", helpers[i]->process_name);
+ }
+ printf(")\n");
+ } else {
+ printf("%s\n", task->task_name);
+ }
+ }
+}
diff --git a/3rdparty/libuv/test/runner.h b/3rdparty/libuv/test/runner.h
new file mode 100644
index 00000000000..78f3c880a98
--- /dev/null
+++ b/3rdparty/libuv/test/runner.h
@@ -0,0 +1,178 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef RUNNER_H_
+#define RUNNER_H_
+
+#include <limits.h> /* PATH_MAX */
+#include <stdio.h> /* FILE */
+
+
+/*
+ * The maximum number of processes (main + helpers) that a test / benchmark
+ * can have.
+ */
+#define MAX_PROCESSES 8
+
+
+/*
+ * Struct to store both tests and to define helper processes for tasks.
+ */
+typedef struct {
+ char *task_name;
+ char *process_name;
+ int (*main)(void);
+ int is_helper;
+ int show_output;
+
+ /*
+ * The time in milliseconds after which a single test or benchmark times out.
+ */
+ int timeout;
+} task_entry_t, bench_entry_t;
+
+
+/*
+ * Macros used by test-list.h and benchmark-list.h.
+ */
+#define TASK_LIST_START \
+ task_entry_t TASKS[] = {
+
+#define TASK_LIST_END \
+ { 0, 0, 0, 0, 0, 0 } \
+ };
+
+#define TEST_DECLARE(name) \
+ int run_test_##name(void);
+
+#define TEST_ENTRY(name) \
+ { #name, #name, &run_test_##name, 0, 0, 5000 },
+
+#define TEST_ENTRY_CUSTOM(name, is_helper, show_output, timeout) \
+ { #name, #name, &run_test_##name, is_helper, show_output, timeout },
+
+#define BENCHMARK_DECLARE(name) \
+ int run_benchmark_##name(void);
+
+#define BENCHMARK_ENTRY(name) \
+ { #name, #name, &run_benchmark_##name, 0, 0, 60000 },
+
+#define HELPER_DECLARE(name) \
+ int run_helper_##name(void);
+
+#define HELPER_ENTRY(task_name, name) \
+ { #task_name, #name, &run_helper_##name, 1, 0, 0 },
+
+#define TEST_HELPER HELPER_ENTRY
+#define BENCHMARK_HELPER HELPER_ENTRY
+
+#ifdef PATH_MAX
+extern char executable_path[PATH_MAX];
+#else
+extern char executable_path[4096];
+#endif
+
+/*
+ * Include platform-dependent definitions
+ */
+#ifdef _WIN32
+# include "runner-win.h"
+#else
+# include "runner-unix.h"
+#endif
+
+
+/* The array that is filled by test-list.h or benchmark-list.h */
+extern task_entry_t TASKS[];
+
+/*
+ * Run all tests.
+ */
+int run_tests(int benchmark_output);
+
+/*
+ * Run a single test. Starts up any helpers.
+ */
+int run_test(const char* test,
+ int benchmark_output,
+ int test_count);
+
+/*
+ * Run a test part, i.e. the test or one of its helpers.
+ */
+int run_test_part(const char* test, const char* part);
+
+
+/*
+ * Print tests in sorted order to `stream`. Used by `./run-tests --list`.
+ */
+void print_tests(FILE* stream);
+
+
+/*
+ * Stuff that should be implemented by test-runner-<platform>.h
+ * All functions return 0 on success, -1 on failure, unless specified
+ * otherwise.
+ */
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char** argv);
+
+/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
+/* Make sure that all stdio output of the processes is buffered up. */
+int process_start(char *name, char* part, process_info_t *p, int is_helper);
+
+/* Wait for all `n` processes in `vec` to terminate. */
+/* Time out after `timeout` msec, or never if timeout == -1 */
+/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
+int process_wait(process_info_t *vec, int n, int timeout);
+
+/* Returns the number of bytes in the stdio output buffer for process `p`. */
+long int process_output_size(process_info_t *p);
+
+/* Copy the contents of the stdio output buffer to `fd`. */
+int process_copy_output(process_info_t *p, int fd);
+
+/* Copy the last line of the stdio output buffer to `buffer` */
+int process_read_last_line(process_info_t *p,
+ char * buffer,
+ size_t buffer_len);
+
+/* Return the name that was specified when `p` was started by process_start */
+char* process_get_name(process_info_t *p);
+
+/* Terminate process `p`. */
+int process_terminate(process_info_t *p);
+
+/* Return the exit code of process p. */
+/* On error, return -1. */
+int process_reap(process_info_t *p);
+
+/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
+void process_cleanup(process_info_t *p);
+
+/* Move the console cursor one line up and back to the first column. */
+void rewind_cursor(void);
+
+/* trigger output as tap */
+extern int tap_output;
+
+#endif /* RUNNER_H_ */
diff --git a/3rdparty/libuv/test/task.h b/3rdparty/libuv/test/task.h
new file mode 100644
index 00000000000..d18c1daa364
--- /dev/null
+++ b/3rdparty/libuv/test/task.h
@@ -0,0 +1,220 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TASK_H_
+#define TASK_H_
+
+#include "uv.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#if !defined(_WIN32)
+# include <sys/time.h>
+# include <sys/resource.h> /* setrlimit() */
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic ignored "-Wvariadic-macros"
+# pragma clang diagnostic ignored "-Wc99-extensions"
+#endif
+
+#define TEST_PORT 9123
+#define TEST_PORT_2 9124
+
+#ifdef _WIN32
+# define TEST_PIPENAME "\\\\?\\pipe\\uv-test"
+# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2"
+# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3"
+#else
+# define TEST_PIPENAME "/tmp/uv-test-sock"
+# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
+# define TEST_PIPENAME_3 "/tmp/uv-test-sock3"
+#endif
+
+#ifdef _WIN32
+# include <io.h>
+# ifndef S_IRUSR
+# define S_IRUSR _S_IREAD
+# endif
+# ifndef S_IWUSR
+# define S_IWUSR _S_IWRITE
+# endif
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+typedef enum {
+ TCP = 0,
+ UDP,
+ PIPE
+} stream_type;
+
+/* Die with fatal error. */
+#define FATAL(msg) \
+ do { \
+ fprintf(stderr, \
+ "Fatal error in %s on line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ msg); \
+ fflush(stderr); \
+ abort(); \
+ } while (0)
+
+/* Have our own assert, so we are sure it does not get optimized away in
+ * a release build.
+ */
+#define ASSERT(expr) \
+ do { \
+ if (!(expr)) { \
+ fprintf(stderr, \
+ "Assertion failed in %s on line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ abort(); \
+ } \
+ } while (0)
+
+/* This macro cleans up the main loop. This is used to avoid valgrind
+ * warnings about memory being "leaked" by the main event loop.
+ */
+#define MAKE_VALGRIND_HAPPY() \
+ do { \
+ close_loop(uv_default_loop()); \
+ uv_loop_delete(uv_default_loop()); \
+ } while (0)
+
+/* Just sugar for wrapping the main() for a task or helper. */
+#define TEST_IMPL(name) \
+ int run_test_##name(void); \
+ int run_test_##name(void)
+
+#define BENCHMARK_IMPL(name) \
+ int run_benchmark_##name(void); \
+ int run_benchmark_##name(void)
+
+#define HELPER_IMPL(name) \
+ int run_helper_##name(void); \
+ int run_helper_##name(void)
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec);
+
+/* Format big numbers nicely. WARNING: leaks memory. */
+const char* fmt(double d);
+
+/* Reserved test exit codes. */
+enum test_status {
+ TEST_OK = 0,
+ TEST_TODO,
+ TEST_SKIP
+};
+
+#define RETURN_OK() \
+ do { \
+ return TEST_OK; \
+ } while (0)
+
+#define RETURN_TODO(explanation) \
+ do { \
+ fprintf(stderr, "%s\n", explanation); \
+ fflush(stderr); \
+ return TEST_TODO; \
+ } while (0)
+
+#define RETURN_SKIP(explanation) \
+ do { \
+ fprintf(stderr, "%s\n", explanation); \
+ fflush(stderr); \
+ return TEST_SKIP; \
+ } while (0)
+
+#if !defined(_WIN32)
+
+# define TEST_FILE_LIMIT(num) \
+ do { \
+ struct rlimit lim; \
+ lim.rlim_cur = (num); \
+ lim.rlim_max = lim.rlim_cur; \
+ if (setrlimit(RLIMIT_NOFILE, &lim)) \
+ RETURN_SKIP("File descriptor limit too low."); \
+ } while (0)
+
+#else /* defined(_WIN32) */
+
+# define TEST_FILE_LIMIT(num) do {} while (0)
+
+#endif
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+#if defined(__clang__) || \
+ defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || \
+ defined(__SUNPRO_C)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+/* Fully close a loop */
+static void close_walk_cb(uv_handle_t* handle, void* arg) {
+ if (!uv_is_closing(handle))
+ uv_close(handle, NULL);
+}
+
+UNUSED static void close_loop(uv_loop_t* loop) {
+ uv_walk(loop, close_walk_cb, NULL);
+ uv_run(loop, UV_RUN_DEFAULT);
+}
+
+UNUSED static int can_ipv6(void) {
+ uv_interface_address_t* addr;
+ int supported;
+ int count;
+ int i;
+
+ if (uv_interface_addresses(&addr, &count))
+ return 1; /* Assume IPv6 support on failure. */
+
+ supported = 0;
+ for (i = 0; supported == 0 && i < count; i += 1)
+ supported = (AF_INET6 == addr[i].address.address6.sin6_family);
+
+ uv_free_interface_addresses(addr, count);
+ return supported;
+}
+
+#endif /* TASK_H_ */
diff --git a/3rdparty/libuv/test/test-active.c b/3rdparty/libuv/test/test-active.c
new file mode 100644
index 00000000000..b17bd176018
--- /dev/null
+++ b/3rdparty/libuv/test/test-active.c
@@ -0,0 +1,84 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(0 && "timer_cb should not have been called");
+}
+
+
+TEST_IMPL(active) {
+ int r;
+ uv_timer_t timer;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ /* uv_is_active() and uv_is_closing() should always return either 0 or 1. */
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_start(&timer, timer_cb, 1000, 0);
+ ASSERT(r == 0);
+
+ ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_stop(&timer);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_start(&timer, timer_cb, 1000, 0);
+ ASSERT(r == 0);
+
+ ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ uv_close((uv_handle_t*) &timer, close_cb);
+
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(1 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-async-null-cb.c b/3rdparty/libuv/test/test-async-null-cb.c
new file mode 100644
index 00000000000..757944a2762
--- /dev/null
+++ b/3rdparty/libuv/test/test-async-null-cb.c
@@ -0,0 +1,55 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_async_t async_handle;
+static uv_check_t check_handle;
+static int check_cb_called;
+static uv_thread_t thread;
+
+
+static void thread_cb(void* dummy) {
+ (void) &dummy;
+ uv_async_send(&async_handle);
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(check_cb_called == 0);
+ uv_close((uv_handle_t*) &async_handle, NULL);
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ check_cb_called++;
+}
+
+
+TEST_IMPL(async_null_cb) {
+ ASSERT(0 == uv_async_init(uv_default_loop(), &async_handle, NULL));
+ ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_thread_create(&thread, thread_cb, NULL));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_thread_join(&thread));
+ ASSERT(1 == check_cb_called);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-async.c b/3rdparty/libuv/test/test-async.c
new file mode 100644
index 00000000000..6f5351bf158
--- /dev/null
+++ b/3rdparty/libuv/test/test-async.c
@@ -0,0 +1,134 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_thread_t thread;
+static uv_mutex_t mutex;
+
+static uv_prepare_t prepare;
+static uv_async_t async;
+
+static volatile int async_cb_called;
+static int prepare_cb_called;
+static int close_cb_called;
+
+
+static void thread_cb(void *arg) {
+ int n;
+ int r;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+ n = async_cb_called;
+ uv_mutex_unlock(&mutex);
+
+ if (n == 3) {
+ break;
+ }
+
+ r = uv_async_send(&async);
+ ASSERT(r == 0);
+
+ /* Work around a bug in Valgrind.
+ *
+ * Valgrind runs threads not in parallel but sequentially, i.e. one after
+ * the other. It also doesn't preempt them, instead it depends on threads
+ * yielding voluntarily by making a syscall.
+ *
+ * That never happens here: the pipe that is associated with the async
+ * handle is written to once but that's too early for Valgrind's scheduler
+ * to kick in. Afterwards, the thread busy-loops, starving the main thread.
+ * Therefore, we yield.
+ *
+ * This behavior has been observed with Valgrind 3.7.0 and 3.9.0.
+ */
+ uv_sleep(0);
+ }
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void async_cb(uv_async_t* handle) {
+ int n;
+
+ ASSERT(handle == &async);
+
+ uv_mutex_lock(&mutex);
+ n = ++async_cb_called;
+ uv_mutex_unlock(&mutex);
+
+ if (n == 3) {
+ uv_close((uv_handle_t*)&async, close_cb);
+ uv_close((uv_handle_t*)&prepare, close_cb);
+ }
+}
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ int r;
+
+ ASSERT(handle == &prepare);
+
+ if (prepare_cb_called++)
+ return;
+
+ r = uv_thread_create(&thread, thread_cb, NULL);
+ ASSERT(r == 0);
+ uv_mutex_unlock(&mutex);
+}
+
+
+TEST_IMPL(async) {
+ int r;
+
+ r = uv_mutex_init(&mutex);
+ ASSERT(r == 0);
+ uv_mutex_lock(&mutex);
+
+ r = uv_prepare_init(uv_default_loop(), &prepare);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare, prepare_cb);
+ ASSERT(r == 0);
+
+ r = uv_async_init(uv_default_loop(), &async, async_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(prepare_cb_called > 0);
+ ASSERT(async_cb_called == 3);
+ ASSERT(close_cb_called == 2);
+
+ ASSERT(0 == uv_thread_join(&thread));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-barrier.c b/3rdparty/libuv/test/test-barrier.c
new file mode 100644
index 00000000000..dfd2dbdef1b
--- /dev/null
+++ b/3rdparty/libuv/test/test-barrier.c
@@ -0,0 +1,106 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ uv_barrier_t barrier;
+ int delay;
+ volatile int posted;
+ int main_barrier_wait_rval;
+ int worker_barrier_wait_rval;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier);
+}
+
+
+TEST_IMPL(barrier_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sleep(100);
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
+
+
+TEST_IMPL(barrier_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
+
+
+TEST_IMPL(barrier_3) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-callback-order.c b/3rdparty/libuv/test/test-callback-order.c
new file mode 100644
index 00000000000..8bc2c4f75de
--- /dev/null
+++ b/3rdparty/libuv/test/test-callback-order.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int idle_cb_called;
+static int timer_cb_called;
+
+static uv_idle_t idle_handle;
+static uv_timer_t timer_handle;
+
+
+/* idle_cb should run before timer_cb */
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(idle_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+ uv_idle_stop(handle);
+ idle_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(idle_cb_called == 1);
+ ASSERT(timer_cb_called == 0);
+ uv_timer_stop(handle);
+ timer_cb_called++;
+}
+
+
+static void next_tick(uv_idle_t* handle) {
+ uv_loop_t* loop = handle->loop;
+ uv_idle_stop(handle);
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+ uv_timer_init(loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 0, 0);
+}
+
+
+TEST_IMPL(callback_order) {
+ uv_loop_t* loop;
+ uv_idle_t idle;
+
+ loop = uv_default_loop();
+ uv_idle_init(loop, &idle);
+ uv_idle_start(&idle, next_tick);
+
+ ASSERT(idle_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(idle_cb_called == 1);
+ ASSERT(timer_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-callback-stack.c b/3rdparty/libuv/test/test-callback-stack.c
new file mode 100644
index 00000000000..8855c0841b3
--- /dev/null
+++ b/3rdparty/libuv/test/test-callback-stack.c
@@ -0,0 +1,205 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * TODO: Add explanation of why we want on_close to be called from fresh
+ * stack.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static const char MESSAGE[] = "Failure is for the weak. Everyone dies alone.";
+
+static uv_tcp_t client;
+static uv_timer_t timer;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+
+static int nested = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int timer_cb_called = 0;
+static int bytes_received = 0;
+static int shutdown_cb_called = 0;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->len = size;
+ buf->base = malloc(size);
+ ASSERT(buf->base != NULL);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(nested == 0 && "close_cb must be called from a fresh stack");
+
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "shutdown_cb must be called from a fresh stack");
+
+ shutdown_cb_called++;
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nested == 0 && "read_cb must be called from a fresh stack");
+
+ printf("Read. nread == %d\n", (int)nread);
+ free(buf->base);
+
+ if (nread == 0) {
+ return;
+
+ } else if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ nested++;
+ uv_close((uv_handle_t*)tcp, close_cb);
+ nested--;
+
+ return;
+ }
+
+ bytes_received += nread;
+
+ /* We call shutdown here because when bytes_received == sizeof MESSAGE */
+ /* there will be no more data sent nor received, so here it would be */
+ /* possible for a backend to to call shutdown_cb immediately and *not* */
+ /* from a fresh stack. */
+ if (bytes_received == sizeof MESSAGE) {
+ nested++;
+
+ puts("Shutdown");
+
+ if (uv_shutdown(&shutdown_req, (uv_stream_t*)tcp, shutdown_cb)) {
+ FATAL("uv_shutdown failed");
+ }
+ nested--;
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ ASSERT(nested == 0 && "timer_cb must be called from a fresh stack");
+
+ puts("Timeout complete. Now read data...");
+
+ nested++;
+ if (uv_read_start((uv_stream_t*)&client, alloc_cb, read_cb)) {
+ FATAL("uv_read_start failed");
+ }
+ nested--;
+
+ timer_cb_called++;
+
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "write_cb must be called from a fresh stack");
+
+ puts("Data written. 500ms timeout...");
+
+ /* After the data has been sent, we're going to wait for a while, then */
+ /* start reading. This makes us certain that the message has been echoed */
+ /* back to our receive buffer when we start reading. This maximizes the */
+ /* temptation for the backend to use dirty stack for calling read_cb. */
+ nested++;
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+ nested--;
+
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf;
+
+ puts("Connected. Write some data to echo server...");
+
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "connect_cb must be called from a fresh stack");
+
+ nested++;
+
+ buf.base = (char*) &MESSAGE;
+ buf.len = sizeof MESSAGE;
+
+ if (uv_write(&write_req, (uv_stream_t*)req->handle, &buf, 1, write_cb)) {
+ FATAL("uv_write failed");
+ }
+
+ nested--;
+
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(callback_stack) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ if (uv_tcp_init(uv_default_loop(), &client)) {
+ FATAL("uv_tcp_init failed");
+ }
+
+ puts("Connecting...");
+
+ nested++;
+
+ if (uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb)) {
+ FATAL("uv_tcp_connect failed");
+ }
+ nested--;
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(nested == 0);
+ ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once");
+ ASSERT(write_cb_called == 1 && "write_cb must be called exactly once");
+ ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once");
+ ASSERT(bytes_received == sizeof MESSAGE);
+ ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once");
+ ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-close-fd.c b/3rdparty/libuv/test/test-close-fd.c
new file mode 100644
index 00000000000..93a7bd7c021
--- /dev/null
+++ b/3rdparty/libuv/test/test-close-fd.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+static unsigned int read_cb_called;
+
+static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
+ static char slab[1];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
+ switch (++read_cb_called) {
+ case 1:
+ ASSERT(nread == 1);
+ uv_read_stop(handle);
+ break;
+ case 2:
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t *) handle, NULL);
+ break;
+ default:
+ ASSERT(!"read_cb_called > 2");
+ }
+}
+
+TEST_IMPL(close_fd) {
+ uv_pipe_t pipe_handle;
+ int fd[2];
+
+ ASSERT(0 == pipe(fd));
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
+ ASSERT(1 == write(fd[1], "", 1));
+ ASSERT(0 == close(fd[1]));
+ fd[1] = -1;
+ ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == read_cb_called);
+ ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(2 == read_cb_called);
+ ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !defined(_WIN32) */
diff --git a/3rdparty/libuv/test/test-close-order.c b/3rdparty/libuv/test/test-close-order.c
new file mode 100644
index 00000000000..2b24f6d6579
--- /dev/null
+++ b/3rdparty/libuv/test/test-close-order.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int check_cb_called;
+static int timer_cb_called;
+static int close_cb_called;
+
+static uv_check_t check_handle;
+static uv_timer_t timer_handle1;
+static uv_timer_t timer_handle2;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+/* check_cb should run before any close_cb */
+static void check_cb(uv_check_t* handle) {
+ ASSERT(check_cb_called == 0);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 0);
+ uv_close((uv_handle_t*) handle, close_cb);
+ uv_close((uv_handle_t*) &timer_handle2, close_cb);
+ check_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) handle, close_cb);
+ timer_cb_called++;
+}
+
+
+TEST_IMPL(close_order) {
+ uv_loop_t* loop;
+ loop = uv_default_loop();
+
+ uv_check_init(loop, &check_handle);
+ uv_check_start(&check_handle, check_cb);
+ uv_timer_init(loop, &timer_handle1);
+ uv_timer_start(&timer_handle1, timer_cb, 0, 0);
+ uv_timer_init(loop, &timer_handle2);
+ uv_timer_start(&timer_handle2, timer_cb, 100000, 0);
+
+ ASSERT(check_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(check_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(timer_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-condvar.c b/3rdparty/libuv/test/test-condvar.c
new file mode 100644
index 00000000000..dbacdba384d
--- /dev/null
+++ b/3rdparty/libuv/test/test-condvar.c
@@ -0,0 +1,173 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ uv_mutex_t mutex;
+ uv_cond_t cond;
+ int delay;
+ int use_broadcast;
+ volatile int posted;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ uv_mutex_lock(&c->mutex);
+ ASSERT(c->posted == 0);
+ c->posted = 1;
+ if (c->use_broadcast)
+ uv_cond_broadcast(&c->cond);
+ else
+ uv_cond_signal(&c->cond);
+ uv_mutex_unlock(&c->mutex);
+}
+
+
+TEST_IMPL(condvar_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_sleep(100);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_3) {
+ uv_thread_t thread;
+ worker_config wc;
+ int r;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6));
+ ASSERT(r == UV_ETIMEDOUT);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_4) {
+ uv_thread_t thread;
+ worker_config wc;
+ int r;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6));
+ ASSERT(r == 0);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_5) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.use_broadcast = 1;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_sleep(100);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-connection-fail.c b/3rdparty/libuv/test/test-connection-fail.c
new file mode 100644
index 00000000000..328bff46e7d
--- /dev/null
+++ b/3rdparty/libuv/test/test-connection-fail.c
@@ -0,0 +1,151 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static uv_tcp_t tcp;
+static uv_connect_t req;
+static int connect_cb_calls;
+static int close_cb_calls;
+
+static uv_timer_t timer;
+static int timer_close_cb_calls;
+static int timer_cb_calls;
+
+
+static void on_close(uv_handle_t* handle) {
+ close_cb_calls++;
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ timer_close_cb_calls++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ timer_cb_calls++;
+
+ /*
+ * These are the important asserts. The connection callback has been made,
+ * but libuv hasn't automatically closed the socket. The user must
+ * uv_close the handle manually.
+ */
+ ASSERT(close_cb_calls == 0);
+ ASSERT(connect_cb_calls == 1);
+
+ /* Close the tcp handle. */
+ uv_close((uv_handle_t*)&tcp, on_close);
+
+ /* Close the timer. */
+ uv_close((uv_handle_t*)handle, timer_close_cb);
+}
+
+
+static void on_connect_with_close(uv_connect_t *req, int status) {
+ ASSERT((uv_stream_t*) &tcp == req->handle);
+ ASSERT(status == UV_ECONNREFUSED);
+ connect_cb_calls++;
+
+ ASSERT(close_cb_calls == 0);
+ uv_close((uv_handle_t*)req->handle, on_close);
+}
+
+
+static void on_connect_without_close(uv_connect_t *req, int status) {
+ ASSERT(status == UV_ECONNREFUSED);
+ connect_cb_calls++;
+
+ uv_timer_start(&timer, timer_cb, 100, 0);
+
+ ASSERT(close_cb_calls == 0);
+}
+
+
+static void connection_fail(uv_connect_cb connect_cb) {
+ struct sockaddr_in client_addr, server_addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
+
+ /* There should be no servers listening on this port. */
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &tcp);
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0));
+
+ r = uv_tcp_connect(&req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ connect_cb);
+ ASSERT(!r);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_calls == 1);
+ ASSERT(close_cb_calls == 1);
+}
+
+
+/*
+ * This test attempts to connect to a port where no server is running. We
+ * expect an error.
+ */
+TEST_IMPL(connection_fail) {
+ connection_fail(on_connect_with_close);
+
+ ASSERT(timer_close_cb_calls == 0);
+ ASSERT(timer_cb_calls == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+/*
+ * This test is the same as the first except it check that the close
+ * callback of the tcp handle hasn't been made after the failed connection
+ * attempt.
+ */
+TEST_IMPL(connection_fail_doesnt_auto_close) {
+ int r;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ connection_fail(on_connect_without_close);
+
+ ASSERT(timer_close_cb_calls == 1);
+ ASSERT(timer_cb_calls == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-cwd-and-chdir.c b/3rdparty/libuv/test/test-cwd-and-chdir.c
new file mode 100644
index 00000000000..1e95043c177
--- /dev/null
+++ b/3rdparty/libuv/test/test-cwd-and-chdir.c
@@ -0,0 +1,51 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+extern char executable_path[];
+
+TEST_IMPL(cwd_and_chdir) {
+ char buffer_orig[PATHMAX];
+ char buffer_new[PATHMAX];
+ size_t size1;
+ size_t size2;
+ int err;
+
+ size1 = sizeof buffer_orig;
+ err = uv_cwd(buffer_orig, &size1);
+ ASSERT(err == 0);
+
+ err = uv_chdir(buffer_orig);
+ ASSERT(err == 0);
+
+ size2 = sizeof buffer_new;
+ err = uv_cwd(buffer_new, &size2);
+ ASSERT(err == 0);
+
+ ASSERT(size1 == size2);
+ ASSERT(strcmp(buffer_orig, buffer_new) == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-default-loop-close.c b/3rdparty/libuv/test/test-default-loop-close.c
new file mode 100644
index 00000000000..fd11cfa8c12
--- /dev/null
+++ b/3rdparty/libuv/test/test-default-loop-close.c
@@ -0,0 +1,59 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int timer_cb_called;
+
+
+static void timer_cb(uv_timer_t* timer) {
+ timer_cb_called++;
+ uv_close((uv_handle_t*) timer, NULL);
+}
+
+
+TEST_IMPL(default_loop_close) {
+ uv_loop_t* loop;
+ uv_timer_t timer_handle;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+ ASSERT(0 == uv_loop_close(loop));
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(2 == timer_cb_called);
+ ASSERT(0 == uv_loop_close(loop));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-delayed-accept.c b/3rdparty/libuv/test/test-delayed-accept.c
new file mode 100644
index 00000000000..4a7998909c3
--- /dev/null
+++ b/3rdparty/libuv/test/test-delayed-accept.c
@@ -0,0 +1,189 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int connection_cb_called = 0;
+static int do_accept_called = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+
+ free(handle);
+
+ close_cb_called++;
+}
+
+
+static void do_accept(uv_timer_t* timer_handle) {
+ uv_tcp_t* server;
+ uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle);
+ int r;
+
+ ASSERT(timer_handle != NULL);
+ ASSERT(accepted_handle != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), accepted_handle);
+ ASSERT(r == 0);
+
+ server = (uv_tcp_t*)timer_handle->data;
+ r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle);
+ ASSERT(r == 0);
+
+ do_accept_called++;
+
+ /* Immediately close the accepted handle. */
+ uv_close((uv_handle_t*)accepted_handle, close_cb);
+
+ /* After accepting the two clients close the server handle */
+ if (do_accept_called == 2) {
+ uv_close((uv_handle_t*)server, close_cb);
+ }
+
+ /* Dispose the timer. */
+ uv_close((uv_handle_t*)timer_handle, close_cb);
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ int r;
+ uv_timer_t* timer_handle;
+
+ ASSERT(status == 0);
+
+ timer_handle = (uv_timer_t*)malloc(sizeof *timer_handle);
+ ASSERT(timer_handle != NULL);
+
+ /* Accept the client after 1 second */
+ r = uv_timer_init(uv_default_loop(), timer_handle);
+ ASSERT(r == 0);
+
+ timer_handle->data = tcp;
+
+ r = uv_timer_start(timer_handle, do_accept, 1000, 0);
+ ASSERT(r == 0);
+
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+ uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ ASSERT(server != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)server, 128, connection_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ /* The server will not send anything, it should close gracefully. */
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ if (nread >= 0) {
+ ASSERT(nread == 0);
+ } else {
+ ASSERT(tcp != NULL);
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ /* Not that the server will send anything, but otherwise we'll never know */
+ /* when the server closes the connection. */
+ r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ connect_cb_called++;
+
+ free(req);
+}
+
+
+static void client_connect(void) {
+ struct sockaddr_in addr;
+ uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof *client);
+ uv_connect_t* connect_req = malloc(sizeof *connect_req);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(client != NULL);
+ ASSERT(connect_req != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(connect_req,
+ client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+}
+
+
+
+TEST_IMPL(delayed_accept) {
+ start_server();
+
+ client_connect();
+ client_connect();
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == 2);
+ ASSERT(do_accept_called == 2);
+ ASSERT(connect_cb_called == 2);
+ ASSERT(close_cb_called == 7);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-dlerror.c b/3rdparty/libuv/test/test-dlerror.c
new file mode 100644
index 00000000000..091200edbed
--- /dev/null
+++ b/3rdparty/libuv/test/test-dlerror.c
@@ -0,0 +1,55 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+TEST_IMPL(dlerror) {
+ const char* path = "test/fixtures/load_error.node";
+ const char* dlerror_no_error = "no error";
+ const char* msg;
+ uv_lib_t lib;
+ int r;
+
+ lib.errmsg = NULL;
+ lib.handle = NULL;
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) != NULL);
+
+ r = uv_dlopen(path, &lib);
+ ASSERT(r == -1);
+
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) == NULL);
+
+ /* Should return the same error twice in a row. */
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) == NULL);
+
+ uv_dlclose(&lib);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-embed.c b/3rdparty/libuv/test/test-embed.c
new file mode 100644
index 00000000000..06137456f8b
--- /dev/null
+++ b/3rdparty/libuv/test/test-embed.c
@@ -0,0 +1,138 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifndef HAVE_KQUEUE
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
+#ifndef HAVE_EPOLL
+# if defined(__linux__)
+# define HAVE_EPOLL 1
+# endif
+#endif
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+
+#if defined(HAVE_KQUEUE)
+# include <sys/types.h>
+# include <sys/event.h>
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_EPOLL)
+# include <sys/epoll.h>
+#endif
+
+static uv_thread_t embed_thread;
+static uv_sem_t embed_sem;
+static uv_timer_t embed_timer;
+static uv_async_t embed_async;
+static volatile int embed_closed;
+
+static int embed_timer_called;
+
+
+static void embed_thread_runner(void* arg) {
+ int r;
+ int fd;
+ int timeout;
+
+ while (!embed_closed) {
+ fd = uv_backend_fd(uv_default_loop());
+ timeout = uv_backend_timeout(uv_default_loop());
+
+ do {
+#if defined(HAVE_KQUEUE)
+ struct timespec ts;
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ r = kevent(fd, NULL, 0, NULL, 0, &ts);
+#elif defined(HAVE_EPOLL)
+ {
+ struct epoll_event ev;
+ r = epoll_wait(fd, &ev, 1, timeout);
+ }
+#endif
+ } while (r == -1 && errno == EINTR);
+ uv_async_send(&embed_async);
+ uv_sem_wait(&embed_sem);
+ }
+}
+
+
+static void embed_cb(uv_async_t* async) {
+ uv_run(uv_default_loop(), UV_RUN_ONCE);
+
+ uv_sem_post(&embed_sem);
+}
+
+
+static void embed_timer_cb(uv_timer_t* timer) {
+ embed_timer_called++;
+ embed_closed = 1;
+
+ uv_close((uv_handle_t*) &embed_async, NULL);
+}
+#endif
+
+
+TEST_IMPL(embed) {
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+ uv_loop_t external;
+
+ ASSERT(0 == uv_loop_init(&external));
+
+ embed_timer_called = 0;
+ embed_closed = 0;
+
+ uv_async_init(&external, &embed_async, embed_cb);
+
+ /* Start timer in default loop */
+ uv_timer_init(uv_default_loop(), &embed_timer);
+ uv_timer_start(&embed_timer, embed_timer_cb, 250, 0);
+
+ /* Start worker that will interrupt external loop */
+ uv_sem_init(&embed_sem, 0);
+ uv_thread_create(&embed_thread, embed_thread_runner, NULL);
+
+ /* But run external loop */
+ uv_run(&external, UV_RUN_DEFAULT);
+
+ uv_thread_join(&embed_thread);
+ uv_loop_close(&external);
+
+ ASSERT(embed_timer_called == 1);
+#endif
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-emfile.c b/3rdparty/libuv/test/test-emfile.c
new file mode 100644
index 00000000000..dd35f785b46
--- /dev/null
+++ b/3rdparty/libuv/test/test-emfile.c
@@ -0,0 +1,110 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static void connection_cb(uv_stream_t* server_handle, int status);
+static void connect_cb(uv_connect_t* req, int status);
+
+static const int maxfd = 31;
+static unsigned connect_cb_called;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+
+
+TEST_IMPL(emfile) {
+ struct sockaddr_in addr;
+ struct rlimit limits;
+ uv_connect_t connect_req;
+ uv_loop_t* loop;
+ int first_fd;
+
+ /* Lower the file descriptor limit and use up all fds save one. */
+ limits.rlim_cur = limits.rlim_max = maxfd + 1;
+ if (setrlimit(RLIMIT_NOFILE, &limits)) {
+ ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */
+ RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?");
+ }
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
+
+ /* Remember the first one so we can clean up afterwards. */
+ do
+ first_fd = dup(0);
+ while (first_fd == -1 && errno == EINTR);
+ ASSERT(first_fd > 0);
+
+ while (dup(0) != -1 || errno == EINTR);
+ ASSERT(errno == EMFILE);
+ close(maxfd);
+
+ /* Now connect and use up the last available file descriptor. The EMFILE
+ * handling logic in src/unix/stream.c should ensure that connect_cb() runs
+ * whereas connection_cb() should *not* run.
+ */
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == connect_cb_called);
+
+ /* Close the dups again. Ignore errors in the unlikely event that the
+ * file descriptors were not contiguous.
+ */
+ while (first_fd < maxfd) {
+ close(first_fd);
+ first_fd += 1;
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void connection_cb(uv_stream_t* server_handle, int status) {
+ ASSERT(0 && "connection_cb should not be called.");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ /* |status| should equal 0 because the connection should have been accepted,
+ * it's just that the server immediately closes it again.
+ */
+ ASSERT(0 == status);
+ connect_cb_called += 1;
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+}
+
+#endif /* !defined(_WIN32) */
diff --git a/3rdparty/libuv/test/test-error.c b/3rdparty/libuv/test/test-error.c
new file mode 100644
index 00000000000..eb337e66f33
--- /dev/null
+++ b/3rdparty/libuv/test/test-error.c
@@ -0,0 +1,50 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Synthetic errors (errors that originate from within libuv, not the system)
+ * should produce sensible error messages when run through uv_strerror().
+ *
+ * See https://github.com/joyent/libuv/issues/210
+ */
+TEST_IMPL(error_message) {
+ /* Cop out. Can't do proper checks on systems with
+ * i18n-ized error messages...
+ */
+ if (strcmp(uv_strerror(0), "Success") != 0) {
+ printf("i18n error messages detected, skipping test.\n");
+ return 0;
+ }
+
+ ASSERT(strstr(uv_strerror(UV_EINVAL), "Success") == NULL);
+ ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0);
+ ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-fail-always.c b/3rdparty/libuv/test/test-fail-always.c
new file mode 100644
index 00000000000..0008459eac7
--- /dev/null
+++ b/3rdparty/libuv/test/test-fail-always.c
@@ -0,0 +1,29 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+
+
+TEST_IMPL(fail_always) {
+ /* This test always fails. It is used to test the test runner. */
+ FATAL("Yes, it always fails");
+ return 2;
+}
diff --git a/3rdparty/libuv/test/test-fs-event.c b/3rdparty/libuv/test/test-fs-event.c
new file mode 100644
index 00000000000..e02ff2fda5e
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs-event.c
@@ -0,0 +1,907 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <fcntl.h>
+
+#ifndef HAVE_KQUEUE
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
+static uv_fs_event_t fs_event;
+static const char file_prefix[] = "fsevent-";
+static const int fs_event_file_count = 16;
+#if defined(__APPLE__) || defined(_WIN32)
+static const char file_prefix_in_subdir[] = "subdir";
+#endif
+static uv_timer_t timer;
+static int timer_cb_called;
+static int close_cb_called;
+static int fs_event_created;
+static int fs_event_removed;
+static int fs_event_cb_called;
+#if defined(PATH_MAX)
+static char fs_event_filename[PATH_MAX];
+#else
+static char fs_event_filename[1024];
+#endif /* defined(PATH_MAX) */
+static int timer_cb_touch_called;
+
+static void create_dir(const char* name) {
+ int r;
+ uv_fs_t req;
+ r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
+ ASSERT(r == 0 || r == UV_EEXIST);
+ uv_fs_req_cleanup(&req);
+}
+
+static void create_file(const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+
+ r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ file = r;
+ uv_fs_req_cleanup(&req);
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void touch_file(const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+ uv_buf_t buf;
+
+ r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ file = r;
+ uv_fs_req_cleanup(&req);
+
+ buf = uv_buf_init("foo", 4);
+ r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+static void fail_cb(uv_fs_event_t* handle,
+ const char* path,
+ int events,
+ int status) {
+ ASSERT(0 && "fail_cb called");
+}
+
+static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file1") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
+ #endif
+ ASSERT(0 == uv_fs_event_stop(handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static const char* fs_event_get_filename(int i) {
+ snprintf(fs_event_filename,
+ sizeof(fs_event_filename),
+ "watch_dir/%s%d",
+ file_prefix,
+ i);
+ return fs_event_filename;
+}
+
+static void fs_event_create_files(uv_timer_t* handle) {
+ /* Make sure we're not attempting to create files we do not intend */
+ ASSERT(fs_event_created < fs_event_file_count);
+
+ /* Create the file */
+ create_file(fs_event_get_filename(fs_event_created));
+
+ if (++fs_event_created < fs_event_file_count) {
+ /* Create another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
+ }
+}
+
+static void fs_event_unlink_files(uv_timer_t* handle) {
+ int r;
+ int i;
+
+ /* NOTE: handle might be NULL if invoked not as timer callback */
+ if (handle == NULL) {
+ /* Unlink all files */
+ for (i = 0; i < 16; i++) {
+ r = remove(fs_event_get_filename(i));
+ if (handle != NULL)
+ ASSERT(r == 0);
+ }
+ } else {
+ /* Make sure we're not attempting to remove files we do not intend */
+ ASSERT(fs_event_removed < fs_event_file_count);
+
+ /* Remove the file */
+ ASSERT(0 == remove(fs_event_get_filename(fs_event_removed)));
+
+ if (++fs_event_removed < fs_event_file_count) {
+ /* Remove another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+ }
+ }
+}
+
+static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ fs_event_cb_called++;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #else
+ ASSERT(filename == NULL ||
+ strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #endif
+
+ if (fs_event_created + fs_event_removed == fs_event_file_count) {
+ /* Once we've processed all create events, delete all files */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+ } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+ /* Once we've processed all create and delete events, stop watching */
+ uv_close((uv_handle_t*) &timer, close_cb);
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+
+#if defined(__APPLE__) || defined(_WIN32)
+static const char* fs_event_get_filename_in_subdir(int i) {
+ snprintf(fs_event_filename,
+ sizeof(fs_event_filename),
+ "watch_dir/subdir/%s%d",
+ file_prefix,
+ i);
+ return fs_event_filename;
+}
+
+static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
+ /* Make sure we're not attempting to create files we do not intend */
+ ASSERT(fs_event_created < fs_event_file_count);
+
+ /* Create the file */
+ create_file(fs_event_get_filename_in_subdir(fs_event_created));
+
+ if (++fs_event_created < fs_event_file_count) {
+ /* Create another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_create_files_in_subdir, 1, 0));
+ }
+}
+
+static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
+ int r;
+ int i;
+
+ /* NOTE: handle might be NULL if invoked not as timer callback */
+ if (handle == NULL) {
+ /* Unlink all files */
+ for (i = 0; i < 16; i++) {
+ r = remove(fs_event_get_filename_in_subdir(i));
+ if (handle != NULL)
+ ASSERT(r == 0);
+ }
+ } else {
+ /* Make sure we're not attempting to remove files we do not intend */
+ ASSERT(fs_event_removed < fs_event_file_count);
+
+ /* Remove the file */
+ ASSERT(0 == remove(fs_event_get_filename_in_subdir(fs_event_removed)));
+
+ if (++fs_event_removed < fs_event_file_count) {
+ /* Remove another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+ }
+ }
+}
+
+static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ fs_event_cb_called++;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #else
+ ASSERT(filename == NULL ||
+ strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #endif
+
+ if (fs_event_created + fs_event_removed == fs_event_file_count) {
+ /* Once we've processed all create events, delete all files */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+ } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+ /* Once we've processed all create and delete events, stop watching */
+ uv_close((uv_handle_t*) &timer, close_cb);
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+#endif
+
+static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file2") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
+ #endif
+ ASSERT(0 == uv_fs_event_stop(handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void timer_cb_close_handle(uv_timer_t* timer) {
+ uv_handle_t* handle;
+
+ ASSERT(timer != NULL);
+ handle = timer->data;
+
+ uv_close((uv_handle_t*)timer, NULL);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
+ const char* filename, int events, int status) {
+ ASSERT(fs_event_cb_called == 0);
+ ++fs_event_cb_called;
+
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "watch_file") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
+ #endif
+
+ /* Regression test for SunOS: touch should generate just one event. */
+ {
+ static uv_timer_t timer;
+ uv_timer_init(handle->loop, &timer);
+ timer.data = handle;
+ uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
+ }
+}
+
+static void timer_cb_file(uv_timer_t* handle) {
+ ++timer_cb_called;
+
+ if (timer_cb_called == 1) {
+ touch_file("watch_dir/file1");
+ } else {
+ touch_file("watch_dir/file2");
+ uv_close((uv_handle_t*)handle, close_cb);
+ }
+}
+
+static void timer_cb_touch(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)timer, NULL);
+ touch_file("watch_file");
+ timer_cb_touch_called++;
+}
+
+static void timer_cb_watch_twice(uv_timer_t* handle) {
+ uv_fs_event_t* handles = handle->data;
+ uv_close((uv_handle_t*) (handles + 0), NULL);
+ uv_close((uv_handle_t*) (handles + 1), NULL);
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+TEST_IMPL(fs_event_watch_dir) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_dir_recursive) {
+#if defined(__APPLE__) || defined(_WIN32)
+ uv_loop_t* loop;
+ int r;
+
+ /* Setup */
+ loop = uv_default_loop();
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/subdir");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_dir("watch_dir/subdir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file_in_subdir, "watch_dir", UV_FS_EVENT_RECURSIVE);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ fs_event_unlink_files_in_subdir(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/subdir");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Recursive directory watching not supported on this platform.");
+#endif
+}
+
+
+TEST_IMPL(fs_event_watch_file) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+ create_file("watch_dir/file2");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, timer_cb_file, 100, 100);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(timer_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file_twice) {
+ const char path[] = "test/fixtures/empty_file";
+ uv_fs_event_t watchers[2];
+ uv_timer_t timer;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ timer.data = watchers;
+
+ ASSERT(0 == uv_fs_event_init(loop, watchers + 0));
+ ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0));
+ ASSERT(0 == uv_fs_event_init(loop, watchers + 1));
+ ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0));
+ ASSERT(0 == uv_timer_init(loop, &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file_current_dir) {
+ uv_timer_t timer;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ /* Setup */
+ remove("watch_file");
+ create_file("watch_file");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file_current_dir,
+ "watch_file",
+ 0);
+ ASSERT(r == 0);
+
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb_touch, 10, 0);
+ ASSERT(r == 0);
+
+ ASSERT(timer_cb_touch_called == 0);
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(timer_cb_touch_called == 1);
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_no_callback_after_close) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file,
+ "watch_dir/file1",
+ 0);
+ ASSERT(r == 0);
+
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+ touch_file("watch_dir/file1");
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_no_callback_on_close) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file,
+ "watch_dir/file1",
+ 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ASSERT(0 && "should never be called");
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ int r;
+
+ r = uv_fs_event_init(handle->loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+TEST_IMPL(fs_event_immediate_close) {
+ uv_timer_t timer;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 1, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_event_close_with_pending_event) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+ create_file("watch_dir/file");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ /* Generate an fs event. */
+ touch_file("watch_dir/file");
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ /* Clean up */
+ remove("watch_dir/file");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#if defined(HAVE_KQUEUE)
+
+/* kqueue doesn't register fs events if you don't have an active watcher.
+ * The file descriptor needs to be part of the kqueue set of interest and
+ * that's not the case until we actually enter the event loop.
+ */
+TEST_IMPL(fs_event_close_in_callback) {
+ fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
+ return 0;
+}
+
+#else /* !HAVE_KQUEUE */
+
+static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(fs_event_cb_called < 3);
+ ++fs_event_cb_called;
+
+ if (fs_event_cb_called == 3) {
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+
+
+TEST_IMPL(fs_event_close_in_callback) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+ create_file("watch_dir/file2");
+ create_file("watch_dir/file3");
+ create_file("watch_dir/file4");
+ create_file("watch_dir/file5");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ /* Generate a couple of fs events. */
+ touch_file("watch_dir/file1");
+ touch_file("watch_dir/file2");
+ touch_file("watch_dir/file3");
+ touch_file("watch_dir/file4");
+ touch_file("watch_dir/file5");
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(fs_event_cb_called == 3);
+
+ /* Clean up */
+ remove("watch_dir/file1");
+ remove("watch_dir/file2");
+ remove("watch_dir/file3");
+ remove("watch_dir/file4");
+ remove("watch_dir/file5");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* HAVE_KQUEUE */
+
+TEST_IMPL(fs_event_start_and_close) {
+ uv_loop_t* loop;
+ uv_fs_event_t fs_event1;
+ uv_fs_event_t fs_event2;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event1);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ r = uv_fs_event_init(loop, &fs_event2);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &fs_event2, close_cb);
+ uv_close((uv_handle_t*) &fs_event1, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_getpath) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+ char buf[1024];
+ size_t len;
+
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ len = sizeof buf;
+ r = uv_fs_event_getpath(&fs_event, buf, &len);
+ ASSERT(r == UV_EINVAL);
+ r = uv_fs_event_start(&fs_event, fail_cb, "watch_dir", 0);
+ ASSERT(r == 0);
+ len = sizeof buf;
+ r = uv_fs_event_getpath(&fs_event, buf, &len);
+ ASSERT(r == 0);
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, "watch_dir", len) == 0);
+ r = uv_fs_event_stop(&fs_event);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#if defined(__APPLE__)
+
+static int fs_event_error_reported;
+
+static void fs_event_error_report_cb(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ if (status != 0)
+ fs_event_error_reported = status;
+}
+
+static void timer_cb_nop(uv_timer_t* handle) {
+ ++timer_cb_called;
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+static void fs_event_error_report_close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+
+ /* handle is allocated on-stack, no need to free it */
+}
+
+
+TEST_IMPL(fs_event_error_reporting) {
+ unsigned int i;
+ uv_loop_t loops[1024];
+ uv_fs_event_t events[ARRAY_SIZE(loops)];
+ uv_loop_t* loop;
+ uv_fs_event_t* event;
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
+
+ remove("watch_dir/");
+ create_dir("watch_dir");
+
+ /* Create a lot of loops, and start FSEventStream in each of them.
+ * Eventually, this should create enough streams to make FSEventStreamStart()
+ * fail.
+ */
+ for (i = 0; i < ARRAY_SIZE(loops); i++) {
+ loop = &loops[i];
+ ASSERT(0 == uv_loop_init(loop));
+ event = &events[i];
+
+ timer_cb_called = 0;
+ close_cb_called = 0;
+ ASSERT(0 == uv_fs_event_init(loop, event));
+ ASSERT(0 == uv_fs_event_start(event,
+ fs_event_error_report_cb,
+ "watch_dir",
+ 0));
+ uv_unref((uv_handle_t*) event);
+
+ /* Let loop run for some time */
+ ASSERT(0 == uv_timer_init(loop, &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0));
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(1 == timer_cb_called);
+ ASSERT(1 == close_cb_called);
+ if (fs_event_error_reported != 0)
+ break;
+ }
+
+ /* At least one loop should fail */
+ ASSERT(fs_event_error_reported == UV_EMFILE);
+
+ /* Stop and close all events, and destroy loops */
+ do {
+ loop = &loops[i];
+ event = &events[i];
+
+ ASSERT(0 == uv_fs_event_stop(event));
+ uv_ref((uv_handle_t*) event);
+ uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
+
+ close_cb_called = 0;
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+
+ uv_loop_close(loop);
+ } while (i-- != 0);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !defined(__APPLE__) */
+
+TEST_IMPL(fs_event_error_reporting) {
+ /* No-op, needed only for FSEvents backend */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* defined(__APPLE__) */
diff --git a/3rdparty/libuv/test/test-fs-poll.c b/3rdparty/libuv/test/test-fs-poll.c
new file mode 100644
index 00000000000..dbc1515b0b1
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs-poll.c
@@ -0,0 +1,186 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+
+#define FIXTURE "testfile"
+
+static void timer_cb(uv_timer_t* handle);
+static void close_cb(uv_handle_t* handle);
+static void poll_cb(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+static void poll_cb_fail(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+static uv_fs_poll_t poll_handle;
+static uv_timer_t timer_handle;
+static uv_loop_t* loop;
+
+static int poll_cb_called;
+static int timer_cb_called;
+static int close_cb_called;
+
+
+static void touch_file(const char* path) {
+ static int count;
+ FILE* fp;
+ int i;
+
+ ASSERT((fp = fopen(FIXTURE, "w+")));
+
+ /* Need to change the file size because the poller may not pick up
+ * sub-second mtime changes.
+ */
+ i = ++count;
+
+ while (i--)
+ fputc('*', fp);
+
+ fclose(fp);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ touch_file(FIXTURE);
+ timer_cb_called++;
+}
+
+
+static void poll_cb_fail(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void poll_cb(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr) {
+ uv_stat_t zero_statbuf;
+
+ memset(&zero_statbuf, 0, sizeof(zero_statbuf));
+
+ ASSERT(handle == &poll_handle);
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+ ASSERT(prev != NULL);
+ ASSERT(curr != NULL);
+
+ switch (poll_cb_called++) {
+ case 0:
+ ASSERT(status == UV_ENOENT);
+ ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ touch_file(FIXTURE);
+ break;
+
+ case 1:
+ ASSERT(status == 0);
+ ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0));
+ break;
+
+ case 2:
+ ASSERT(status == 0);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0));
+ break;
+
+ case 3:
+ ASSERT(status == 0);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ remove(FIXTURE);
+ break;
+
+ case 4:
+ ASSERT(status == UV_ENOENT);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ uv_close((uv_handle_t*)handle, close_cb);
+ break;
+
+ default:
+ ASSERT(0);
+ }
+}
+
+
+TEST_IMPL(fs_poll) {
+ loop = uv_default_loop();
+
+ remove(FIXTURE);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
+ ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(poll_cb_called == 5);
+ ASSERT(timer_cb_called == 2);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_poll_getpath) {
+ char buf[1024];
+ size_t len;
+ loop = uv_default_loop();
+
+ remove(FIXTURE);
+
+ ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
+ len = sizeof buf;
+ ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len));
+ ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
+ len = sizeof buf;
+ ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(0 == memcmp(buf, FIXTURE, len));
+
+ uv_close((uv_handle_t*) &poll_handle, close_cb);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-fs.c b/3rdparty/libuv/test/test-fs.c
new file mode 100644
index 00000000000..cf37ac4909c
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs.c
@@ -0,0 +1,2664 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <string.h> /* memset */
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* FIXME we shouldn't need to branch in this file */
+#if defined(__unix__) || defined(__POSIX__) || \
+ defined(__APPLE__) || defined(_AIX)
+#include <unistd.h> /* unlink, rmdir, etc. */
+#else
+# include <direct.h>
+# include <io.h>
+# define unlink _unlink
+# define rmdir _rmdir
+# define open _open
+# define write _write
+# define close _close
+# ifndef stat
+# define stat _stati64
+# endif
+# ifndef lseek
+# define lseek _lseek
+# endif
+#endif
+
+#define TOO_LONG_NAME_LENGTH 65536
+#define PATHMAX 1024
+
+typedef struct {
+ const char* path;
+ double atime;
+ double mtime;
+} utime_check_t;
+
+
+static int dummy_cb_count;
+static int close_cb_count;
+static int create_cb_count;
+static int open_cb_count;
+static int read_cb_count;
+static int write_cb_count;
+static int unlink_cb_count;
+static int mkdir_cb_count;
+static int mkdtemp_cb_count;
+static int rmdir_cb_count;
+static int scandir_cb_count;
+static int stat_cb_count;
+static int rename_cb_count;
+static int fsync_cb_count;
+static int fdatasync_cb_count;
+static int ftruncate_cb_count;
+static int sendfile_cb_count;
+static int fstat_cb_count;
+static int access_cb_count;
+static int chmod_cb_count;
+static int fchmod_cb_count;
+static int chown_cb_count;
+static int fchown_cb_count;
+static int link_cb_count;
+static int symlink_cb_count;
+static int readlink_cb_count;
+static int realpath_cb_count;
+static int utime_cb_count;
+static int futime_cb_count;
+
+static uv_loop_t* loop;
+
+static uv_fs_t open_req1;
+static uv_fs_t open_req2;
+static uv_fs_t read_req;
+static uv_fs_t write_req;
+static uv_fs_t unlink_req;
+static uv_fs_t close_req;
+static uv_fs_t mkdir_req;
+static uv_fs_t mkdtemp_req1;
+static uv_fs_t mkdtemp_req2;
+static uv_fs_t rmdir_req;
+static uv_fs_t scandir_req;
+static uv_fs_t stat_req;
+static uv_fs_t rename_req;
+static uv_fs_t fsync_req;
+static uv_fs_t fdatasync_req;
+static uv_fs_t ftruncate_req;
+static uv_fs_t sendfile_req;
+static uv_fs_t utime_req;
+static uv_fs_t futime_req;
+
+static char buf[32];
+static char buf2[32];
+static char test_buf[] = "test-buffer\n";
+static char test_buf2[] = "second-buffer\n";
+static uv_buf_t iov;
+
+static void check_permission(const char* filename, unsigned int mode) {
+ int r;
+ uv_fs_t req;
+ uv_stat_t* s;
+
+ r = uv_fs_stat(NULL, &req, filename, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+
+ s = &req.statbuf;
+#ifdef _WIN32
+ /*
+ * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit,
+ * so only testing for the specified flags.
+ */
+ ASSERT((s->st_mode & 0777) & mode);
+#else
+ ASSERT((s->st_mode & 0777) == mode);
+#endif
+
+ uv_fs_req_cleanup(&req);
+}
+
+
+static void dummy_cb(uv_fs_t* req) {
+ (void) req;
+ dummy_cb_count++;
+}
+
+
+static void link_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_LINK);
+ ASSERT(req->result == 0);
+ link_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void symlink_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_SYMLINK);
+ ASSERT(req->result == 0);
+ symlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void readlink_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_READLINK);
+ ASSERT(req->result == 0);
+ ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0);
+ readlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void realpath_cb(uv_fs_t* req) {
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size = sizeof(test_file_abs_buf);
+ ASSERT(req->fs_type == UV_FS_REALPATH);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req->result == UV_ENOSYS) {
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+ return;
+ }
+#endif
+ ASSERT(req->result == 0);
+
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+#ifdef _WIN32
+ strcat(test_file_abs_buf, "\\test_file");
+ ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0);
+#else
+ strcat(test_file_abs_buf, "/test_file");
+ ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0);
+#endif
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void access_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_ACCESS);
+ access_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void fchmod_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_FCHMOD);
+ ASSERT(req->result == 0);
+ fchmod_cb_count++;
+ uv_fs_req_cleanup(req);
+ check_permission("test_file", *(int*)req->data);
+}
+
+
+static void chmod_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHMOD);
+ ASSERT(req->result == 0);
+ chmod_cb_count++;
+ uv_fs_req_cleanup(req);
+ check_permission("test_file", *(int*)req->data);
+}
+
+
+static void fchown_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_FCHOWN);
+ ASSERT(req->result == 0);
+ fchown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void chown_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHOWN);
+ ASSERT(req->result == 0);
+ chown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void chown_root_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHOWN);
+#ifdef _WIN32
+ /* On windows, chown is a no-op and always succeeds. */
+ ASSERT(req->result == 0);
+#else
+ /* On unix, chown'ing the root directory is not allowed -
+ * unless you're root, of course.
+ */
+ if (geteuid() == 0)
+ ASSERT(req->result == 0);
+ else
+ ASSERT(req->result == UV_EPERM);
+#endif
+ chown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void unlink_cb(uv_fs_t* req) {
+ ASSERT(req == &unlink_req);
+ ASSERT(req->fs_type == UV_FS_UNLINK);
+ ASSERT(req->result == 0);
+ unlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void fstat_cb(uv_fs_t* req) {
+ uv_stat_t* s = req->ptr;
+ ASSERT(req->fs_type == UV_FS_FSTAT);
+ ASSERT(req->result == 0);
+ ASSERT(s->st_size == sizeof(test_buf));
+ uv_fs_req_cleanup(req);
+ fstat_cb_count++;
+}
+
+
+static void close_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &close_req);
+ ASSERT(req->fs_type == UV_FS_CLOSE);
+ ASSERT(req->result == 0);
+ close_cb_count++;
+ uv_fs_req_cleanup(req);
+ if (close_cb_count == 3) {
+ r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb);
+ ASSERT(r == 0);
+ }
+}
+
+
+static void ftruncate_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &ftruncate_req);
+ ASSERT(req->fs_type == UV_FS_FTRUNCATE);
+ ASSERT(req->result == 0);
+ ftruncate_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &read_req);
+ ASSERT(req->fs_type == UV_FS_READ);
+ ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */
+ read_cb_count++;
+ uv_fs_req_cleanup(req);
+ if (read_cb_count == 1) {
+ ASSERT(strcmp(buf, test_buf) == 0);
+ r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7,
+ ftruncate_cb);
+ } else {
+ ASSERT(strcmp(buf, "test-bu") == 0);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ }
+ ASSERT(r == 0);
+}
+
+
+static void open_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &open_req1);
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ if (req->result < 0) {
+ fprintf(stderr, "async open error: %d\n", (int) req->result);
+ ASSERT(0);
+ }
+ open_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_file2\0", 11) == 0);
+ uv_fs_req_cleanup(req);
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
+ read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void open_cb_simple(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ if (req->result < 0) {
+ fprintf(stderr, "async open error: %d\n", (int) req->result);
+ ASSERT(0);
+ }
+ open_cb_count++;
+ ASSERT(req->path);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void fsync_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &fsync_req);
+ ASSERT(req->fs_type == UV_FS_FSYNC);
+ ASSERT(req->result == 0);
+ fsync_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
+}
+
+
+static void fdatasync_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &fdatasync_req);
+ ASSERT(req->fs_type == UV_FS_FDATASYNC);
+ ASSERT(req->result == 0);
+ fdatasync_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb);
+ ASSERT(r == 0);
+}
+
+
+static void write_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &write_req);
+ ASSERT(req->fs_type == UV_FS_WRITE);
+ ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */
+ write_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb);
+ ASSERT(r == 0);
+}
+
+
+static void create_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &open_req1);
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result >= 0);
+ create_cb_count++;
+ uv_fs_req_cleanup(req);
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void rename_cb(uv_fs_t* req) {
+ ASSERT(req == &rename_req);
+ ASSERT(req->fs_type == UV_FS_RENAME);
+ ASSERT(req->result == 0);
+ rename_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void mkdir_cb(uv_fs_t* req) {
+ ASSERT(req == &mkdir_req);
+ ASSERT(req->fs_type == UV_FS_MKDIR);
+ ASSERT(req->result == 0);
+ mkdir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void check_mkdtemp_result(uv_fs_t* req) {
+ int r;
+
+ ASSERT(req->fs_type == UV_FS_MKDTEMP);
+ ASSERT(req->result == 0);
+ ASSERT(req->path);
+ ASSERT(strlen(req->path) == 15);
+ ASSERT(memcmp(req->path, "test_dir_", 9) == 0);
+ ASSERT(memcmp(req->path + 9, "XXXXXX", 6) != 0);
+ check_permission(req->path, 0700);
+
+ /* Check if req->path is actually a directory */
+ r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
+ uv_fs_req_cleanup(&stat_req);
+}
+
+
+static void mkdtemp_cb(uv_fs_t* req) {
+ ASSERT(req == &mkdtemp_req1);
+ check_mkdtemp_result(req);
+ mkdtemp_cb_count++;
+}
+
+
+static void rmdir_cb(uv_fs_t* req) {
+ ASSERT(req == &rmdir_req);
+ ASSERT(req->fs_type == UV_FS_RMDIR);
+ ASSERT(req->result == 0);
+ rmdir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void assert_is_file_type(uv_dirent_t dent) {
+#ifdef HAVE_DIRENT_TYPES
+ /*
+ * For Apple and Windows, we know getdents is expected to work but for other
+ * environments, the filesystem dictates whether or not getdents supports
+ * returning the file type.
+ *
+ * See:
+ * http://man7.org/linux/man-pages/man2/getdents.2.html
+ * https://github.com/libuv/libuv/issues/501
+ */
+ #if defined(__APPLE__) || defined(_WIN32)
+ ASSERT(dent.type == UV_DIRENT_FILE);
+ #else
+ ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN);
+ #endif
+#else
+ ASSERT(dent.type == UV_DIRENT_UNKNOWN);
+#endif
+}
+
+
+static void scandir_cb(uv_fs_t* req) {
+ uv_dirent_t dent;
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == 2);
+ ASSERT(req->ptr);
+
+ while (UV_EOF != uv_fs_scandir_next(req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ scandir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+ ASSERT(!req->ptr);
+}
+
+
+static void empty_scandir_cb(uv_fs_t* req) {
+ uv_dirent_t dent;
+
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == 0);
+ ASSERT(req->ptr == NULL);
+ ASSERT(UV_EOF == uv_fs_scandir_next(req, &dent));
+ uv_fs_req_cleanup(req);
+ scandir_cb_count++;
+}
+
+
+static void file_scandir_cb(uv_fs_t* req) {
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == UV_ENOTDIR);
+ ASSERT(req->ptr == NULL);
+ uv_fs_req_cleanup(req);
+ scandir_cb_count++;
+}
+
+
+static void stat_cb(uv_fs_t* req) {
+ ASSERT(req == &stat_req);
+ ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT);
+ ASSERT(req->result == 0);
+ ASSERT(req->ptr);
+ stat_cb_count++;
+ uv_fs_req_cleanup(req);
+ ASSERT(!req->ptr);
+}
+
+
+static void sendfile_cb(uv_fs_t* req) {
+ ASSERT(req == &sendfile_req);
+ ASSERT(req->fs_type == UV_FS_SENDFILE);
+ ASSERT(req->result == 65546);
+ sendfile_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void open_noent_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ENOENT);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void open_nametoolong_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ENAMETOOLONG);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void open_loop_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ELOOP);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+TEST_IMPL(fs_file_noent) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ENOENT);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ /* TODO add EACCES test */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_file_nametoolong) {
+ uv_fs_t req;
+ int r;
+ char name[TOO_LONG_NAME_LENGTH + 1];
+
+ loop = uv_default_loop();
+
+ memset(name, 'a', TOO_LONG_NAME_LENGTH);
+ name[TOO_LONG_NAME_LENGTH] = 0;
+
+ r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ENAMETOOLONG);
+ ASSERT(req.result == UV_ENAMETOOLONG);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_file_loop) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ unlink("test_symlink");
+ r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
+ * Starting with vista they are supported, but only when elevated, otherwise
+ * we'll see UV_EPERM.
+ */
+ if (r == UV_ENOTSUP || r == UV_EPERM)
+ return 0;
+#endif
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ELOOP);
+ ASSERT(req.result == UV_ELOOP);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ unlink("test_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+static void check_utime(const char* path, double atime, double mtime) {
+ uv_stat_t* s;
+ uv_fs_t req;
+ int r;
+
+ r = uv_fs_stat(loop, &req, path, NULL);
+ ASSERT(r == 0);
+
+ ASSERT(req.result == 0);
+ s = &req.statbuf;
+
+ ASSERT(s->st_atim.tv_sec == atime);
+ ASSERT(s->st_mtim.tv_sec == mtime);
+
+ uv_fs_req_cleanup(&req);
+}
+
+
+static void utime_cb(uv_fs_t* req) {
+ utime_check_t* c;
+
+ ASSERT(req == &utime_req);
+ ASSERT(req->result == 0);
+ ASSERT(req->fs_type == UV_FS_UTIME);
+
+ c = req->data;
+ check_utime(c->path, c->atime, c->mtime);
+
+ uv_fs_req_cleanup(req);
+ utime_cb_count++;
+}
+
+
+static void futime_cb(uv_fs_t* req) {
+ utime_check_t* c;
+
+ ASSERT(req == &futime_req);
+ ASSERT(req->result == 0);
+ ASSERT(req->fs_type == UV_FS_FUTIME);
+
+ c = req->data;
+ check_utime(c->path, c->atime, c->mtime);
+
+ uv_fs_req_cleanup(req);
+ futime_cb_count++;
+}
+
+
+TEST_IMPL(fs_file_async) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IRUSR | S_IWUSR, create_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(fsync_cb_count == 1);
+ ASSERT(fdatasync_cb_count == 1);
+ ASSERT(close_cb_count == 1);
+
+ r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(close_cb_count == 1);
+ ASSERT(rename_cb_count == 1);
+
+ r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+ ASSERT(read_cb_count == 1);
+ ASSERT(close_cb_count == 2);
+ ASSERT(rename_cb_count == 1);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(ftruncate_cb_count == 1);
+
+ r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 2);
+ ASSERT(read_cb_count == 2);
+ ASSERT(close_cb_count == 3);
+ ASSERT(rename_cb_count == 1);
+ ASSERT(unlink_cb_count == 1);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(ftruncate_cb_count == 1);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_sync) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL);
+ ASSERT(r == 0);
+ ASSERT(ftruncate_req.result == 0);
+ uv_fs_req_cleanup(&ftruncate_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(rename_req.result == 0);
+ uv_fs_req_cleanup(&rename_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, "test-bu") == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(unlink_req.result == 0);
+ uv_fs_req_cleanup(&unlink_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_write_null_buffer) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(write_req.result == 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_async_dir) {
+ int r;
+ uv_dirent_t dent;
+
+ /* Setup */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(mkdir_cb_count == 1);
+
+ /* Create 2 files synchronously. */
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ /* sync uv_fs_scandir */
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(stat_cb_count == 4);
+
+ r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(unlink_cb_count == 1);
+
+ r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(unlink_cb_count == 2);
+
+ r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(rmdir_cb_count == 1);
+
+ /* Cleanup */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_async_sendfile) {
+ int f, r;
+ struct stat s1, s2;
+
+ loop = uv_default_loop();
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
+ ASSERT(f != -1);
+
+ r = write(f, "begin\n", 6);
+ ASSERT(r == 6);
+
+ r = lseek(f, 65536, SEEK_CUR);
+ ASSERT(r == 65542);
+
+ r = write(f, "end\n", 4);
+ ASSERT(r != -1);
+
+ r = close(f);
+ ASSERT(r == 0);
+
+ /* Test starts here. */
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req2.result >= 0);
+ uv_fs_req_cleanup(&open_req2);
+
+ r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
+ 0, 131072, sendfile_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(sendfile_cb_count == 1);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+ r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ stat("test_file", &s1);
+ stat("test_file2", &s2);
+ ASSERT(65546 == s2.st_size && s1.st_size == s2.st_size);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_mkdtemp) {
+ int r;
+ const char* path_template = "test_dir_XXXXXX";
+
+ loop = uv_default_loop();
+
+ r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(mkdtemp_cb_count == 1);
+
+ /* sync mkdtemp */
+ r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
+ ASSERT(r == 0);
+ check_mkdtemp_result(&mkdtemp_req2);
+
+ /* mkdtemp return different values on subsequent calls */
+ ASSERT(strcmp(mkdtemp_req1.path, mkdtemp_req2.path) != 0);
+
+ /* Cleanup */
+ rmdir(mkdtemp_req1.path);
+ rmdir(mkdtemp_req2.path);
+ uv_fs_req_cleanup(&mkdtemp_req1);
+ uv_fs_req_cleanup(&mkdtemp_req2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_fstat) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_stat_t* s;
+#ifndef _WIN32
+ struct stat t;
+#endif
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_fstat(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ s = req.ptr;
+ ASSERT(s->st_size == sizeof(test_buf));
+
+#ifndef _WIN32
+ r = fstat(file, &t);
+ ASSERT(r == 0);
+
+ ASSERT(s->st_dev == (uint64_t) t.st_dev);
+ ASSERT(s->st_mode == (uint64_t) t.st_mode);
+ ASSERT(s->st_nlink == (uint64_t) t.st_nlink);
+ ASSERT(s->st_uid == (uint64_t) t.st_uid);
+ ASSERT(s->st_gid == (uint64_t) t.st_gid);
+ ASSERT(s->st_rdev == (uint64_t) t.st_rdev);
+ ASSERT(s->st_ino == (uint64_t) t.st_ino);
+ ASSERT(s->st_size == (uint64_t) t.st_size);
+ ASSERT(s->st_blksize == (uint64_t) t.st_blksize);
+ ASSERT(s->st_blocks == (uint64_t) t.st_blocks);
+#if defined(__APPLE__)
+ ASSERT(s->st_atim.tv_sec == t.st_atimespec.tv_sec);
+ ASSERT(s->st_atim.tv_nsec == t.st_atimespec.tv_nsec);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtimespec.tv_sec);
+ ASSERT(s->st_mtim.tv_nsec == t.st_mtimespec.tv_nsec);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctimespec.tv_sec);
+ ASSERT(s->st_ctim.tv_nsec == t.st_ctimespec.tv_nsec);
+ ASSERT(s->st_birthtim.tv_sec == t.st_birthtimespec.tv_sec);
+ ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec);
+ ASSERT(s->st_flags == t.st_flags);
+ ASSERT(s->st_gen == t.st_gen);
+#elif defined(_AIX)
+ ASSERT(s->st_atim.tv_sec == t.st_atime);
+ ASSERT(s->st_atim.tv_nsec == 0);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtime);
+ ASSERT(s->st_mtim.tv_nsec == 0);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctime);
+ ASSERT(s->st_ctim.tv_nsec == 0);
+#elif defined(__sun) || \
+ defined(_BSD_SOURCE) || \
+ defined(_SVID_SOURCE) || \
+ defined(_XOPEN_SOURCE) || \
+ defined(_DEFAULT_SOURCE)
+ ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec);
+ ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec);
+ ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec);
+ ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec);
+# if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+ ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec);
+ ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec);
+ ASSERT(s->st_flags == t.st_flags);
+ ASSERT(s->st_gen == t.st_gen);
+# endif
+#else
+ ASSERT(s->st_atim.tv_sec == t.st_atime);
+ ASSERT(s->st_atim.tv_nsec == 0);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtime);
+ ASSERT(s->st_mtim.tv_nsec == 0);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctime);
+ ASSERT(s->st_ctim.tv_nsec == 0);
+#endif
+#endif
+
+ uv_fs_req_cleanup(&req);
+
+ /* Now do the uv_fs_fstat call asynchronously */
+ r = uv_fs_fstat(loop, &req, file, fstat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fstat_cb_count == 1);
+
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_access) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+ rmdir("test_dir");
+
+ loop = uv_default_loop();
+
+ /* File should not exist */
+ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
+ ASSERT(r < 0);
+ ASSERT(req.result < 0);
+ uv_fs_req_cleanup(&req);
+
+ /* File should not exist */
+ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(access_cb_count == 1);
+ access_cb_count = 0; /* reset for the next test */
+
+ /* Create file */
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ /* File should exist */
+ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* File should exist */
+ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(access_cb_count == 1);
+ access_cb_count = 0; /* reset for the next test */
+
+ /* Close file */
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* Directory access */
+ r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ rmdir("test_dir");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_chmod) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+#ifndef _WIN32
+ /* Make the file write-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0200);
+#endif
+
+ /* Make the file read-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0400);
+
+ /* Make the file read+write with sync uv_fs_fchmod */
+ r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0600);
+
+#ifndef _WIN32
+ /* async chmod */
+ {
+ static int mode = 0200;
+ req.data = &mode;
+ }
+ r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chmod_cb_count == 1);
+ chmod_cb_count = 0; /* reset for the next test */
+#endif
+
+ /* async chmod */
+ {
+ static int mode = 0400;
+ req.data = &mode;
+ }
+ r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chmod_cb_count == 1);
+
+ /* async fchmod */
+ {
+ static int mode = 0600;
+ req.data = &mode;
+ }
+ r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fchmod_cb_count == 1);
+
+ close(file);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_unlink_readonly) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL,
+ &req,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* Make the file read-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0400);
+
+ /* Try to unlink the file */
+ r = uv_fs_unlink(NULL, &req, "test_file", NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
+ uv_fs_req_cleanup(&req);
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_chown) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ /* sync chown */
+ r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* sync fchown */
+ r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* async chown */
+ r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chown_cb_count == 1);
+
+ /* chown to root (fail) */
+ chown_cb_count = 0;
+ r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chown_cb_count == 1);
+
+ /* async fchown */
+ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fchown_cb_count == 1);
+
+ close(file);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_link) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync link */
+ r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /* async link */
+ r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(link_cb_count == 1);
+
+ r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_readlink) {
+ uv_fs_t req;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(dummy_cb_count == 1);
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL));
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_realpath) {
+ uv_fs_t req;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(dummy_cb_count == 1);
+ ASSERT(req.ptr == NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req.result == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL));
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_symlink) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink2");
+ unlink("test_file_symlink_symlink");
+ unlink("test_file_symlink2_symlink");
+ test_file_abs_size = sizeof(test_file_abs_buf);
+#ifdef _WIN32
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "\\test_file");
+#else
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "/test_file");
+#endif
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync symlink */
+ r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
+#ifdef _WIN32
+ if (r < 0) {
+ if (r == UV_ENOTSUP) {
+ /*
+ * Windows doesn't support symlinks on older versions.
+ * We just pass the test and bail out early if we get ENOTSUP.
+ */
+ return 0;
+ } else if (r == UV_EPERM) {
+ /*
+ * Creating a symlink is only allowed when running elevated.
+ * We pass the test and bail out early if we get UV_EPERM.
+ */
+ return 0;
+ }
+ }
+#endif
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ r = uv_fs_symlink(NULL,
+ &req,
+ "test_file_symlink",
+ "test_file_symlink_symlink",
+ 0,
+ NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(strcmp(req.ptr, "test_file_symlink") == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ /* async link */
+ r = uv_fs_symlink(loop,
+ &req,
+ "test_file",
+ "test_file_symlink2",
+ 0,
+ symlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(symlink_cb_count == 1);
+
+ r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ r = uv_fs_symlink(NULL,
+ &req,
+ "test_file_symlink2",
+ "test_file_symlink2_symlink",
+ 0,
+ NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(readlink_cb_count == 1);
+
+ r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(realpath_cb_count == 1);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink_symlink");
+ unlink("test_file_symlink2");
+ unlink("test_file_symlink2_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_symlink_dir) {
+ uv_fs_t req;
+ int r;
+ char* test_dir;
+ uv_dirent_t dent;
+ static char test_dir_abs_buf[PATHMAX];
+ size_t test_dir_abs_size;
+
+ /* set-up */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+ rmdir("test_dir_symlink");
+ test_dir_abs_size = sizeof(test_dir_abs_buf);
+
+ loop = uv_default_loop();
+
+ uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+#ifdef _WIN32
+ strcpy(test_dir_abs_buf, "\\\\?\\");
+ uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
+ test_dir_abs_size += 4;
+ strcat(test_dir_abs_buf, "\\test_dir\\");
+ test_dir_abs_size += strlen("\\test_dir\\");
+ test_dir = test_dir_abs_buf;
+#else
+ uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
+ strcat(test_dir_abs_buf, "/test_dir");
+ test_dir_abs_size += strlen("/test_dir");
+ test_dir = "test_dir";
+#endif
+
+ r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink",
+ UV_FS_SYMLINK_JUNCTION, NULL);
+ fprintf(stderr, "r == %i\n", r);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
+#ifdef _WIN32
+ ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4));
+#else
+ ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir));
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(strcmp(req.ptr, test_dir + 4) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_dir) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(strlen(req.ptr) == test_dir_abs_size - 5);
+ ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ /* unlink will remove the directory symlink */
+ r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
+ ASSERT(r == UV_ENOENT);
+ uv_fs_req_cleanup(&scandir_req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ /* clean-up */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+ rmdir("test_dir_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_utime) {
+ utime_check_t checkme;
+ const char* path = "test_file";
+ double atime;
+ double mtime;
+ uv_fs_t req;
+ int r;
+
+ /* Setup. */
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ uv_fs_req_cleanup(&req);
+ close(r);
+
+ atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+ r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, path, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ check_utime(path, atime, mtime);
+ uv_fs_req_cleanup(&req);
+
+ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+ checkme.path = path;
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+
+ /* async utime */
+ utime_req.data = &checkme;
+ r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(utime_cb_count == 1);
+
+ /* Cleanup. */
+ unlink(path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(fs_stat_root) {
+ int r;
+ uv_loop_t* loop = uv_default_loop();
+
+ r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
+ ASSERT(r == 0);
+
+ /* stats the current directory on c: */
+ r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(fs_futime) {
+ utime_check_t checkme;
+ const char* path = "test_file";
+ double atime;
+ double mtime;
+ uv_file file;
+ uv_fs_t req;
+ int r;
+
+ /* Setup. */
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ uv_fs_req_cleanup(&req);
+ close(r);
+
+ atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+ r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result; /* FIXME probably not how it's supposed to be used */
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, path, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ check_utime(path, atime, mtime);
+ uv_fs_req_cleanup(&req);
+
+ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+ checkme.path = path;
+
+ /* async futime */
+ futime_req.data = &checkme;
+ r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(futime_cb_count == 1);
+
+ /* Cleanup. */
+ unlink(path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_stat_missing_path) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
+ ASSERT(r == UV_ENOENT);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_scandir_empty_dir) {
+ const char* path;
+ uv_fs_t req;
+ uv_dirent_t dent;
+ int r;
+
+ path = "./empty_dir/";
+ loop = uv_default_loop();
+
+ uv_fs_mkdir(NULL, &req, path, 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+ /* Fill the req to ensure that required fields are cleaned up */
+ memset(&req, 0xdb, sizeof(req));
+
+ r = uv_fs_scandir(NULL, &req, path, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ ASSERT(req.ptr == NULL);
+ ASSERT(UV_EOF == uv_fs_scandir_next(&req, &dent));
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb);
+ ASSERT(r == 0);
+
+ ASSERT(scandir_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ uv_fs_rmdir(NULL, &req, path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_scandir_file) {
+ const char* path;
+ int r;
+
+ path = "test/fixtures/empty_file";
+ loop = uv_default_loop();
+
+ r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
+ ASSERT(r == UV_ENOTDIR);
+ uv_fs_req_cleanup(&scandir_req);
+
+ r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb);
+ ASSERT(r == 0);
+
+ ASSERT(scandir_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_open_dir) {
+ const char* path;
+ uv_fs_t req;
+ int r, file;
+
+ path = ".";
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(req.ptr == NULL);
+ file = r;
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_open_append) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ printf("read = %d\n", r);
+ ASSERT(r == 26);
+ ASSERT(read_req.result == 26);
+ ASSERT(memcmp(buf,
+ "test-buffer\n\0test-buffer\n\0",
+ sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_rename_to_existing_file) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(rename_req.result == 0);
+ uv_fs_req_cleanup(&rename_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_read_file_eof) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
+ read_req.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_multiple_bufs) {
+ uv_buf_t iovs[2];
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
+ iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ memset(buf2, 0, sizeof(buf2));
+ /* Read the strings back to separate buffers. */
+ iovs[0] = uv_buf_init(buf, sizeof(test_buf));
+ iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ ASSERT(strcmp(buf2, test_buf2) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
+ read_req.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_alotof_bufs) {
+ const size_t iovcount = 54321;
+ uv_buf_t* iovs;
+ char* buffer;
+ size_t index;
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ iovs = malloc(sizeof(*iovs) * iovcount);
+ ASSERT(iovs != NULL);
+
+ r = uv_fs_open(NULL,
+ &open_req1,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+ r = uv_fs_write(NULL,
+ &write_req,
+ open_req1.result,
+ iovs,
+ iovcount,
+ -1,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+ uv_fs_req_cleanup(&write_req);
+
+ /* Read the strings back to separate buffers. */
+ buffer = malloc(sizeof(test_buf) * iovcount);
+ ASSERT(buffer != NULL);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+ sizeof(test_buf));
+
+ r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
+
+ for (index = 0; index < iovcount; ++index)
+ ASSERT(strncmp(buffer + index * sizeof(test_buf),
+ test_buf,
+ sizeof(test_buf)) == 0);
+
+ uv_fs_req_cleanup(&read_req);
+ free(buffer);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL,
+ &read_req,
+ open_req1.result,
+ &iov,
+ 1,
+ read_req.result,
+ NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ free(iovs);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_alotof_bufs_with_offset) {
+ const size_t iovcount = 54321;
+ uv_buf_t* iovs;
+ char* buffer;
+ size_t index;
+ int r;
+ int64_t offset;
+ char* filler = "0123456789";
+ int filler_len = strlen(filler);
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ iovs = malloc(sizeof(*iovs) * iovcount);
+ ASSERT(iovs != NULL);
+
+ r = uv_fs_open(NULL,
+ &open_req1,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(filler, filler_len);
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r == filler_len);
+ ASSERT(write_req.result == filler_len);
+ uv_fs_req_cleanup(&write_req);
+ offset = (int64_t)r;
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+ r = uv_fs_write(NULL,
+ &write_req,
+ open_req1.result,
+ iovs,
+ iovcount,
+ offset,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+ uv_fs_req_cleanup(&write_req);
+
+ /* Read the strings back to separate buffers. */
+ buffer = malloc(sizeof(test_buf) * iovcount);
+ ASSERT(buffer != NULL);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+ sizeof(test_buf));
+
+ r = uv_fs_read(NULL, &read_req, open_req1.result,
+ iovs, iovcount, offset, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result == sizeof(test_buf) * iovcount);
+
+ for (index = 0; index < iovcount; ++index)
+ ASSERT(strncmp(buffer + index * sizeof(test_buf),
+ test_buf,
+ sizeof(test_buf)) == 0);
+
+ uv_fs_req_cleanup(&read_req);
+ free(buffer);
+
+ r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
+ ASSERT(r == 0);
+ ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
+ offset + (int64_t)(iovcount * sizeof(test_buf)));
+ uv_fs_req_cleanup(&stat_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL,
+ &read_req,
+ open_req1.result,
+ &iov,
+ 1,
+ read_req.result + offset,
+ NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ free(iovs);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_read_write_null_arguments) {
+ int r;
+
+ r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_read(NULL, NULL, 0, &iov, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_write(NULL, NULL, 0, &iov, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-currentexe.c b/3rdparty/libuv/test/test-get-currentexe.c
new file mode 100644
index 00000000000..0e9d6965402
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-currentexe.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+extern char executable_path[];
+
+TEST_IMPL(get_currentexe) {
+ char buffer[PATHMAX];
+ size_t size;
+ char* match;
+ char* path;
+ int r;
+
+ size = sizeof(buffer) / sizeof(buffer[0]);
+ r = uv_exepath(buffer, &size);
+ ASSERT(!r);
+
+ /* uv_exepath can return an absolute path on darwin, so if the test runner
+ * was run with a relative prefix of "./", we need to strip that prefix off
+ * executable_path or we'll fail. */
+ if (executable_path[0] == '.' && executable_path[1] == '/') {
+ path = executable_path + 2;
+ } else {
+ path = executable_path;
+ }
+
+ match = strstr(buffer, path);
+ /* Verify that the path returned from uv_exepath is a subdirectory of
+ * executable_path.
+ */
+ ASSERT(match && !strcmp(match, path));
+ ASSERT(size == strlen(buffer));
+
+ /* Negative tests */
+ size = sizeof(buffer) / sizeof(buffer[0]);
+ r = uv_exepath(NULL, &size);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_exepath(buffer, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ size = 0;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == UV_EINVAL);
+
+ memset(buffer, -1, sizeof(buffer));
+
+ size = 1;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == 0);
+ ASSERT(size == 0);
+ ASSERT(buffer[0] == '\0');
+
+ memset(buffer, -1, sizeof(buffer));
+
+ size = 2;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == 0);
+ ASSERT(size == 1);
+ ASSERT(buffer[0] != '\0');
+ ASSERT(buffer[1] == '\0');
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-loadavg.c b/3rdparty/libuv/test/test-get-loadavg.c
new file mode 100644
index 00000000000..4762e47576d
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-loadavg.c
@@ -0,0 +1,35 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+TEST_IMPL(get_loadavg) {
+
+ double avg[3] = {-1, -1, -1};
+ uv_loadavg(avg);
+
+ ASSERT(avg[0] >= 0);
+ ASSERT(avg[1] >= 0);
+ ASSERT(avg[2] >= 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-memory.c b/3rdparty/libuv/test/test-get-memory.c
new file mode 100644
index 00000000000..2396939bcb1
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-memory.c
@@ -0,0 +1,38 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+TEST_IMPL(get_memory) {
+ uint64_t free_mem = uv_get_free_memory();
+ uint64_t total_mem = uv_get_total_memory();
+
+ printf("free_mem=%llu, total_mem=%llu\n",
+ (unsigned long long) free_mem,
+ (unsigned long long) total_mem);
+
+ ASSERT(free_mem > 0);
+ ASSERT(total_mem > 0);
+ ASSERT(total_mem > free_mem);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getaddrinfo.c b/3rdparty/libuv/test/test-getaddrinfo.c
new file mode 100644
index 00000000000..6b644a8d442
--- /dev/null
+++ b/3rdparty/libuv/test/test-getaddrinfo.c
@@ -0,0 +1,184 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdlib.h>
+
+#define CONCURRENT_COUNT 10
+
+static const char* name = "localhost";
+
+static int getaddrinfo_cbs = 0;
+
+/* data used for running multiple calls concurrently */
+static uv_getaddrinfo_t* getaddrinfo_handle;
+static uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT];
+static int callback_counts[CONCURRENT_COUNT];
+static int fail_cb_called;
+
+
+static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(fail_cb_called == 0);
+ ASSERT(status < 0);
+ ASSERT(res == NULL);
+ uv_freeaddrinfo(res); /* Should not crash. */
+ fail_cb_called++;
+}
+
+
+static void getaddrinfo_basic_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(handle == getaddrinfo_handle);
+ getaddrinfo_cbs++;
+ free(handle);
+ uv_freeaddrinfo(res);
+}
+
+
+static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ int i;
+ int* data = (int*)handle->data;
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (&getaddrinfo_handles[i] == handle) {
+ ASSERT(i == *data);
+
+ callback_counts[i]++;
+ break;
+ }
+ }
+ ASSERT (i < CONCURRENT_COUNT);
+
+ free(data);
+ uv_freeaddrinfo(res);
+
+ getaddrinfo_cbs++;
+}
+
+
+TEST_IMPL(getaddrinfo_fail) {
+ uv_getaddrinfo_t req;
+
+ /* Use a FQDN by ending in a period */
+ ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
+ &req,
+ getaddrinfo_fail_cb,
+ "xyzzy.xyzzy.xyzzy.",
+ NULL,
+ NULL));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(fail_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_fail_sync) {
+ uv_getaddrinfo_t req;
+
+ /* Use a FQDN by ending in a period */
+ ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
+ &req,
+ NULL,
+ "xyzzy.xyzzy.xyzzy.",
+ NULL,
+ NULL));
+ uv_freeaddrinfo(req.addrinfo);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_basic) {
+ int r;
+ getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
+
+ r = uv_getaddrinfo(uv_default_loop(),
+ getaddrinfo_handle,
+ &getaddrinfo_basic_cb,
+ name,
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(getaddrinfo_cbs == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_basic_sync) {
+ uv_getaddrinfo_t req;
+
+ ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
+ &req,
+ NULL,
+ name,
+ NULL,
+ NULL));
+ uv_freeaddrinfo(req.addrinfo);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_concurrent) {
+ int i, r;
+ int* data;
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ callback_counts[i] = 0;
+
+ data = (int*)malloc(sizeof(int));
+ ASSERT(data != NULL);
+ *data = i;
+ getaddrinfo_handles[i].data = data;
+
+ r = uv_getaddrinfo(uv_default_loop(),
+ &getaddrinfo_handles[i],
+ &getaddrinfo_cuncurrent_cb,
+ name,
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ ASSERT(callback_counts[i] == 1);
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getnameinfo.c b/3rdparty/libuv/test/test-getnameinfo.c
new file mode 100644
index 00000000000..b1391616d13
--- /dev/null
+++ b/3rdparty/libuv/test/test-getnameinfo.c
@@ -0,0 +1,101 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static const char* address_ip4 = "127.0.0.1";
+static const char* address_ip6 = "::1";
+static const int port = 80;
+
+static struct sockaddr_in addr4;
+static struct sockaddr_in6 addr6;
+static uv_getnameinfo_t req;
+
+static void getnameinfo_req(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(handle != NULL);
+ ASSERT(status == 0);
+ ASSERT(hostname != NULL);
+ ASSERT(service != NULL);
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip4) {
+ int r;
+
+ r = uv_ip4_addr(address_ip4, port, &addr4);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr4,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip4_sync) {
+ ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));
+
+ ASSERT(0 == uv_getnameinfo(uv_default_loop(),
+ &req,
+ NULL,
+ (const struct sockaddr*)&addr4,
+ 0));
+ ASSERT(req.host[0] != '\0');
+ ASSERT(req.service[0] != '\0');
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip6) {
+ int r;
+
+ r = uv_ip6_addr(address_ip6, port, &addr6);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr6,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getsockname.c b/3rdparty/libuv/test/test-getsockname.c
new file mode 100644
index 00000000000..565c17fe50b
--- /dev/null
+++ b/3rdparty/libuv/test/test-getsockname.c
@@ -0,0 +1,361 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int server_port = TEST_PORT;
+/* Will be updated right after making the uv_connect_call */
+static int connect_port = -1;
+
+static int getsocknamecount = 0;
+static int getpeernamecount = 0;
+
+static uv_loop_t* loop;
+static uv_tcp_t tcp;
+static uv_udp_t udp;
+static uv_connect_t connect_req;
+static uv_tcp_t tcpServer;
+static uv_udp_t udpServer;
+static uv_udp_send_t send_req;
+
+
+static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+ uv_close((uv_handle_t*)&tcpServer, NULL);
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_shutdown_t* req;
+ int r;
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ req = (uv_shutdown_t*) malloc(sizeof *req);
+ r = uv_shutdown(req, handle, after_shutdown);
+ ASSERT(r == 0);
+}
+
+
+static void check_sockname(struct sockaddr* addr, const char* compare_ip,
+ int compare_port, const char* context) {
+ struct sockaddr_in check_addr = *(struct sockaddr_in*) addr;
+ struct sockaddr_in compare_addr;
+ char check_ip[17];
+ int r;
+
+ ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr));
+
+ /* Both addresses should be ipv4 */
+ ASSERT(check_addr.sin_family == AF_INET);
+ ASSERT(compare_addr.sin_family == AF_INET);
+
+ /* Check if the ip matches */
+ ASSERT(memcmp(&check_addr.sin_addr,
+ &compare_addr.sin_addr,
+ sizeof compare_addr.sin_addr) == 0);
+
+ /* Check if the port matches. If port == 0 anything goes. */
+ ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port);
+
+ r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip);
+ ASSERT(r == 0);
+
+ printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port));
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ struct sockaddr sockname, peername;
+ int namelen;
+ uv_tcp_t* handle;
+ int r;
+
+ if (status != 0) {
+ fprintf(stderr, "Connect error %s\n", uv_err_name(status));
+ }
+ ASSERT(status == 0);
+
+ handle = malloc(sizeof(*handle));
+ ASSERT(handle != NULL);
+
+ r = uv_tcp_init(loop, handle);
+ ASSERT(r == 0);
+
+ /* associate server with stream */
+ handle->data = server;
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(handle, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket");
+ getsocknamecount++;
+
+ namelen = sizeof peername;
+ r = uv_tcp_getpeername(handle, &peername, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer");
+ getpeernamecount++;
+
+ r = uv_read_start((uv_stream_t*)handle, alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static void on_connect(uv_connect_t* req, int status) {
+ struct sockaddr sockname, peername;
+ int r, namelen;
+
+ ASSERT(status == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "127.0.0.1", 0, "connected socket");
+ getsocknamecount++;
+
+ namelen = sizeof peername;
+ r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer");
+ getpeernamecount++;
+
+ uv_close((uv_handle_t*)&tcp, NULL);
+}
+
+
+static int tcp_listener(void) {
+ struct sockaddr_in addr;
+ struct sockaddr sockname, peername;
+ int namelen;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection);
+ if (r) {
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", server_port, "server socket");
+ getsocknamecount++;
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getpeername(&tcpServer, &peername, &namelen);
+ ASSERT(r == UV_ENOTCONN);
+ getpeernamecount++;
+
+ return 0;
+}
+
+
+static void tcp_connector(void) {
+ struct sockaddr_in server_addr;
+ struct sockaddr sockname;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
+
+ r = uv_tcp_init(loop, &tcp);
+ tcp.data = &connect_req;
+ ASSERT(!r);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ on_connect);
+ ASSERT(!r);
+
+ /* Fetch the actual port used by the connecting socket. */
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&tcp, &sockname, &namelen);
+ ASSERT(!r);
+ ASSERT(sockname.sa_family == AF_INET);
+ connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port);
+ ASSERT(connect_port > 0);
+}
+
+
+static void udp_recv(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ struct sockaddr sockname;
+ int namelen;
+ int r;
+
+ ASSERT(nread >= 0);
+ free(buf->base);
+
+ if (nread == 0) {
+ return;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof(sockname);
+ r = uv_udp_getsockname(&udp, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket");
+ getsocknamecount++;
+
+ uv_close((uv_handle_t*) &udp, NULL);
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+static void udp_send(uv_udp_send_t* req, int status) {
+
+}
+
+
+static int udp_listener(void) {
+ struct sockaddr_in addr;
+ struct sockaddr sockname;
+ int namelen;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
+
+ r = uv_udp_init(loop, &udpServer);
+ if (r) {
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&udpServer, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket");
+ getsocknamecount++;
+
+ r = uv_udp_recv_start(&udpServer, alloc, udp_recv);
+ ASSERT(r == 0);
+
+ return 0;
+}
+
+
+static void udp_sender(void) {
+ struct sockaddr_in server_addr;
+ uv_buf_t buf;
+ int r;
+
+ r = uv_udp_init(loop, &udp);
+ ASSERT(!r);
+
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
+
+ r = uv_udp_send(&send_req,
+ &udp,
+ &buf,
+ 1,
+ (const struct sockaddr*) &server_addr,
+ udp_send);
+ ASSERT(!r);
+}
+
+
+TEST_IMPL(getsockname_tcp) {
+ loop = uv_default_loop();
+
+ if (tcp_listener())
+ return 1;
+
+ tcp_connector();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(getsocknamecount == 3);
+ ASSERT(getpeernamecount == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getsockname_udp) {
+ loop = uv_default_loop();
+
+ if (udp_listener())
+ return 1;
+
+ udp_sender();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(getsocknamecount == 2);
+
+ ASSERT(udp.send_queue_size == 0);
+ ASSERT(udpServer.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-handle-fileno.c b/3rdparty/libuv/test/test-handle-fileno.c
new file mode 100644
index 00000000000..3fe933adebd
--- /dev/null
+++ b/3rdparty/libuv/test/test-handle-fileno.c
@@ -0,0 +1,121 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int get_tty_fd(void) {
+ /* Make sure we have an FD that refers to a tty */
+#ifdef _WIN32
+ HANDLE handle;
+ handle = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE)
+ return -1;
+ return _open_osfhandle((intptr_t) handle, 0);
+#else /* unix */
+ return open("/dev/tty", O_RDONLY, 0);
+#endif
+}
+
+
+TEST_IMPL(handle_fileno) {
+ int r;
+ int tty_fd;
+ struct sockaddr_in addr;
+ uv_os_fd_t fd;
+ uv_tcp_t tcp;
+ uv_udp_t udp;
+ uv_pipe_t pipe;
+ uv_tty_t tty;
+ uv_idle_t idle;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_idle_init(loop, &idle);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &idle, &fd);
+ ASSERT(r == UV_EINVAL);
+ uv_close((uv_handle_t*) &idle, NULL);
+
+ r = uv_tcp_init(loop, &tcp);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &tcp, NULL);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_udp_init(loop, &udp);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &udp, NULL);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_pipe_init(loop, &pipe, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_pipe_bind(&pipe, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &pipe, NULL);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == UV_EBADF);
+
+ tty_fd = get_tty_fd();
+ if (tty_fd < 0) {
+ fprintf(stderr, "Cannot open a TTY fd");
+ fflush(stderr);
+ } else {
+ r = uv_tty_init(loop, &tty, tty_fd, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tty, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &tty, NULL);
+ r = uv_fileno((uv_handle_t*) &tty, &fd);
+ ASSERT(r == UV_EBADF);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-homedir.c b/3rdparty/libuv/test/test-homedir.c
new file mode 100644
index 00000000000..cbc47566c55
--- /dev/null
+++ b/3rdparty/libuv/test/test-homedir.c
@@ -0,0 +1,49 @@
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+#define SMALLPATH 1
+
+TEST_IMPL(homedir) {
+ char homedir[PATHMAX];
+ size_t len;
+ char last;
+ int r;
+
+ /* Test the normal case */
+ len = sizeof homedir;
+ homedir[0] = '\0';
+ ASSERT(strlen(homedir) == 0);
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == 0);
+ ASSERT(strlen(homedir) == len);
+ ASSERT(len > 0);
+ ASSERT(homedir[len] == '\0');
+
+ if (len > 1) {
+ last = homedir[len - 1];
+#ifdef _WIN32
+ ASSERT(last != '\\');
+#else
+ ASSERT(last != '/');
+#endif
+ }
+
+ /* Test the case where the buffer is too small */
+ len = SMALLPATH;
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == UV_ENOBUFS);
+ ASSERT(len > SMALLPATH);
+
+ /* Test invalid inputs */
+ r = uv_os_homedir(NULL, &len);
+ ASSERT(r == UV_EINVAL);
+ r = uv_os_homedir(homedir, NULL);
+ ASSERT(r == UV_EINVAL);
+ len = 0;
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == UV_EINVAL);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-hrtime.c b/3rdparty/libuv/test/test-hrtime.c
new file mode 100644
index 00000000000..72a4d4b181d
--- /dev/null
+++ b/3rdparty/libuv/test/test-hrtime.c
@@ -0,0 +1,54 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifndef MILLISEC
+# define MILLISEC 1000
+#endif
+
+#ifndef NANOSEC
+# define NANOSEC ((uint64_t) 1e9)
+#endif
+
+
+TEST_IMPL(hrtime) {
+ uint64_t a, b, diff;
+ int i = 75;
+ while (i > 0) {
+ a = uv_hrtime();
+ uv_sleep(45);
+ b = uv_hrtime();
+
+ diff = b - a;
+
+ /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */
+
+ /* The windows Sleep() function has only a resolution of 10-20 ms. */
+ /* Check that the difference between the two hrtime values is somewhat in */
+ /* the range we expect it to be. */
+ ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC);
+ ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC);
+ --i;
+ }
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-idle.c b/3rdparty/libuv/test/test-idle.c
new file mode 100644
index 00000000000..f49d1964827
--- /dev/null
+++ b/3rdparty/libuv/test/test-idle.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static uv_idle_t idle_handle;
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+
+static int idle_cb_called = 0;
+static int check_cb_called = 0;
+static int timer_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+
+ uv_close((uv_handle_t*) &idle_handle, close_cb);
+ uv_close((uv_handle_t*) &check_handle, close_cb);
+ uv_close((uv_handle_t*) &timer_handle, close_cb);
+
+ timer_cb_called++;
+ fprintf(stderr, "timer_cb %d\n", timer_cb_called);
+ fflush(stderr);
+}
+
+
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(handle == &idle_handle);
+
+ idle_cb_called++;
+ fprintf(stderr, "idle_cb %d\n", idle_cb_called);
+ fflush(stderr);
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(handle == &check_handle);
+
+ check_cb_called++;
+ fprintf(stderr, "check_cb %d\n", check_cb_called);
+ fflush(stderr);
+}
+
+
+TEST_IMPL(idle_starvation) {
+ int r;
+
+ r = uv_idle_init(uv_default_loop(), &idle_handle);
+ ASSERT(r == 0);
+ r = uv_idle_start(&idle_handle, idle_cb);
+ ASSERT(r == 0);
+
+ r = uv_check_init(uv_default_loop(), &check_handle);
+ ASSERT(r == 0);
+ r = uv_check_start(&check_handle, check_cb);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, timer_cb, 50, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(idle_cb_called > 0);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ip4-addr.c b/3rdparty/libuv/test/test-ip4-addr.c
new file mode 100644
index 00000000000..3d6e0cf286a
--- /dev/null
+++ b/3rdparty/libuv/test/test-ip4-addr.c
@@ -0,0 +1,46 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+TEST_IMPL(ip4_addr) {
+
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr));
+
+ /* for broken address family */
+ ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1",
+ &addr.sin_addr.s_addr));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ip6-addr.c b/3rdparty/libuv/test/test-ip6-addr.c
new file mode 100644
index 00000000000..869b099e0fc
--- /dev/null
+++ b/3rdparty/libuv/test/test-ip6-addr.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __linux__
+# include <sys/socket.h>
+# include <net/if.h>
+#endif
+
+
+TEST_IMPL(ip6_addr_link_local) {
+ char string_address[INET6_ADDRSTRLEN];
+ uv_interface_address_t* addresses;
+ uv_interface_address_t* address;
+ struct sockaddr_in6 addr;
+ unsigned int iface_index;
+ const char* device_name;
+ /* 40 bytes address, 16 bytes device name, plus reserve. */
+ char scoped_addr[128];
+ int count;
+ int ix;
+
+ ASSERT(0 == uv_interface_addresses(&addresses, &count));
+
+ for (ix = 0; ix < count; ix++) {
+ address = addresses + ix;
+
+ if (address->address.address6.sin6_family != AF_INET6)
+ continue;
+
+ ASSERT(0 == uv_inet_ntop(AF_INET6,
+ &address->address.address6.sin6_addr,
+ string_address,
+ sizeof(string_address)));
+
+ /* Skip addresses that are not link-local. */
+ if (strncmp(string_address, "fe80::", 6) != 0)
+ continue;
+
+ iface_index = address->address.address6.sin6_scope_id;
+ device_name = address->name;
+
+#ifdef _WIN32
+ snprintf(scoped_addr,
+ sizeof(scoped_addr),
+ "%s%%%d",
+ string_address,
+ iface_index);
+#else
+ snprintf(scoped_addr,
+ sizeof(scoped_addr),
+ "%s%%%s",
+ string_address,
+ device_name);
+#endif
+
+ fprintf(stderr, "Testing link-local address %s "
+ "(iface_index: 0x%02x, device_name: %s)\n",
+ scoped_addr,
+ iface_index,
+ device_name);
+ fflush(stderr);
+
+ ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr));
+ fprintf(stderr, "Got scope_id 0x%02x\n", addr.sin6_scope_id);
+ fflush(stderr);
+ ASSERT(iface_index == addr.sin6_scope_id);
+ }
+
+ uv_free_interface_addresses(addresses, count);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#define GOOD_ADDR_LIST(X) \
+ X("::") \
+ X("::1") \
+ X("fe80::1") \
+ X("fe80::") \
+ X("fe80::2acf:daff:fedd:342a") \
+ X("fe80:0:0:0:2acf:daff:fedd:342a") \
+ X("fe80:0:0:0:2acf:daff:1.2.3.4") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") \
+
+#define BAD_ADDR_LIST(X) \
+ X(":::1") \
+ X("abcde::1") \
+ X("fe80:0:0:0:2acf:daff:fedd:342a:5678") \
+ X("fe80:0:0:0:2acf:daff:abcd:1.2.3.4") \
+ X("fe80:0:0:2acf:daff:1.2.3.4.5") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \
+
+#define TEST_GOOD(ADDR) \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
+
+#define TEST_BAD(ADDR) \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR, &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
+
+TEST_IMPL(ip6_pton) {
+ struct in6_addr addr;
+
+ GOOD_ADDR_LIST(TEST_GOOD)
+ BAD_ADDR_LIST(TEST_BAD)
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#undef GOOD_ADDR_LIST
+#undef BAD_ADDR_LIST
diff --git a/3rdparty/libuv/test/test-ipc-send-recv.c b/3rdparty/libuv/test/test-ipc-send-recv.c
new file mode 100644
index 00000000000..c445483fa08
--- /dev/null
+++ b/3rdparty/libuv/test/test-ipc-send-recv.c
@@ -0,0 +1,411 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* See test-ipc.ctx */
+void spawn_helper(uv_pipe_t* channel,
+ uv_process_t* process,
+ const char* helper);
+
+void ipc_send_recv_helper_threadproc(void* arg);
+
+union handles {
+ uv_handle_t handle;
+ uv_stream_t stream;
+ uv_pipe_t pipe;
+ uv_tcp_t tcp;
+ uv_tty_t tty;
+};
+
+struct test_ctx {
+ uv_pipe_t channel;
+ uv_connect_t connect_req;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ uv_handle_type expected_type;
+ union handles send;
+ union handles send2;
+ union handles recv;
+ union handles recv2;
+};
+
+struct echo_ctx {
+ uv_pipe_t listen;
+ uv_pipe_t channel;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ uv_handle_type expected_type;
+ union handles recv;
+ union handles recv2;
+};
+
+static struct test_ctx ctx;
+static struct echo_ctx ctx2;
+
+/* Used in write2_cb to decide if we need to cleanup or not */
+static int is_child_process;
+static int is_in_process;
+static int read_cb_called;
+static int recv_cb_called;
+static int write2_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ /* we're not actually reading anything so a small buffer is okay */
+ static char slab[8];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void recv_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_handle_type pending;
+ uv_pipe_t* pipe;
+ int r;
+ union handles* recv;
+
+ if (++recv_cb_called == 1) {
+ recv = &ctx.recv;
+ } else {
+ recv = &ctx.recv2;
+ }
+
+ pipe = (uv_pipe_t*) handle;
+ ASSERT(pipe == &ctx.channel);
+
+ /* Depending on the OS, the final recv_cb can be called after the child
+ * process has terminated which can result in nread being UV_EOF instead of
+ * the number of bytes read. Since the other end of the pipe has closed this
+ * UV_EOF is an acceptable value. */
+ if (nread == UV_EOF) {
+ /* UV_EOF is only acceptable for the final recv_cb call */
+ ASSERT(recv_cb_called == 2);
+ } else {
+ ASSERT(nread >= 0);
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(pending == ctx.expected_type);
+
+ if (pending == UV_NAMED_PIPE)
+ r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
+ else if (pending == UV_TCP)
+ r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
+ else
+ abort();
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, &recv->stream);
+ ASSERT(r == 0);
+ }
+
+ /* Close after two writes received */
+ if (recv_cb_called == 2) {
+ uv_close((uv_handle_t*)&ctx.channel, NULL);
+ }
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(req == &ctx.connect_req);
+ ASSERT(status == 0);
+
+ buf = uv_buf_init(".", 1);
+ r = uv_write2(&ctx.write_req,
+ (uv_stream_t*)&ctx.channel,
+ &buf, 1,
+ &ctx.send.stream,
+ NULL);
+ ASSERT(r == 0);
+
+ /* Perform two writes to the same pipe to make sure that on Windows we are
+ * not running into issue 505:
+ * https://github.com/libuv/libuv/issues/505 */
+ buf = uv_buf_init(".", 1);
+ r = uv_write2(&ctx.write_req2,
+ (uv_stream_t*)&ctx.channel,
+ &buf, 1,
+ &ctx.send2.stream,
+ NULL);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+}
+
+static int run_test(int inprocess) {
+ uv_process_t process;
+ uv_thread_t tid;
+ int r;
+
+ if (inprocess) {
+ r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42);
+ ASSERT(r == 0);
+
+ uv_sleep(1000);
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb);
+ } else {
+ spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
+
+ connect_cb(&ctx.connect_req, 0);
+ }
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(recv_cb_called == 2);
+
+ if (inprocess) {
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+ }
+
+ return 0;
+}
+
+static int run_ipc_send_recv_pipe(int inprocess) {
+ int r;
+
+ ctx.expected_type = UV_NAMED_PIPE;
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_send_recv_pipe) {
+ return run_ipc_send_recv_pipe(0);
+}
+
+TEST_IMPL(ipc_send_recv_pipe_inprocess) {
+ return run_ipc_send_recv_pipe(1);
+}
+
+static int run_ipc_send_recv_tcp(int inprocess) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ctx.expected_type = UV_TCP;
+
+ r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_send_recv_tcp) {
+ return run_ipc_send_recv_tcp(0);
+}
+
+TEST_IMPL(ipc_send_recv_tcp_inprocess) {
+ return run_ipc_send_recv_tcp(1);
+}
+
+
+/* Everything here runs in a child process or second thread. */
+
+static void write2_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ /* After two successful writes in the child process, allow the child
+ * process to be closed. */
+ if (++write2_cb_called == 2 && (is_child_process || is_in_process)) {
+ uv_close(&ctx2.recv.handle, NULL);
+ uv_close(&ctx2.recv2.handle, NULL);
+ uv_close((uv_handle_t*)&ctx2.channel, NULL);
+ uv_close((uv_handle_t*)&ctx2.listen, NULL);
+ }
+}
+
+static void read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rdbuf) {
+ uv_buf_t wrbuf;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+ int r;
+ union handles* recv;
+ uv_write_t* write_req;
+
+ if (nread == UV__EOF || nread == UV__ECONNABORTED) {
+ return;
+ }
+
+ if (++read_cb_called == 2) {
+ recv = &ctx2.recv;
+ write_req = &ctx2.write_req;
+ } else {
+ recv = &ctx2.recv2;
+ write_req = &ctx2.write_req2;
+ }
+
+ pipe = (uv_pipe_t*) handle;
+ ASSERT(pipe == &ctx2.channel);
+ ASSERT(nread >= 0);
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
+
+ if (pending == UV_NAMED_PIPE)
+ r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
+ else if (pending == UV_TCP)
+ r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
+ else
+ abort();
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, &recv->stream);
+ ASSERT(r == 0);
+
+ wrbuf = uv_buf_init(".", 1);
+ r = uv_write2(write_req,
+ (uv_stream_t*)&ctx2.channel,
+ &wrbuf,
+ 1,
+ &recv->stream,
+ write2_cb);
+ ASSERT(r == 0);
+}
+
+static void send_recv_start() {
+ int r;
+ ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel));
+
+ r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+static void listen_cb(uv_stream_t* handle, int status) {
+ int r;
+ ASSERT(handle == (uv_stream_t*)&ctx2.listen);
+ ASSERT(status == 0);
+
+ r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel);
+ ASSERT(r == 0);
+
+ send_recv_start();
+}
+
+int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) {
+ int r;
+
+ is_in_process = inprocess;
+
+ memset(&ctx2, 0, sizeof(ctx2));
+
+ r = uv_pipe_init(loop, &ctx2.listen, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &ctx2.channel, 1);
+ ASSERT(r == 0);
+
+ if (inprocess) {
+ r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb);
+ ASSERT(r == 0);
+ } else {
+ r = uv_pipe_open(&ctx2.channel, 0);
+ ASSERT(r == 0);
+
+ send_recv_start();
+ }
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ return 0;
+}
+
+/* stdin is a duplex channel over which a handle is sent.
+ * We receive it and send it back where it came from.
+ */
+int ipc_send_recv_helper(void) {
+ int r;
+
+ r = run_ipc_send_recv_helper(uv_default_loop(), 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+void ipc_send_recv_helper_threadproc(void* arg) {
+ int r;
+ uv_loop_t loop;
+
+ r = uv_loop_init(&loop);
+ ASSERT(r == 0);
+
+ r = run_ipc_send_recv_helper(&loop, 1);
+ ASSERT(r == 0);
+
+ r = uv_loop_close(&loop);
+ ASSERT(r == 0);
+}
diff --git a/3rdparty/libuv/test/test-ipc.c b/3rdparty/libuv/test/test-ipc.c
new file mode 100644
index 00000000000..f018c2d4d49
--- /dev/null
+++ b/3rdparty/libuv/test/test-ipc.c
@@ -0,0 +1,779 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static uv_pipe_t channel;
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_server2;
+static uv_tcp_t tcp_connection;
+
+static int exit_cb_called;
+static int read_cb_called;
+static int tcp_write_cb_called;
+static int tcp_read_cb_called;
+static int on_pipe_read_called;
+static int local_conn_accepted;
+static int remote_conn_accepted;
+static int tcp_server_listening;
+static uv_write_t write_req;
+static uv_write_t conn_notify_req;
+static int close_cb_called;
+static int connection_accepted;
+static int tcp_conn_read_cb_called;
+static int tcp_conn_write_cb_called;
+
+typedef struct {
+ uv_connect_t conn_req;
+ uv_write_t tcp_write_req;
+ uv_tcp_t conn;
+} tcp_conn;
+
+#define CONN_COUNT 100
+#define BACKLOG 128
+
+
+static void close_server_conn_cb(uv_handle_t* handle) {
+ free(handle);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_tcp_t* conn;
+ int r;
+
+ if (!local_conn_accepted) {
+ /* Accept the connection and close it. Also and close the server. */
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+ r = uv_tcp_init(server->loop, conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_server_conn_cb);
+ uv_close((uv_handle_t*)server, NULL);
+ local_conn_accepted = 1;
+ }
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 0);
+ uv_close((uv_handle_t*)process, NULL);
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void close_client_conn_cb(uv_handle_t* handle) {
+ tcp_conn* p = (tcp_conn*)handle->data;
+ free(p);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_close((uv_handle_t*)req->handle, close_client_conn_cb);
+}
+
+
+static void make_many_connections(void) {
+ tcp_conn* conn;
+ struct sockaddr_in addr;
+ int r, i;
+
+ for (i = 0; i < CONN_COUNT; i++) {
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+
+ r = uv_tcp_init(uv_default_loop(), &conn->conn);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn->conn_req,
+ (uv_tcp_t*) &conn->conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ conn->conn.data = conn;
+ }
+}
+
+
+static void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+ uv_buf_t outbuf;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ pending = uv_pipe_pending_type(pipe);
+ if (!tcp_server_listening) {
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ ASSERT(r == 0);
+
+ tcp_server_listening = 1;
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL);
+ ASSERT(r == 0);
+
+ /* Create a bunch of connections to get both servers to accept. */
+ make_many_connections();
+ } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) {
+ /* Remote server has accepted a connection. Close the channel. */
+ ASSERT(0 == uv_pipe_pending_count(pipe));
+ ASSERT(pending == UV_UNKNOWN_HANDLE);
+ remote_conn_accepted = 1;
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+
+#ifdef _WIN32
+static void on_read_listen_after_bound_twice(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ ASSERT(uv_pipe_pending_count(pipe) > 0);
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ if (read_cb_called == 1) {
+ /* Accept the first TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ ASSERT(r == 0);
+ } else if (read_cb_called == 2) {
+ /* Accept the second TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&tcp_server, NULL);
+ uv_close((uv_handle_t*)&tcp_server2, NULL);
+ ASSERT(0 == uv_pipe_pending_count(pipe));
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+#endif
+
+void spawn_helper(uv_pipe_t* channel,
+ uv_process_t* process,
+ const char* helper) {
+ uv_process_options_t options;
+ size_t exepath_size;
+ char exepath[1024];
+ char* args[3];
+ int r;
+ uv_stdio_container_t stdio[1];
+
+ r = uv_pipe_init(uv_default_loop(), channel, 1);
+ ASSERT(r == 0);
+ ASSERT(channel->ipc);
+
+ exepath_size = sizeof(exepath);
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = (char*)helper;
+ args[2] = NULL;
+
+ memset(&options, 0, sizeof(options));
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE |
+ UV_READABLE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)channel;
+ options.stdio_count = 1;
+
+ r = uv_spawn(uv_default_loop(), process, &options);
+ ASSERT(r == 0);
+}
+
+
+static void on_tcp_write(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req->handle == (uv_stream_t*)&tcp_connection);
+ tcp_write_cb_called++;
+}
+
+
+static void on_read_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(memcmp("hello again\n", buf->base, nread) == 0);
+ ASSERT(tcp == (uv_stream_t*)&tcp_connection);
+ free(buf->base);
+
+ tcp_read_cb_called++;
+
+ uv_close((uv_handle_t*)tcp, NULL);
+ uv_close((uv_handle_t*)&channel, NULL);
+}
+
+
+static void on_read_connection(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_buf_t outbuf;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+ pending = uv_pipe_pending_type(pipe);
+
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP connection */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_connection);
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, (uv_stream_t*)&tcp_connection);
+ ASSERT(r == 0);
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ /* Write/read to/from the connection */
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1,
+ on_tcp_write);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read);
+ ASSERT(r == 0);
+
+ free(buf->base);
+}
+
+
+static int run_ipc_test(const char* helper, uv_read_cb read_cb) {
+ uv_process_t process;
+ int r;
+
+ spawn_helper(&channel, &process, helper);
+ uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(ipc_listen_before_write) {
+ int r = run_ipc_test("ipc_helper_listen_before_write", on_read);
+ ASSERT(local_conn_accepted == 1);
+ ASSERT(remote_conn_accepted == 1);
+ ASSERT(read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_listen_after_write) {
+ int r = run_ipc_test("ipc_helper_listen_after_write", on_read);
+ ASSERT(local_conn_accepted == 1);
+ ASSERT(remote_conn_accepted == 1);
+ ASSERT(read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_tcp_connection) {
+ int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection);
+ ASSERT(read_cb_called == 1);
+ ASSERT(tcp_write_cb_called == 1);
+ ASSERT(tcp_read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(listen_with_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 1);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ ASSERT(server.reqs_pending == 32);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(listen_no_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ ASSERT(server.reqs_pending == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_listen_after_bind_twice) {
+ int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice);
+ ASSERT(read_cb_called == 2);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+#endif
+
+
+/* Everything here runs in a child process. */
+
+static tcp_conn conn;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void conn_notify_write_cb(uv_write_t* req, int status) {
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+}
+
+
+static void tcp_connection_write_cb(uv_write_t* req, int status) {
+ ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ tcp_conn_write_cb_called++;
+}
+
+
+static void on_tcp_child_process_read(uv_stream_t* tcp,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_buf_t outbuf;
+ int r;
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on tcp connection: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ ASSERT(nread > 0);
+ ASSERT(memcmp("world\n", buf->base, nread) == 0);
+ on_pipe_read_called++;
+ free(buf->base);
+
+ /* Write to the socket */
+ outbuf = uv_buf_init("hello again\n", 12);
+ r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb);
+ ASSERT(r == 0);
+
+ tcp_conn_read_cb_called++;
+}
+
+
+static void connect_child_process_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read);
+ ASSERT(r == 0);
+}
+
+
+static void ipc_on_connection(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+
+ if (!connection_accepted) {
+ /*
+ * Accept the connection and close it. Also let the other
+ * side know.
+ */
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ r = uv_tcp_init(server->loop, &conn.conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)&conn.conn);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&conn.conn, close_cb);
+
+ buf = uv_buf_init("accepted_connection\n", 20);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ NULL, conn_notify_write_cb);
+ ASSERT(r == 0);
+
+ connection_accepted = 1;
+ }
+}
+
+
+static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+ uv_tcp_t* conn;
+
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+
+ r = uv_tcp_init(server->loop, conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ /* Send the accepted connection to the other process */
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)conn, NULL);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) conn,
+ on_read_alloc,
+ on_tcp_child_process_read);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_cb);
+}
+
+
+int ipc_helper(int listen_after_write) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel that we
+ * over which a handle will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ if (!listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ ASSERT(r == 0);
+ }
+
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ ASSERT(r == 0);
+
+ if (listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ ASSERT(r == 0);
+ }
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connection_accepted == 1);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+int ipc_helper_tcp_connection(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which a handle will be transmitted.
+ */
+
+ int r;
+ struct sockaddr_in addr;
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn);
+ ASSERT(r == 0);
+
+ /* Make a connection to the server */
+ r = uv_tcp_init(uv_default_loop(), &conn.conn);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn.conn_req,
+ (uv_tcp_t*) &conn.conn,
+ (const struct sockaddr*) &addr,
+ connect_child_process_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(tcp_conn_read_cb_called == 1);
+ ASSERT(tcp_conn_write_cb_called == 1);
+ ASSERT(close_cb_called == 4);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+int ipc_helper_bind_twice(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which two handles will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ buf = uv_buf_init("hello\n", 6);
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ ASSERT(r == 0);
+ r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server2, NULL);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-list.h b/3rdparty/libuv/test/test-list.h
new file mode 100644
index 00000000000..858a20af49c
--- /dev/null
+++ b/3rdparty/libuv/test/test-list.h
@@ -0,0 +1,732 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+TEST_DECLARE (platform_output)
+TEST_DECLARE (callback_order)
+TEST_DECLARE (close_order)
+TEST_DECLARE (run_once)
+TEST_DECLARE (run_nowait)
+TEST_DECLARE (loop_alive)
+TEST_DECLARE (loop_close)
+TEST_DECLARE (loop_stop)
+TEST_DECLARE (loop_update_time)
+TEST_DECLARE (loop_backend_timeout)
+TEST_DECLARE (loop_configure)
+TEST_DECLARE (default_loop_close)
+TEST_DECLARE (barrier_1)
+TEST_DECLARE (barrier_2)
+TEST_DECLARE (barrier_3)
+TEST_DECLARE (condvar_1)
+TEST_DECLARE (condvar_2)
+TEST_DECLARE (condvar_3)
+TEST_DECLARE (condvar_4)
+TEST_DECLARE (condvar_5)
+TEST_DECLARE (semaphore_1)
+TEST_DECLARE (semaphore_2)
+TEST_DECLARE (semaphore_3)
+TEST_DECLARE (tty)
+TEST_DECLARE (tty_file)
+TEST_DECLARE (stdio_over_pipes)
+TEST_DECLARE (ip6_pton)
+TEST_DECLARE (ipc_listen_before_write)
+TEST_DECLARE (ipc_listen_after_write)
+#ifndef _WIN32
+TEST_DECLARE (ipc_send_recv_pipe)
+TEST_DECLARE (ipc_send_recv_pipe_inprocess)
+#endif
+TEST_DECLARE (ipc_send_recv_tcp)
+TEST_DECLARE (ipc_send_recv_tcp_inprocess)
+TEST_DECLARE (ipc_tcp_connection)
+TEST_DECLARE (tcp_ping_pong)
+TEST_DECLARE (tcp_ping_pong_v6)
+TEST_DECLARE (pipe_ping_pong)
+TEST_DECLARE (delayed_accept)
+TEST_DECLARE (multiple_listen)
+#ifndef _WIN32
+TEST_DECLARE (tcp_write_after_connect)
+#endif
+TEST_DECLARE (tcp_writealot)
+TEST_DECLARE (tcp_write_fail)
+TEST_DECLARE (tcp_try_write)
+TEST_DECLARE (tcp_write_queue_order)
+TEST_DECLARE (tcp_open)
+TEST_DECLARE (tcp_open_twice)
+TEST_DECLARE (tcp_connect_error_after_write)
+TEST_DECLARE (tcp_shutdown_after_write)
+TEST_DECLARE (tcp_bind_error_addrinuse)
+TEST_DECLARE (tcp_bind_error_addrnotavail_1)
+TEST_DECLARE (tcp_bind_error_addrnotavail_2)
+TEST_DECLARE (tcp_bind_error_fault)
+TEST_DECLARE (tcp_bind_error_inval)
+TEST_DECLARE (tcp_bind_localhost_ok)
+TEST_DECLARE (tcp_bind_invalid_flags)
+TEST_DECLARE (tcp_listen_without_bind)
+TEST_DECLARE (tcp_connect_error_fault)
+TEST_DECLARE (tcp_connect_timeout)
+TEST_DECLARE (tcp_close_while_connecting)
+TEST_DECLARE (tcp_close)
+TEST_DECLARE (tcp_create_early)
+TEST_DECLARE (tcp_create_early_bad_bind)
+TEST_DECLARE (tcp_create_early_bad_domain)
+TEST_DECLARE (tcp_create_early_accept)
+#ifndef _WIN32
+TEST_DECLARE (tcp_close_accept)
+TEST_DECLARE (tcp_oob)
+#endif
+TEST_DECLARE (tcp_flags)
+TEST_DECLARE (tcp_write_to_half_open_connection)
+TEST_DECLARE (tcp_unexpected_read)
+TEST_DECLARE (tcp_read_stop)
+TEST_DECLARE (tcp_bind6_error_addrinuse)
+TEST_DECLARE (tcp_bind6_error_addrnotavail)
+TEST_DECLARE (tcp_bind6_error_fault)
+TEST_DECLARE (tcp_bind6_error_inval)
+TEST_DECLARE (tcp_bind6_localhost_ok)
+TEST_DECLARE (udp_bind)
+TEST_DECLARE (udp_bind_reuseaddr)
+TEST_DECLARE (udp_create_early)
+TEST_DECLARE (udp_create_early_bad_bind)
+TEST_DECLARE (udp_create_early_bad_domain)
+TEST_DECLARE (udp_send_and_recv)
+TEST_DECLARE (udp_send_immediate)
+TEST_DECLARE (udp_send_unreachable)
+TEST_DECLARE (udp_multicast_join)
+TEST_DECLARE (udp_multicast_join6)
+TEST_DECLARE (udp_multicast_ttl)
+TEST_DECLARE (udp_multicast_interface)
+TEST_DECLARE (udp_multicast_interface6)
+TEST_DECLARE (udp_dgram_too_big)
+TEST_DECLARE (udp_dual_stack)
+TEST_DECLARE (udp_ipv6_only)
+TEST_DECLARE (udp_options)
+TEST_DECLARE (udp_options6)
+TEST_DECLARE (udp_no_autobind)
+TEST_DECLARE (udp_open)
+TEST_DECLARE (udp_open_twice)
+TEST_DECLARE (udp_try_send)
+TEST_DECLARE (pipe_bind_error_addrinuse)
+TEST_DECLARE (pipe_bind_error_addrnotavail)
+TEST_DECLARE (pipe_bind_error_inval)
+TEST_DECLARE (pipe_connect_multiple)
+TEST_DECLARE (pipe_listen_without_bind)
+TEST_DECLARE (pipe_connect_bad_name)
+TEST_DECLARE (pipe_connect_to_file)
+TEST_DECLARE (pipe_connect_on_prepare)
+TEST_DECLARE (pipe_getsockname)
+TEST_DECLARE (pipe_getsockname_abstract)
+TEST_DECLARE (pipe_getsockname_blocking)
+TEST_DECLARE (pipe_pending_instances)
+TEST_DECLARE (pipe_sendmsg)
+TEST_DECLARE (pipe_server_close)
+TEST_DECLARE (connection_fail)
+TEST_DECLARE (connection_fail_doesnt_auto_close)
+TEST_DECLARE (shutdown_close_tcp)
+TEST_DECLARE (shutdown_close_pipe)
+TEST_DECLARE (shutdown_eof)
+TEST_DECLARE (shutdown_twice)
+TEST_DECLARE (callback_stack)
+TEST_DECLARE (error_message)
+TEST_DECLARE (timer)
+TEST_DECLARE (timer_init)
+TEST_DECLARE (timer_again)
+TEST_DECLARE (timer_start_twice)
+TEST_DECLARE (timer_order)
+TEST_DECLARE (timer_huge_timeout)
+TEST_DECLARE (timer_huge_repeat)
+TEST_DECLARE (timer_run_once)
+TEST_DECLARE (timer_from_check)
+TEST_DECLARE (timer_null_callback)
+TEST_DECLARE (idle_starvation)
+TEST_DECLARE (loop_handles)
+TEST_DECLARE (get_loadavg)
+TEST_DECLARE (walk_handles)
+TEST_DECLARE (watcher_cross_stop)
+TEST_DECLARE (ref)
+TEST_DECLARE (idle_ref)
+TEST_DECLARE (async_ref)
+TEST_DECLARE (prepare_ref)
+TEST_DECLARE (check_ref)
+TEST_DECLARE (unref_in_prepare_cb)
+TEST_DECLARE (timer_ref)
+TEST_DECLARE (timer_ref2)
+TEST_DECLARE (fs_event_ref)
+TEST_DECLARE (fs_poll_ref)
+TEST_DECLARE (tcp_ref)
+TEST_DECLARE (tcp_ref2)
+TEST_DECLARE (tcp_ref2b)
+TEST_DECLARE (tcp_ref3)
+TEST_DECLARE (tcp_ref4)
+TEST_DECLARE (udp_ref)
+TEST_DECLARE (udp_ref2)
+TEST_DECLARE (udp_ref3)
+TEST_DECLARE (pipe_ref)
+TEST_DECLARE (pipe_ref2)
+TEST_DECLARE (pipe_ref3)
+TEST_DECLARE (pipe_ref4)
+#ifndef _WIN32
+TEST_DECLARE (pipe_close_stdout_read_stdin)
+#endif
+TEST_DECLARE (pipe_set_non_blocking)
+TEST_DECLARE (process_ref)
+TEST_DECLARE (has_ref)
+TEST_DECLARE (active)
+TEST_DECLARE (embed)
+TEST_DECLARE (async)
+TEST_DECLARE (async_null_cb)
+TEST_DECLARE (get_currentexe)
+TEST_DECLARE (process_title)
+TEST_DECLARE (cwd_and_chdir)
+TEST_DECLARE (get_memory)
+TEST_DECLARE (handle_fileno)
+TEST_DECLARE (homedir)
+TEST_DECLARE (hrtime)
+TEST_DECLARE (getaddrinfo_fail)
+TEST_DECLARE (getaddrinfo_fail_sync)
+TEST_DECLARE (getaddrinfo_basic)
+TEST_DECLARE (getaddrinfo_basic_sync)
+TEST_DECLARE (getaddrinfo_concurrent)
+TEST_DECLARE (getnameinfo_basic_ip4)
+TEST_DECLARE (getnameinfo_basic_ip4_sync)
+TEST_DECLARE (getnameinfo_basic_ip6)
+TEST_DECLARE (getsockname_tcp)
+TEST_DECLARE (getsockname_udp)
+TEST_DECLARE (fail_always)
+TEST_DECLARE (pass_always)
+TEST_DECLARE (socket_buffer_size)
+TEST_DECLARE (spawn_fails)
+#ifndef _WIN32
+TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup)
+#endif
+TEST_DECLARE (spawn_exit_code)
+TEST_DECLARE (spawn_stdout)
+TEST_DECLARE (spawn_stdin)
+TEST_DECLARE (spawn_stdio_greater_than_3)
+TEST_DECLARE (spawn_ignored_stdio)
+TEST_DECLARE (spawn_and_kill)
+TEST_DECLARE (spawn_detached)
+TEST_DECLARE (spawn_and_kill_with_std)
+TEST_DECLARE (spawn_and_ping)
+TEST_DECLARE (spawn_preserve_env)
+TEST_DECLARE (spawn_setuid_fails)
+TEST_DECLARE (spawn_setgid_fails)
+TEST_DECLARE (spawn_stdout_to_file)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file2)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file_swap)
+TEST_DECLARE (spawn_auto_unref)
+TEST_DECLARE (spawn_closed_process_io)
+TEST_DECLARE (spawn_reads_child_path)
+TEST_DECLARE (spawn_inherit_streams)
+TEST_DECLARE (fs_poll)
+TEST_DECLARE (fs_poll_getpath)
+TEST_DECLARE (kill)
+TEST_DECLARE (fs_file_noent)
+TEST_DECLARE (fs_file_nametoolong)
+TEST_DECLARE (fs_file_loop)
+TEST_DECLARE (fs_file_async)
+TEST_DECLARE (fs_file_sync)
+TEST_DECLARE (fs_file_write_null_buffer)
+TEST_DECLARE (fs_async_dir)
+TEST_DECLARE (fs_async_sendfile)
+TEST_DECLARE (fs_mkdtemp)
+TEST_DECLARE (fs_fstat)
+TEST_DECLARE (fs_access)
+TEST_DECLARE (fs_chmod)
+TEST_DECLARE (fs_unlink_readonly)
+TEST_DECLARE (fs_chown)
+TEST_DECLARE (fs_link)
+TEST_DECLARE (fs_readlink)
+TEST_DECLARE (fs_realpath)
+TEST_DECLARE (fs_symlink)
+TEST_DECLARE (fs_symlink_dir)
+TEST_DECLARE (fs_utime)
+TEST_DECLARE (fs_futime)
+TEST_DECLARE (fs_file_open_append)
+TEST_DECLARE (fs_stat_missing_path)
+TEST_DECLARE (fs_read_file_eof)
+TEST_DECLARE (fs_event_watch_dir)
+TEST_DECLARE (fs_event_watch_dir_recursive)
+TEST_DECLARE (fs_event_watch_file)
+TEST_DECLARE (fs_event_watch_file_twice)
+TEST_DECLARE (fs_event_watch_file_current_dir)
+TEST_DECLARE (fs_event_no_callback_after_close)
+TEST_DECLARE (fs_event_no_callback_on_close)
+TEST_DECLARE (fs_event_immediate_close)
+TEST_DECLARE (fs_event_close_with_pending_event)
+TEST_DECLARE (fs_event_close_in_callback)
+TEST_DECLARE (fs_event_start_and_close)
+TEST_DECLARE (fs_event_error_reporting)
+TEST_DECLARE (fs_event_getpath)
+TEST_DECLARE (fs_scandir_empty_dir)
+TEST_DECLARE (fs_scandir_file)
+TEST_DECLARE (fs_open_dir)
+TEST_DECLARE (fs_rename_to_existing_file)
+TEST_DECLARE (fs_write_multiple_bufs)
+TEST_DECLARE (fs_read_write_null_arguments)
+TEST_DECLARE (fs_write_alotof_bufs)
+TEST_DECLARE (fs_write_alotof_bufs_with_offset)
+TEST_DECLARE (threadpool_queue_work_simple)
+TEST_DECLARE (threadpool_queue_work_einval)
+TEST_DECLARE (threadpool_multiple_event_loops)
+TEST_DECLARE (threadpool_cancel_getaddrinfo)
+TEST_DECLARE (threadpool_cancel_getnameinfo)
+TEST_DECLARE (threadpool_cancel_work)
+TEST_DECLARE (threadpool_cancel_fs)
+TEST_DECLARE (threadpool_cancel_single)
+TEST_DECLARE (thread_local_storage)
+TEST_DECLARE (thread_mutex)
+TEST_DECLARE (thread_rwlock)
+TEST_DECLARE (thread_rwlock_trylock)
+TEST_DECLARE (thread_create)
+TEST_DECLARE (thread_equal)
+TEST_DECLARE (dlerror)
+TEST_DECLARE (poll_duplex)
+TEST_DECLARE (poll_unidirectional)
+TEST_DECLARE (poll_close)
+
+TEST_DECLARE (ip4_addr)
+TEST_DECLARE (ip6_addr_link_local)
+
+#ifdef _WIN32
+TEST_DECLARE (poll_close_doesnt_corrupt_stack)
+TEST_DECLARE (poll_closesocket)
+TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
+TEST_DECLARE (argument_escaping)
+TEST_DECLARE (environment_creation)
+#endif
+TEST_DECLARE (listen_with_simultaneous_accepts)
+TEST_DECLARE (listen_no_simultaneous_accepts)
+TEST_DECLARE (fs_stat_root)
+TEST_DECLARE (spawn_with_an_odd_path)
+TEST_DECLARE (ipc_listen_after_bind_twice)
+#else
+TEST_DECLARE (emfile)
+TEST_DECLARE (close_fd)
+TEST_DECLARE (spawn_fs_open)
+TEST_DECLARE (spawn_setuid_setgid)
+TEST_DECLARE (we_get_signal)
+TEST_DECLARE (we_get_signals)
+TEST_DECLARE (signal_multiple_loops)
+TEST_DECLARE (closed_fd_events)
+#endif
+#ifdef __APPLE__
+TEST_DECLARE (osx_select)
+TEST_DECLARE (osx_select_many_fds)
+#endif
+HELPER_DECLARE (tcp4_echo_server)
+HELPER_DECLARE (tcp6_echo_server)
+HELPER_DECLARE (udp4_echo_server)
+HELPER_DECLARE (pipe_echo_server)
+
+TEST_DECLARE (queue_foreach_delete)
+
+TASK_LIST_START
+ TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)
+
+#if 0
+ TEST_ENTRY (callback_order)
+#endif
+ TEST_ENTRY (close_order)
+ TEST_ENTRY (run_once)
+ TEST_ENTRY (run_nowait)
+ TEST_ENTRY (loop_alive)
+ TEST_ENTRY (loop_close)
+ TEST_ENTRY (loop_stop)
+ TEST_ENTRY (loop_update_time)
+ TEST_ENTRY (loop_backend_timeout)
+ TEST_ENTRY (loop_configure)
+ TEST_ENTRY (default_loop_close)
+ TEST_ENTRY (barrier_1)
+ TEST_ENTRY (barrier_2)
+ TEST_ENTRY (barrier_3)
+ TEST_ENTRY (condvar_1)
+ TEST_ENTRY (condvar_2)
+ TEST_ENTRY (condvar_3)
+ TEST_ENTRY (condvar_4)
+ TEST_ENTRY (condvar_5)
+ TEST_ENTRY (semaphore_1)
+ TEST_ENTRY (semaphore_2)
+ TEST_ENTRY (semaphore_3)
+
+ TEST_ENTRY (pipe_connect_bad_name)
+ TEST_ENTRY (pipe_connect_to_file)
+ TEST_ENTRY (pipe_connect_on_prepare)
+
+ TEST_ENTRY (pipe_server_close)
+#ifndef _WIN32
+ TEST_ENTRY (pipe_close_stdout_read_stdin)
+#endif
+ TEST_ENTRY (pipe_set_non_blocking)
+ TEST_ENTRY (tty)
+ TEST_ENTRY (tty_file)
+ TEST_ENTRY (stdio_over_pipes)
+ TEST_ENTRY (ip6_pton)
+ TEST_ENTRY (ipc_listen_before_write)
+ TEST_ENTRY (ipc_listen_after_write)
+#ifndef _WIN32
+ TEST_ENTRY (ipc_send_recv_pipe)
+ TEST_ENTRY (ipc_send_recv_pipe_inprocess)
+#endif
+ TEST_ENTRY (ipc_send_recv_tcp)
+ TEST_ENTRY (ipc_send_recv_tcp_inprocess)
+ TEST_ENTRY (ipc_tcp_connection)
+
+ TEST_ENTRY (tcp_ping_pong)
+ TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_ping_pong_v6)
+ TEST_HELPER (tcp_ping_pong_v6, tcp6_echo_server)
+
+ TEST_ENTRY (pipe_ping_pong)
+ TEST_HELPER (pipe_ping_pong, pipe_echo_server)
+
+ TEST_ENTRY (delayed_accept)
+ TEST_ENTRY (multiple_listen)
+
+#ifndef _WIN32
+ TEST_ENTRY (tcp_write_after_connect)
+#endif
+
+ TEST_ENTRY (tcp_writealot)
+ TEST_HELPER (tcp_writealot, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_write_fail)
+ TEST_HELPER (tcp_write_fail, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_try_write)
+
+ TEST_ENTRY (tcp_write_queue_order)
+
+ TEST_ENTRY (tcp_open)
+ TEST_HELPER (tcp_open, tcp4_echo_server)
+ TEST_ENTRY (tcp_open_twice)
+
+ TEST_ENTRY (tcp_shutdown_after_write)
+ TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_connect_error_after_write)
+ TEST_ENTRY (tcp_bind_error_addrinuse)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_1)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_2)
+ TEST_ENTRY (tcp_bind_error_fault)
+ TEST_ENTRY (tcp_bind_error_inval)
+ TEST_ENTRY (tcp_bind_localhost_ok)
+ TEST_ENTRY (tcp_bind_invalid_flags)
+ TEST_ENTRY (tcp_listen_without_bind)
+ TEST_ENTRY (tcp_connect_error_fault)
+ TEST_ENTRY (tcp_connect_timeout)
+ TEST_ENTRY (tcp_close_while_connecting)
+ TEST_ENTRY (tcp_close)
+ TEST_ENTRY (tcp_create_early)
+ TEST_ENTRY (tcp_create_early_bad_bind)
+ TEST_ENTRY (tcp_create_early_bad_domain)
+ TEST_ENTRY (tcp_create_early_accept)
+#ifndef _WIN32
+ TEST_ENTRY (tcp_close_accept)
+ TEST_ENTRY (tcp_oob)
+#endif
+ TEST_ENTRY (tcp_flags)
+ TEST_ENTRY (tcp_write_to_half_open_connection)
+ TEST_ENTRY (tcp_unexpected_read)
+
+ TEST_ENTRY (tcp_read_stop)
+ TEST_HELPER (tcp_read_stop, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_bind6_error_addrinuse)
+ TEST_ENTRY (tcp_bind6_error_addrnotavail)
+ TEST_ENTRY (tcp_bind6_error_fault)
+ TEST_ENTRY (tcp_bind6_error_inval)
+ TEST_ENTRY (tcp_bind6_localhost_ok)
+
+ TEST_ENTRY (udp_bind)
+ TEST_ENTRY (udp_bind_reuseaddr)
+ TEST_ENTRY (udp_create_early)
+ TEST_ENTRY (udp_create_early_bad_bind)
+ TEST_ENTRY (udp_create_early_bad_domain)
+ TEST_ENTRY (udp_send_and_recv)
+ TEST_ENTRY (udp_send_immediate)
+ TEST_ENTRY (udp_send_unreachable)
+ TEST_ENTRY (udp_dgram_too_big)
+ TEST_ENTRY (udp_dual_stack)
+ TEST_ENTRY (udp_ipv6_only)
+ TEST_ENTRY (udp_options)
+ TEST_ENTRY (udp_options6)
+ TEST_ENTRY (udp_no_autobind)
+ TEST_ENTRY (udp_multicast_interface)
+ TEST_ENTRY (udp_multicast_interface6)
+ TEST_ENTRY (udp_multicast_join)
+ TEST_ENTRY (udp_multicast_join6)
+ TEST_ENTRY (udp_multicast_ttl)
+ TEST_ENTRY (udp_try_send)
+
+ TEST_ENTRY (udp_open)
+ TEST_HELPER (udp_open, udp4_echo_server)
+ TEST_ENTRY (udp_open_twice)
+
+ TEST_ENTRY (pipe_bind_error_addrinuse)
+ TEST_ENTRY (pipe_bind_error_addrnotavail)
+ TEST_ENTRY (pipe_bind_error_inval)
+ TEST_ENTRY (pipe_connect_multiple)
+ TEST_ENTRY (pipe_listen_without_bind)
+ TEST_ENTRY (pipe_getsockname)
+ TEST_ENTRY (pipe_getsockname_abstract)
+ TEST_ENTRY (pipe_getsockname_blocking)
+ TEST_ENTRY (pipe_pending_instances)
+ TEST_ENTRY (pipe_sendmsg)
+
+ TEST_ENTRY (connection_fail)
+ TEST_ENTRY (connection_fail_doesnt_auto_close)
+
+ TEST_ENTRY (shutdown_close_tcp)
+ TEST_HELPER (shutdown_close_tcp, tcp4_echo_server)
+ TEST_ENTRY (shutdown_close_pipe)
+ TEST_HELPER (shutdown_close_pipe, pipe_echo_server)
+
+ TEST_ENTRY (shutdown_eof)
+ TEST_HELPER (shutdown_eof, tcp4_echo_server)
+
+ TEST_ENTRY (shutdown_twice)
+ TEST_HELPER (shutdown_twice, tcp4_echo_server)
+
+ TEST_ENTRY (callback_stack)
+ TEST_HELPER (callback_stack, tcp4_echo_server)
+
+ TEST_ENTRY (error_message)
+
+ TEST_ENTRY (timer)
+ TEST_ENTRY (timer_init)
+ TEST_ENTRY (timer_again)
+ TEST_ENTRY (timer_start_twice)
+ TEST_ENTRY (timer_order)
+ TEST_ENTRY (timer_huge_timeout)
+ TEST_ENTRY (timer_huge_repeat)
+ TEST_ENTRY (timer_run_once)
+ TEST_ENTRY (timer_from_check)
+ TEST_ENTRY (timer_null_callback)
+
+ TEST_ENTRY (idle_starvation)
+
+ TEST_ENTRY (ref)
+ TEST_ENTRY (idle_ref)
+ TEST_ENTRY (fs_poll_ref)
+ TEST_ENTRY (async_ref)
+ TEST_ENTRY (prepare_ref)
+ TEST_ENTRY (check_ref)
+ TEST_ENTRY (unref_in_prepare_cb)
+ TEST_ENTRY (timer_ref)
+ TEST_ENTRY (timer_ref2)
+ TEST_ENTRY (fs_event_ref)
+ TEST_ENTRY (tcp_ref)
+ TEST_ENTRY (tcp_ref2)
+ TEST_ENTRY (tcp_ref2b)
+ TEST_ENTRY (tcp_ref3)
+ TEST_HELPER (tcp_ref3, tcp4_echo_server)
+ TEST_ENTRY (tcp_ref4)
+ TEST_HELPER (tcp_ref4, tcp4_echo_server)
+ TEST_ENTRY (udp_ref)
+ TEST_ENTRY (udp_ref2)
+ TEST_ENTRY (udp_ref3)
+ TEST_HELPER (udp_ref3, udp4_echo_server)
+ TEST_ENTRY (pipe_ref)
+ TEST_ENTRY (pipe_ref2)
+ TEST_ENTRY (pipe_ref3)
+ TEST_HELPER (pipe_ref3, pipe_echo_server)
+ TEST_ENTRY (pipe_ref4)
+ TEST_HELPER (pipe_ref4, pipe_echo_server)
+ TEST_ENTRY (process_ref)
+ TEST_ENTRY (has_ref)
+
+ TEST_ENTRY (loop_handles)
+ TEST_ENTRY (walk_handles)
+
+ TEST_ENTRY (watcher_cross_stop)
+
+ TEST_ENTRY (active)
+
+ TEST_ENTRY (embed)
+
+ TEST_ENTRY (async)
+ TEST_ENTRY (async_null_cb)
+
+ TEST_ENTRY (get_currentexe)
+
+ TEST_ENTRY (process_title)
+
+ TEST_ENTRY (cwd_and_chdir)
+
+ TEST_ENTRY (get_memory)
+
+ TEST_ENTRY (get_loadavg)
+
+ TEST_ENTRY (handle_fileno)
+
+ TEST_ENTRY (homedir)
+
+ TEST_ENTRY (hrtime)
+
+ TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
+ TEST_ENTRY (getaddrinfo_fail_sync)
+
+ TEST_ENTRY (getaddrinfo_basic)
+ TEST_ENTRY (getaddrinfo_basic_sync)
+ TEST_ENTRY (getaddrinfo_concurrent)
+
+ TEST_ENTRY (getnameinfo_basic_ip4)
+ TEST_ENTRY (getnameinfo_basic_ip4_sync)
+ TEST_ENTRY (getnameinfo_basic_ip6)
+
+ TEST_ENTRY (getsockname_tcp)
+ TEST_ENTRY (getsockname_udp)
+
+ TEST_ENTRY (poll_duplex)
+ TEST_ENTRY (poll_unidirectional)
+ TEST_ENTRY (poll_close)
+
+ TEST_ENTRY (socket_buffer_size)
+
+ TEST_ENTRY (spawn_fails)
+#ifndef _WIN32
+ TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup)
+#endif
+ TEST_ENTRY (spawn_exit_code)
+ TEST_ENTRY (spawn_stdout)
+ TEST_ENTRY (spawn_stdin)
+ TEST_ENTRY (spawn_stdio_greater_than_3)
+ TEST_ENTRY (spawn_ignored_stdio)
+ TEST_ENTRY (spawn_and_kill)
+ TEST_ENTRY (spawn_detached)
+ TEST_ENTRY (spawn_and_kill_with_std)
+ TEST_ENTRY (spawn_and_ping)
+ TEST_ENTRY (spawn_preserve_env)
+ TEST_ENTRY (spawn_setuid_fails)
+ TEST_ENTRY (spawn_setgid_fails)
+ TEST_ENTRY (spawn_stdout_to_file)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file2)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file_swap)
+ TEST_ENTRY (spawn_auto_unref)
+ TEST_ENTRY (spawn_closed_process_io)
+ TEST_ENTRY (spawn_reads_child_path)
+ TEST_ENTRY (spawn_inherit_streams)
+ TEST_ENTRY (fs_poll)
+ TEST_ENTRY (fs_poll_getpath)
+ TEST_ENTRY (kill)
+
+#ifdef _WIN32
+ TEST_ENTRY (poll_close_doesnt_corrupt_stack)
+ TEST_ENTRY (poll_closesocket)
+ TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
+ TEST_ENTRY (argument_escaping)
+ TEST_ENTRY (environment_creation)
+# endif
+ TEST_ENTRY (listen_with_simultaneous_accepts)
+ TEST_ENTRY (listen_no_simultaneous_accepts)
+ TEST_ENTRY (fs_stat_root)
+ TEST_ENTRY (spawn_with_an_odd_path)
+ TEST_ENTRY (ipc_listen_after_bind_twice)
+#else
+ TEST_ENTRY (emfile)
+ TEST_ENTRY (close_fd)
+ TEST_ENTRY (spawn_fs_open)
+ TEST_ENTRY (spawn_setuid_setgid)
+ TEST_ENTRY (we_get_signal)
+ TEST_ENTRY (we_get_signals)
+ TEST_ENTRY (signal_multiple_loops)
+ TEST_ENTRY (closed_fd_events)
+#endif
+
+#ifdef __APPLE__
+ TEST_ENTRY (osx_select)
+ TEST_ENTRY (osx_select_many_fds)
+#endif
+
+ TEST_ENTRY (fs_file_noent)
+ TEST_ENTRY (fs_file_nametoolong)
+ TEST_ENTRY (fs_file_loop)
+ TEST_ENTRY (fs_file_async)
+ TEST_ENTRY (fs_file_sync)
+ TEST_ENTRY (fs_file_write_null_buffer)
+ TEST_ENTRY (fs_async_dir)
+ TEST_ENTRY (fs_async_sendfile)
+ TEST_ENTRY (fs_mkdtemp)
+ TEST_ENTRY (fs_fstat)
+ TEST_ENTRY (fs_access)
+ TEST_ENTRY (fs_chmod)
+ TEST_ENTRY (fs_unlink_readonly)
+ TEST_ENTRY (fs_chown)
+ TEST_ENTRY (fs_utime)
+ TEST_ENTRY (fs_futime)
+ TEST_ENTRY (fs_readlink)
+ TEST_ENTRY (fs_realpath)
+ TEST_ENTRY (fs_symlink)
+ TEST_ENTRY (fs_symlink_dir)
+ TEST_ENTRY (fs_stat_missing_path)
+ TEST_ENTRY (fs_read_file_eof)
+ TEST_ENTRY (fs_file_open_append)
+ TEST_ENTRY (fs_event_watch_dir)
+ TEST_ENTRY (fs_event_watch_dir_recursive)
+ TEST_ENTRY (fs_event_watch_file)
+ TEST_ENTRY (fs_event_watch_file_twice)
+ TEST_ENTRY (fs_event_watch_file_current_dir)
+ TEST_ENTRY (fs_event_no_callback_after_close)
+ TEST_ENTRY (fs_event_no_callback_on_close)
+ TEST_ENTRY (fs_event_immediate_close)
+ TEST_ENTRY (fs_event_close_with_pending_event)
+ TEST_ENTRY (fs_event_close_in_callback)
+ TEST_ENTRY (fs_event_start_and_close)
+ TEST_ENTRY (fs_event_error_reporting)
+ TEST_ENTRY (fs_event_getpath)
+ TEST_ENTRY (fs_scandir_empty_dir)
+ TEST_ENTRY (fs_scandir_file)
+ TEST_ENTRY (fs_open_dir)
+ TEST_ENTRY (fs_rename_to_existing_file)
+ TEST_ENTRY (fs_write_multiple_bufs)
+ TEST_ENTRY (fs_write_alotof_bufs)
+ TEST_ENTRY (fs_write_alotof_bufs_with_offset)
+ TEST_ENTRY (fs_read_write_null_arguments)
+ TEST_ENTRY (threadpool_queue_work_simple)
+ TEST_ENTRY (threadpool_queue_work_einval)
+ TEST_ENTRY (threadpool_multiple_event_loops)
+ TEST_ENTRY (threadpool_cancel_getaddrinfo)
+ TEST_ENTRY (threadpool_cancel_getnameinfo)
+ TEST_ENTRY (threadpool_cancel_work)
+ TEST_ENTRY (threadpool_cancel_fs)
+ TEST_ENTRY (threadpool_cancel_single)
+ TEST_ENTRY (thread_local_storage)
+ TEST_ENTRY (thread_mutex)
+ TEST_ENTRY (thread_rwlock)
+ TEST_ENTRY (thread_rwlock_trylock)
+ TEST_ENTRY (thread_create)
+ TEST_ENTRY (thread_equal)
+ TEST_ENTRY (dlerror)
+ TEST_ENTRY (ip4_addr)
+ TEST_ENTRY (ip6_addr_link_local)
+
+ TEST_ENTRY (queue_foreach_delete)
+
+#if 0
+ /* These are for testing the test runner. */
+ TEST_ENTRY (fail_always)
+ TEST_ENTRY (pass_always)
+#endif
+TASK_LIST_END
diff --git a/3rdparty/libuv/test/test-loop-alive.c b/3rdparty/libuv/test/test-loop-alive.c
new file mode 100644
index 00000000000..cf4d301930c
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-alive.c
@@ -0,0 +1,67 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle);
+}
+
+
+static uv_work_t work_req;
+
+static void work_cb(uv_work_t* req) {
+ ASSERT(req);
+}
+
+static void after_work_cb(uv_work_t* req, int status) {
+ ASSERT(req);
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(loop_alive) {
+ int r;
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ /* loops with handles are alive */
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 0);
+ ASSERT(uv_loop_alive(uv_default_loop()));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ /* loops with requests are alive */
+ r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb);
+ ASSERT(r == 0);
+ ASSERT(uv_loop_alive(uv_default_loop()));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-close.c b/3rdparty/libuv/test/test-loop-close.c
new file mode 100644
index 00000000000..5aec234ed03
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-close.c
@@ -0,0 +1,53 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle);
+ uv_stop(handle->loop);
+}
+
+
+TEST_IMPL(loop_close) {
+ int r;
+ uv_loop_t loop;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ uv_timer_init(&loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ ASSERT(UV_EBUSY == uv_loop_close(&loop));
+
+ uv_run(&loop, UV_RUN_DEFAULT);
+
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_loop_close(&loop));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-configure.c b/3rdparty/libuv/test/test-loop-configure.c
new file mode 100644
index 00000000000..d057c1ed8a7
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-configure.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+TEST_IMPL(loop_configure) {
+ uv_timer_t timer_handle;
+ uv_loop_t loop;
+ ASSERT(0 == uv_loop_init(&loop));
+#ifdef _WIN32
+ ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0));
+#else
+ ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF));
+#endif
+ ASSERT(0 == uv_timer_init(&loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+ ASSERT(0 == uv_loop_close(&loop));
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-handles.c b/3rdparty/libuv/test/test-loop-handles.c
new file mode 100644
index 00000000000..c3e8498ae90
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-handles.c
@@ -0,0 +1,337 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Tests commented out with XXX are ones that are failing on Linux */
+
+/*
+ * Purpose of this test is to check semantics of starting and stopping
+ * prepare, check and idle watchers.
+ *
+ * - A watcher must be able to safely stop or close itself;
+ * - Once a watcher is stopped or closed its callback should never be called.
+ * - If a watcher is closed, it is implicitly stopped and its close_cb should
+ * be called exactly once.
+ * - A watcher can safely start and stop other watchers of the same type.
+ * - Prepare and check watchers are called once per event loop iterations.
+ * - All active idle watchers are queued when the event loop has no more work
+ * to do. This is done repeatedly until all idle watchers are inactive.
+ * - If a watcher starts another watcher of the same type its callback is not
+ * immediately queued. For check and prepare watchers, that means that if
+ * a watcher makes another of the same type active, it'll not be called until
+ * the next event loop iteration. For idle. watchers this means that the
+ * newly activated idle watcher might not be queued immediately.
+ * - Prepare, check, idle watchers keep the event loop alive even when they're
+ * not active.
+ *
+ * This is what the test globally does:
+ *
+ * - prepare_1 is always active and counts event loop iterations. It also
+ * creates and starts prepare_2 every other iteration. Finally it verifies
+ * that no idle watchers are active before polling.
+ * - prepare_2 is started by prepare_1 every other iteration. It immediately
+ * stops itself. It verifies that a watcher is not queued immediately
+ * if created by another watcher of the same type.
+ * - There's a check watcher that stops the event loop after a certain number
+ * of iterations. It starts a varying number of idle_1 watchers.
+ * - Idle_1 watchers stop themselves after being called a few times. All idle_1
+ * watchers try to start the idle_2 watcher if it is not already started or
+ * awaiting its close callback.
+ * - The idle_2 watcher always exists but immediately closes itself after
+ * being started by a check_1 watcher. It verifies that a watcher is
+ * implicitly stopped when closed, and that a watcher can close itself
+ * safely.
+ * - There is a repeating timer. It does not keep the event loop alive
+ * (ev_unref) but makes sure that the loop keeps polling the system for
+ * events.
+ */
+
+
+#include "uv.h"
+#include "task.h"
+
+#include <math.h>
+
+
+#define IDLE_COUNT 7
+#define ITERATIONS 21
+#define TIMEOUT 100
+
+
+static uv_prepare_t prepare_1_handle;
+static uv_prepare_t prepare_2_handle;
+
+static uv_check_t check_handle;
+
+static uv_idle_t idle_1_handles[IDLE_COUNT];
+static uv_idle_t idle_2_handle;
+
+static uv_timer_t timer_handle;
+
+
+static int loop_iteration = 0;
+
+static int prepare_1_cb_called = 0;
+static int prepare_1_close_cb_called = 0;
+
+static int prepare_2_cb_called = 0;
+static int prepare_2_close_cb_called = 0;
+
+static int check_cb_called = 0;
+static int check_close_cb_called = 0;
+
+static int idle_1_cb_called = 0;
+static int idle_1_close_cb_called = 0;
+static int idles_1_active = 0;
+
+static int idle_2_cb_called = 0;
+static int idle_2_close_cb_called = 0;
+static int idle_2_cb_started = 0;
+static int idle_2_is_active = 0;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+}
+
+
+static void idle_2_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle == (uv_handle_t*)&idle_2_handle);
+
+ ASSERT(idle_2_is_active);
+
+ idle_2_close_cb_called++;
+ idle_2_is_active = 0;
+}
+
+
+static void idle_2_cb(uv_idle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_2_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle == &idle_2_handle);
+
+ idle_2_cb_called++;
+
+ uv_close((uv_handle_t*)handle, idle_2_close_cb);
+}
+
+
+static void idle_1_cb(uv_idle_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "IDLE_1_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle != NULL);
+ ASSERT(idles_1_active > 0);
+
+ /* Init idle_2 and make it active */
+ if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) {
+ r = uv_idle_init(uv_default_loop(), &idle_2_handle);
+ ASSERT(r == 0);
+ r = uv_idle_start(&idle_2_handle, idle_2_cb);
+ ASSERT(r == 0);
+ idle_2_is_active = 1;
+ idle_2_cb_started++;
+ }
+
+ idle_1_cb_called++;
+
+ if (idle_1_cb_called % 5 == 0) {
+ r = uv_idle_stop((uv_idle_t*)handle);
+ ASSERT(r == 0);
+ idles_1_active--;
+ }
+}
+
+
+static void idle_1_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_1_CLOSE_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle != NULL);
+
+ idle_1_close_cb_called++;
+}
+
+
+static void prepare_1_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&prepare_1_handle);
+
+ prepare_1_close_cb_called++;
+}
+
+
+static void check_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "CHECK_CLOSE_CB\n");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&check_handle);
+
+ check_close_cb_called++;
+}
+
+
+static void prepare_2_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&prepare_2_handle);
+
+ prepare_2_close_cb_called++;
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ int i, r;
+
+ fprintf(stderr, "%s", "CHECK_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &check_handle);
+
+ if (loop_iteration < ITERATIONS) {
+ /* Make some idle watchers active */
+ for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) {
+ r = uv_idle_start(&idle_1_handles[i], idle_1_cb);
+ ASSERT(r == 0);
+ idles_1_active++;
+ }
+
+ } else {
+ /* End of the test - close all handles */
+ uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb);
+ uv_close((uv_handle_t*)&check_handle, check_close_cb);
+ uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb);
+
+ for (i = 0; i < IDLE_COUNT; i++) {
+ uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb);
+ }
+
+ /* This handle is closed/recreated every time, close it only if it is */
+ /* active.*/
+ if (idle_2_is_active) {
+ uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb);
+ }
+ }
+
+ check_cb_called++;
+}
+
+
+static void prepare_2_cb(uv_prepare_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "PREPARE_2_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &prepare_2_handle);
+
+ /* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */
+ /* and it stops itself immediately. A started watcher is not queued */
+ /* until the next round, so when this callback is made */
+ /* (loop_iteration % 2 == 0) cannot be true. */
+ ASSERT(loop_iteration % 2 != 0);
+
+ r = uv_prepare_stop((uv_prepare_t*)handle);
+ ASSERT(r == 0);
+
+ prepare_2_cb_called++;
+}
+
+
+static void prepare_1_cb(uv_prepare_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "PREPARE_1_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &prepare_1_handle);
+
+ if (loop_iteration % 2 == 0) {
+ r = uv_prepare_start(&prepare_2_handle, prepare_2_cb);
+ ASSERT(r == 0);
+ }
+
+ prepare_1_cb_called++;
+ loop_iteration++;
+
+ printf("Loop iteration %d of %d.\n", loop_iteration, ITERATIONS);
+}
+
+
+TEST_IMPL(loop_handles) {
+ int i;
+ int r;
+
+ r = uv_prepare_init(uv_default_loop(), &prepare_1_handle);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare_1_handle, prepare_1_cb);
+ ASSERT(r == 0);
+
+ r = uv_check_init(uv_default_loop(), &check_handle);
+ ASSERT(r == 0);
+ r = uv_check_start(&check_handle, check_cb);
+ ASSERT(r == 0);
+
+ /* initialize only, prepare_2 is started by prepare_1_cb */
+ r = uv_prepare_init(uv_default_loop(), &prepare_2_handle);
+ ASSERT(r == 0);
+
+ for (i = 0; i < IDLE_COUNT; i++) {
+ /* initialize only, idle_1 handles are started by check_cb */
+ r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]);
+ ASSERT(r == 0);
+ }
+
+ /* don't init or start idle_2, both is done by idle_1_cb */
+
+ /* the timer callback is there to keep the event loop polling */
+ /* unref it as it is not supposed to keep the loop alive */
+ r = uv_timer_init(uv_default_loop(), &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*)&timer_handle);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(loop_iteration == ITERATIONS);
+
+ ASSERT(prepare_1_cb_called == ITERATIONS);
+ ASSERT(prepare_1_close_cb_called == 1);
+
+ ASSERT(prepare_2_cb_called == floor(ITERATIONS / 2.0));
+ ASSERT(prepare_2_close_cb_called == 1);
+
+ ASSERT(check_cb_called == ITERATIONS);
+ ASSERT(check_close_cb_called == 1);
+
+ /* idle_1_cb should be called a lot */
+ ASSERT(idle_1_close_cb_called == IDLE_COUNT);
+
+ ASSERT(idle_2_close_cb_called == idle_2_cb_started);
+ ASSERT(idle_2_is_active == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-stop.c b/3rdparty/libuv/test/test-loop-stop.c
new file mode 100644
index 00000000000..14b8c11186c
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-stop.c
@@ -0,0 +1,71 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_prepare_t prepare_handle;
+static uv_timer_t timer_handle;
+static int prepare_called = 0;
+static int timer_called = 0;
+static int num_ticks = 10;
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(handle == &prepare_handle);
+ prepare_called++;
+ if (prepare_called == num_ticks)
+ uv_prepare_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+ timer_called++;
+ if (timer_called == 1)
+ uv_stop(uv_default_loop());
+ else if (timer_called == num_ticks)
+ uv_timer_stop(handle);
+}
+
+
+TEST_IMPL(loop_stop) {
+ int r;
+ uv_prepare_init(uv_default_loop(), &prepare_handle);
+ uv_prepare_start(&prepare_handle, prepare_cb);
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 1);
+
+ r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(prepare_called > 1);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(timer_called == 10);
+ ASSERT(prepare_called == 10);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-time.c b/3rdparty/libuv/test/test-loop-time.c
new file mode 100644
index 00000000000..a2db42cceec
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-time.c
@@ -0,0 +1,63 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+TEST_IMPL(loop_update_time) {
+ uint64_t start;
+
+ start = uv_now(uv_default_loop());
+ while (uv_now(uv_default_loop()) - start < 1000)
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+static void cb(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)timer, NULL);
+}
+
+TEST_IMPL(loop_backend_timeout) {
+ uv_loop_t *loop = uv_default_loop();
+ uv_timer_t timer;
+ int r;
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ ASSERT(!uv_loop_alive(loop));
+ ASSERT(uv_backend_timeout(loop) == 0);
+
+ r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */
+ ASSERT(r == 0);
+ ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */
+ ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(uv_backend_timeout(loop) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-multiple-listen.c b/3rdparty/libuv/test/test-multiple-listen.c
new file mode 100644
index 00000000000..4ae5fa67b3a
--- /dev/null
+++ b/3rdparty/libuv/test/test-multiple-listen.c
@@ -0,0 +1,109 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int connection_cb_called = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+static uv_tcp_t server;
+static uv_tcp_t client;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*)&server, close_cb);
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
+ ASSERT(r == 0);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ free(req);
+ uv_close((uv_handle_t*)&client, close_cb);
+ connect_cb_called++;
+}
+
+
+static void client_connect(void) {
+ struct sockaddr_in addr;
+ uv_connect_t* connect_req = malloc(sizeof *connect_req);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(connect_req != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+}
+
+
+
+TEST_IMPL(multiple_listen) {
+ start_server();
+
+ client_connect();
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-mutexes.c b/3rdparty/libuv/test/test-mutexes.c
new file mode 100644
index 00000000000..af5e4e88a22
--- /dev/null
+++ b/3rdparty/libuv/test/test-mutexes.c
@@ -0,0 +1,162 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_cond_t condvar;
+static uv_mutex_t mutex;
+static uv_rwlock_t rwlock;
+static int step;
+
+/* The mutex and rwlock tests are really poor.
+ * They're very basic sanity checks and nothing more.
+ * Apologies if that rhymes.
+ */
+
+TEST_IMPL(thread_mutex) {
+ uv_mutex_t mutex;
+ int r;
+
+ r = uv_mutex_init(&mutex);
+ ASSERT(r == 0);
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_unlock(&mutex);
+ uv_mutex_destroy(&mutex);
+
+ return 0;
+}
+
+
+TEST_IMPL(thread_rwlock) {
+ uv_rwlock_t rwlock;
+ int r;
+
+ r = uv_rwlock_init(&rwlock);
+ ASSERT(r == 0);
+
+ uv_rwlock_rdlock(&rwlock);
+ uv_rwlock_rdunlock(&rwlock);
+ uv_rwlock_wrlock(&rwlock);
+ uv_rwlock_wrunlock(&rwlock);
+ uv_rwlock_destroy(&rwlock);
+
+ return 0;
+}
+
+
+/* Call when holding |mutex|. */
+static void synchronize_nowait(void) {
+ step += 1;
+ uv_cond_signal(&condvar);
+}
+
+
+/* Call when holding |mutex|. */
+static void synchronize(void) {
+ int current;
+
+ synchronize_nowait();
+ /* Wait for the other thread. Guard against spurious wakeups. */
+ for (current = step; current == step; uv_cond_wait(&condvar, &mutex));
+ ASSERT(step == current + 1);
+}
+
+
+static void thread_rwlock_trylock_peer(void* unused) {
+ (void) &unused;
+
+ uv_mutex_lock(&mutex);
+
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Acquire write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Release write lock and acquire read lock. */
+ uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
+
+ uv_rwlock_rdunlock(&rwlock);
+ synchronize_nowait(); /* Signal main thread we're going away. */
+ uv_mutex_unlock(&mutex);
+}
+
+
+TEST_IMPL(thread_rwlock_trylock) {
+ uv_thread_t thread;
+
+ ASSERT(0 == uv_cond_init(&condvar));
+ ASSERT(0 == uv_mutex_init(&mutex));
+ ASSERT(0 == uv_rwlock_init(&rwlock));
+
+ uv_mutex_lock(&mutex);
+ ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL));
+
+ /* Hold write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize(); /* Releases the mutex to the other thread. */
+
+ /* Release write lock and acquire read lock. Pthreads doesn't support
+ * the notion of upgrading or downgrading rwlocks, so neither do we.
+ */
+ uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
+
+ /* Release read lock. */
+ uv_rwlock_rdunlock(&rwlock);
+ synchronize();
+
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_rwlock_destroy(&rwlock);
+ uv_mutex_unlock(&mutex);
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&condvar);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-osx-select.c b/3rdparty/libuv/test/test-osx-select.c
new file mode 100644
index 00000000000..a0afda9181e
--- /dev/null
+++ b/3rdparty/libuv/test/test-osx-select.c
@@ -0,0 +1,140 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef __APPLE__
+
+#include <sys/ioctl.h>
+#include <string.h>
+
+static int read_count;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char slab[1024];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ fprintf(stdout, "got data %d\n", ++read_count);
+ fflush(stdout);
+
+ if (read_count == 3)
+ uv_close((uv_handle_t*) stream, NULL);
+}
+
+
+TEST_IMPL(osx_select) {
+ int r;
+ int fd;
+ size_t i;
+ size_t len;
+ const char* str;
+ uv_tty_t tty;
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
+ ASSERT(r == 0);
+
+ uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
+
+ /* Emulate user-input */
+ str = "got some input\n"
+ "with a couple of lines\n"
+ "feel pretty happy\n";
+ for (i = 0, len = strlen(str); i < len; i++) {
+ r = ioctl(fd, TIOCSTI, str + i);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(read_count == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(osx_select_many_fds) {
+ int r;
+ int fd;
+ size_t i;
+ size_t len;
+ const char* str;
+ struct sockaddr_in addr;
+ uv_tty_t tty;
+ uv_tcp_t tcps[1500];
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100);
+
+ r = uv_ip4_addr("127.0.0.1", 0, &addr);
+ ASSERT(r == 0);
+
+ for (i = 0; i < ARRAY_SIZE(tcps); i++) {
+ r = uv_tcp_init(uv_default_loop(), &tcps[i]);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcps[i], (const struct sockaddr *) &addr, 0);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*) &tcps[i]);
+ }
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ /* Emulate user-input */
+ str = "got some input\n"
+ "with a couple of lines\n"
+ "feel pretty happy\n";
+ for (i = 0, len = strlen(str); i < len; i++) {
+ r = ioctl(fd, TIOCSTI, str + i);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(read_count == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* __APPLE__ */
diff --git a/3rdparty/libuv/test/test-pass-always.c b/3rdparty/libuv/test/test-pass-always.c
new file mode 100644
index 00000000000..4fb58ff94be
--- /dev/null
+++ b/3rdparty/libuv/test/test-pass-always.c
@@ -0,0 +1,28 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+
+
+TEST_IMPL(pass_always) {
+ /* This test always passes. It is used to test the test runner. */
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ping-pong.c b/3rdparty/libuv/test/test-ping-pong.c
new file mode 100644
index 00000000000..c074178541b
--- /dev/null
+++ b/3rdparty/libuv/test/test-ping-pong.c
@@ -0,0 +1,270 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static int completed_pingers = 0;
+
+#define NUM_PINGS 1000
+
+/* 64 bytes is enough for a pinger */
+#define BUFSIZE 10240
+
+static char PING[] = "PING\n";
+static int pinger_on_connect_count;
+
+
+typedef struct {
+ int pongs;
+ int state;
+ union {
+ uv_tcp_t tcp;
+ uv_pipe_t pipe;
+ } stream;
+ uv_connect_t connect_req;
+ char read_buffer[BUFSIZE];
+} pinger_t;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void pinger_on_close(uv_handle_t* handle) {
+ pinger_t* pinger = (pinger_t*)handle->data;
+
+ ASSERT(NUM_PINGS == pinger->pongs);
+
+ free(pinger);
+
+ completed_pingers++;
+}
+
+
+static void pinger_after_write(uv_write_t *req, int status) {
+ ASSERT(status == 0);
+ free(req);
+}
+
+
+static void pinger_write_ping(pinger_t* pinger) {
+ uv_write_t *req;
+ uv_buf_t buf;
+
+ buf = uv_buf_init(PING, sizeof(PING) - 1);
+
+ req = malloc(sizeof(*req));
+ if (uv_write(req,
+ (uv_stream_t*) &pinger->stream.tcp,
+ &buf,
+ 1,
+ pinger_after_write)) {
+ FATAL("uv_write failed");
+ }
+
+ puts("PING");
+}
+
+
+static void pinger_read_cb(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ssize_t i;
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)stream->data;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ puts("got EOF");
+ free(buf->base);
+
+ uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+
+ return;
+ }
+
+ /* Now we count the pings */
+ for (i = 0; i < nread; i++) {
+ ASSERT(buf->base[i] == PING[pinger->state]);
+ pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
+
+ if (pinger->state != 0)
+ continue;
+
+ printf("PONG %d\n", pinger->pongs);
+ pinger->pongs++;
+
+ if (pinger->pongs < NUM_PINGS) {
+ pinger_write_ping(pinger);
+ } else {
+ uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+ break;
+ }
+ }
+
+ free(buf->base);
+}
+
+
+static void pinger_on_connect(uv_connect_t *req, int status) {
+ pinger_t *pinger = (pinger_t*)req->handle->data;
+
+ pinger_on_connect_count++;
+
+ ASSERT(status == 0);
+
+ ASSERT(1 == uv_is_readable(req->handle));
+ ASSERT(1 == uv_is_writable(req->handle));
+ ASSERT(0 == uv_is_closing((uv_handle_t *) req->handle));
+
+ pinger_write_ping(pinger);
+
+ uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb);
+}
+
+
+/* same ping-pong test, but using IPv6 connection */
+static void tcp_pinger_v6_new(void) {
+ int r;
+ struct sockaddr_in6 server_addr;
+ pinger_t *pinger;
+
+
+ ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
+ pinger->stream.tcp.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->stream.tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_on_connect);
+ ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+static void tcp_pinger_new(void) {
+ int r;
+ struct sockaddr_in server_addr;
+ pinger_t *pinger;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
+ pinger->stream.tcp.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->stream.tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_on_connect);
+ ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+static void pipe_pinger_new(void) {
+ int r;
+ pinger_t *pinger;
+
+ pinger = (pinger_t*)malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
+ pinger->stream.pipe.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+
+ uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
+ pinger_on_connect);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+TEST_IMPL(tcp_ping_pong) {
+ tcp_pinger_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ping_pong_v6) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ tcp_pinger_v6_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ping_pong) {
+ pipe_pinger_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-bind-error.c b/3rdparty/libuv/test/test-pipe-bind-error.c
new file mode 100644
index 00000000000..38b57db6991
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-bind-error.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrinuse) {
+ uv_pipe_t server1, server2;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server1, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server1, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &server2, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server2, TEST_PIPENAME);
+ ASSERT(r == UV_EADDRINUSE);
+
+ r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrnotavail) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server, BAD_PIPENAME);
+ ASSERT(r == UV_EACCES);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_inval) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME_2);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_listen_without_bind) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c b/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c
new file mode 100644
index 00000000000..ee8bb2a9a8b
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c
@@ -0,0 +1,104 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "uv.h"
+#include "task.h"
+
+void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf)
+{
+ static char buffer[1024];
+
+ buf->base = buffer;
+ buf->len = sizeof(buffer);
+}
+
+void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf)
+{
+ if (nread < 0) {
+ uv_close((uv_handle_t*)stream, NULL);
+ return;
+ }
+}
+
+/*
+ * This test is a reproduction of joyent/libuv#1419 .
+ */
+TEST_IMPL(pipe_close_stdout_read_stdin) {
+ int r = -1;
+ int pid;
+ int fd[2];
+ int status;
+ uv_pipe_t stdin_pipe;
+
+ r = pipe(fd);
+ ASSERT(r == 0);
+
+ if ((pid = fork()) == 0) {
+ /*
+ * Make the read side of the pipe our stdin.
+ * The write side will be closed by the parent process.
+ */
+ close(fd[1]);
+ close(0);
+ r = dup(fd[0]);
+ ASSERT(r != -1);
+
+ /* Create a stream that reads from the pipe. */
+ r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin);
+ ASSERT(r == 0);
+
+ /*
+ * Because the other end of the pipe was closed, there should
+ * be no event left to process after one run of the event loop.
+ * Otherwise, it means that events were not processed correctly.
+ */
+ ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0);
+ } else {
+ /*
+ * Close both ends of the pipe so that the child
+ * get a POLLHUP event when it tries to read from
+ * the other end.
+ */
+ close(fd[1]);
+ close(fd[0]);
+
+ waitpid(pid, &status, 0);
+ ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* ifndef _WIN32 */
diff --git a/3rdparty/libuv/test/test-pipe-connect-error.c b/3rdparty/libuv/test/test-pipe-connect-error.c
new file mode 100644
index 00000000000..ebb2a6ca826
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-error.c
@@ -0,0 +1,95 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOENT);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+static void connect_cb_file(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(pipe_connect_bad_name) {
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_connect_to_file) {
+ const char* path = "test/fixtures/empty_file";
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, path, connect_cb_file);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-connect-multiple.c b/3rdparty/libuv/test/test-pipe-connect-multiple.c
new file mode 100644
index 00000000000..3de5a9a0bf4
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-multiple.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connection_cb_called = 0;
+static int connect_cb_called = 0;
+
+#define NUM_CLIENTS 4
+
+typedef struct {
+ uv_pipe_t pipe_handle;
+ uv_connect_t conn_req;
+} client_t;
+
+static uv_pipe_t server_handle;
+static client_t clients[NUM_CLIENTS];
+static uv_pipe_t connections[NUM_CLIENTS];
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ int r;
+ uv_pipe_t* conn;
+ ASSERT(status == 0);
+
+ conn = &connections[connection_cb_called];
+ r = uv_pipe_init(server->loop, conn, 0);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ if (++connection_cb_called == NUM_CLIENTS &&
+ connect_cb_called == NUM_CLIENTS) {
+ uv_stop(server->loop);
+ }
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == 0);
+ if (++connect_cb_called == NUM_CLIENTS &&
+ connection_cb_called == NUM_CLIENTS) {
+ uv_stop(connect_req->handle->loop);
+ }
+}
+
+
+TEST_IMPL(pipe_connect_multiple) {
+ int i;
+ int r;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &server_handle, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ for (i = 0; i < NUM_CLIENTS; i++) {
+ r = uv_pipe_init(loop, &clients[i].pipe_handle, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&clients[i].conn_req,
+ &clients[i].pipe_handle,
+ TEST_PIPENAME,
+ connect_cb);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == NUM_CLIENTS);
+ ASSERT(connect_cb_called == NUM_CLIENTS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-connect-prepare.c b/3rdparty/libuv/test/test-pipe-connect-prepare.c
new file mode 100644
index 00000000000..a86e7284a79
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-prepare.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+static uv_pipe_t pipe_handle;
+static uv_prepare_t prepare_handle;
+static uv_connect_t conn_req;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOENT);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)&prepare_handle, close_cb);
+ uv_close((uv_handle_t*)&pipe_handle, close_cb);
+}
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(handle == &prepare_handle);
+ uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb);
+}
+
+
+TEST_IMPL(pipe_connect_on_prepare) {
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0);
+ ASSERT(r == 0);
+
+ r = uv_prepare_init(uv_default_loop(), &prepare_handle);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare_handle, prepare_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 2);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-getsockname.c b/3rdparty/libuv/test/test-pipe-getsockname.c
new file mode 100644
index 00000000000..5e036f9d528
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-getsockname.c
@@ -0,0 +1,263 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__linux__)
+ #include <sys/socket.h>
+ #include <sys/un.h>
+#endif
+
+#ifndef _WIN32
+# include <unistd.h> /* close */
+#else
+# include <fcntl.h>
+#endif
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ char buf[1024];
+ size_t len;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == 0 && len == 0);
+
+ pipe_client_connect_cb_called++;
+
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_getsockname) {
+ uv_loop_t* loop;
+ char buf[1024];
+ size_t len;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ ASSERT(r == UV_ENOTCONN);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == 0 && len == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(pipe_client_connect_cb_called == 1);
+ ASSERT(pipe_close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_getsockname_abstract) {
+#if defined(__linux__)
+ char buf[1024];
+ size_t len;
+ int r;
+ int sock;
+ struct sockaddr_un sun;
+ socklen_t sun_len;
+ char abstract_pipe[] = "\0test-pipe";
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ ASSERT(sock != -1);
+
+ sun_len = sizeof sun;
+ memset(&sun, 0, sun_len);
+ sun.sun_family = AF_UNIX;
+ memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
+
+ r = bind(sock, (struct sockaddr*)&sun, sun_len);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_open(&pipe_server, sock);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
+
+ uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ close(sock);
+
+ ASSERT(pipe_close_cb_called == 1);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#endif
+}
+
+TEST_IMPL(pipe_getsockname_blocking) {
+#ifdef _WIN32
+ HANDLE readh, writeh;
+ int readfd;
+ char buf1[1024], buf2[1024];
+ size_t len1, len2;
+ int r;
+
+ r = CreatePipe(&readh, &writeh, NULL, 65536);
+ ASSERT(r != 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
+ ASSERT(r == 0);
+ readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
+ ASSERT(r != -1);
+ r = uv_pipe_open(&pipe_client, readfd);
+ ASSERT(r == 0);
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ ASSERT(r == 0);
+ Sleep(100);
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ ASSERT(r == 0);
+
+ len1 = sizeof buf1;
+ r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
+ ASSERT(r == 0);
+ ASSERT(buf1[len1 - 1] != 0);
+
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ ASSERT(r == 0);
+ Sleep(100);
+
+ len2 = sizeof buf2;
+ r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
+ ASSERT(r == 0);
+ ASSERT(buf2[len2 - 1] != 0);
+
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ ASSERT(r == 0);
+
+ ASSERT(len1 == len2);
+ ASSERT(memcmp(buf1, buf2, len1) == 0);
+
+ pipe_close_cb_called = 0;
+ uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(pipe_close_cb_called == 1);
+
+ _close(readfd);
+ CloseHandle(writeh);
+#endif
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-pending-instances.c b/3rdparty/libuv/test/test-pipe-pending-instances.c
new file mode 100644
index 00000000000..b6ff911a0f2
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-pending-instances.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ ASSERT(0 && "this will never be called");
+}
+
+
+TEST_IMPL(pipe_pending_instances) {
+ int r;
+ uv_pipe_t pipe_handle;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &pipe_handle, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 8);
+
+ r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 16);
+
+ r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&pipe_handle, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-sendmsg.c b/3rdparty/libuv/test/test-pipe-sendmsg.c
new file mode 100644
index 00000000000..f6d893b4494
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-sendmsg.c
@@ -0,0 +1,169 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+#ifndef _WIN32
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+
+/* NOTE: size should be divisible by 2 */
+static uv_pipe_t incoming[4];
+static unsigned int incoming_count;
+static unsigned int close_called;
+
+
+static void set_nonblocking(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ unsigned long on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+#else
+ int flags = fcntl(sock, F_GETFL, 0);
+ ASSERT(flags >= 0);
+ r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+ ASSERT(r >= 0);
+#endif
+}
+
+
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_called++;
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_pipe_t* p;
+ uv_pipe_t* inc;
+ uv_handle_type pending;
+ unsigned int i;
+
+ p = (uv_pipe_t*) handle;
+ ASSERT(nread >= 0);
+
+ while (uv_pipe_pending_count(p) != 0) {
+ pending = uv_pipe_pending_type(p);
+ ASSERT(pending == UV_NAMED_PIPE);
+
+ ASSERT(incoming_count < ARRAY_SIZE(incoming));
+ inc = &incoming[incoming_count++];
+ ASSERT(0 == uv_pipe_init(p->loop, inc, 0));
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc));
+ }
+
+ if (incoming_count != ARRAY_SIZE(incoming))
+ return;
+
+ ASSERT(0 == uv_read_stop((uv_stream_t*) p));
+ uv_close((uv_handle_t*) p, close_cb);
+ for (i = 0; i < ARRAY_SIZE(incoming); i++)
+ uv_close((uv_handle_t*) &incoming[i], close_cb);
+}
+
+
+TEST_IMPL(pipe_sendmsg) {
+ uv_pipe_t p;
+ int r;
+ int fds[2];
+ int send_fds[ARRAY_SIZE(incoming)];
+ struct msghdr msg;
+ char scratch[64];
+ struct cmsghdr *cmsg;
+ unsigned int i;
+ uv_buf_t buf;
+
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+ for (i = 0; i < ARRAY_SIZE(send_fds); i += 2)
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i));
+ ASSERT(i == ARRAY_SIZE(send_fds));
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1));
+ ASSERT(0 == uv_pipe_open(&p, fds[1]));
+
+ buf = uv_buf_init("X", 1);
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ msg.msg_control = (void*) scratch;
+ msg.msg_controllen = CMSG_LEN(sizeof(send_fds));
+ ASSERT(sizeof(scratch) >= msg.msg_controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = msg.msg_controllen;
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ for (i = 0; i < ARRAY_SIZE(send_fds); i++)
+ pi[i] = send_fds[i];
+ }
+
+ set_nonblocking(fds[1]);
+ ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb));
+
+ do
+ r = sendmsg(fds[0], &msg, 0);
+ while (r == -1 && errno == EINTR);
+ ASSERT(r == 1);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(ARRAY_SIZE(incoming) == incoming_count);
+ ASSERT(ARRAY_SIZE(incoming) + 1 == close_called);
+ close(fds[0]);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+TEST_IMPL(pipe_sendmsg) {
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-pipe-server-close.c b/3rdparty/libuv/test/test-pipe-server-close.c
new file mode 100644
index 00000000000..1dcdfffaf7c
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-server-close.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ pipe_client_connect_cb_called++;
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_server_close) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(pipe_client_connect_cb_called == 1);
+ ASSERT(pipe_close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-set-non-blocking.c b/3rdparty/libuv/test/test-pipe-set-non-blocking.c
new file mode 100644
index 00000000000..fcc9fc0da85
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-set-non-blocking.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _WIN32
+
+TEST_IMPL(pipe_set_non_blocking) {
+ RETURN_SKIP("Test not implemented on Windows.");
+}
+
+#else /* !_WIN32 */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+struct thread_ctx {
+ uv_barrier_t barrier;
+ int fd;
+};
+
+static void thread_main(void* arg) {
+ struct thread_ctx* ctx;
+ char buf[4096];
+ ssize_t n;
+
+ ctx = arg;
+ uv_barrier_wait(&ctx->barrier);
+
+ do
+ n = read(ctx->fd, buf, sizeof(buf));
+ while (n > 0 || (n == -1 && errno == EINTR));
+
+ ASSERT(n == 0);
+}
+
+TEST_IMPL(pipe_set_non_blocking) {
+ struct thread_ctx ctx;
+ uv_pipe_t pipe_handle;
+ uv_thread_t thread;
+ size_t nwritten;
+ char data[4096];
+ uv_buf_t buf;
+ int fd[2];
+ int n;
+
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));
+
+ ctx.fd = fd[1];
+ ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
+ uv_barrier_wait(&ctx.barrier);
+
+ buf.len = sizeof(data);
+ buf.base = data;
+ memset(data, '.', sizeof(data));
+
+ nwritten = 0;
+ while (nwritten < 10 << 20) {
+ /* The stream is in blocking mode so uv_try_write() should always succeed
+ * with the exact number of bytes that we wanted written.
+ */
+ n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
+ ASSERT(n == sizeof(data));
+ nwritten += n;
+ }
+
+ uv_close((uv_handle_t*) &pipe_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(0 == uv_thread_join(&thread));
+ ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
+ uv_barrier_destroy(&ctx.barrier);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-platform-output.c b/3rdparty/libuv/test/test-platform-output.c
new file mode 100644
index 00000000000..76495e14fd8
--- /dev/null
+++ b/3rdparty/libuv/test/test-platform-output.c
@@ -0,0 +1,126 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+TEST_IMPL(platform_output) {
+ char buffer[512];
+ size_t rss;
+ size_t size;
+ double uptime;
+ uv_rusage_t rusage;
+ uv_cpu_info_t* cpus;
+ uv_interface_address_t* interfaces;
+ int count;
+ int i;
+ int err;
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+ printf("uv_get_process_title: %s\n", buffer);
+
+ size = sizeof(buffer);
+ err = uv_cwd(buffer, &size);
+ ASSERT(err == 0);
+ printf("uv_cwd: %s\n", buffer);
+
+ err = uv_resident_set_memory(&rss);
+ ASSERT(err == 0);
+ printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
+
+ err = uv_uptime(&uptime);
+ ASSERT(err == 0);
+ ASSERT(uptime > 0);
+ printf("uv_uptime: %f\n", uptime);
+
+ err = uv_getrusage(&rusage);
+ ASSERT(err == 0);
+ ASSERT(rusage.ru_utime.tv_sec >= 0);
+ ASSERT(rusage.ru_utime.tv_usec >= 0);
+ ASSERT(rusage.ru_stime.tv_sec >= 0);
+ ASSERT(rusage.ru_stime.tv_usec >= 0);
+ printf("uv_getrusage:\n");
+ printf(" user: %llu sec %llu microsec\n",
+ (unsigned long long) rusage.ru_utime.tv_sec,
+ (unsigned long long) rusage.ru_utime.tv_usec);
+ printf(" system: %llu sec %llu microsec\n",
+ (unsigned long long) rusage.ru_stime.tv_sec,
+ (unsigned long long) rusage.ru_stime.tv_usec);
+
+ err = uv_cpu_info(&cpus, &count);
+ ASSERT(err == 0);
+
+ printf("uv_cpu_info:\n");
+ for (i = 0; i < count; i++) {
+ printf(" model: %s\n", cpus[i].model);
+ printf(" speed: %d\n", cpus[i].speed);
+ printf(" times.sys: %llu\n", (unsigned long long) cpus[i].cpu_times.sys);
+ printf(" times.user: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.user);
+ printf(" times.idle: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.idle);
+ printf(" times.irq: %llu\n", (unsigned long long) cpus[i].cpu_times.irq);
+ printf(" times.nice: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.nice);
+ }
+ uv_free_cpu_info(cpus, count);
+
+ err = uv_interface_addresses(&interfaces, &count);
+ ASSERT(err == 0);
+
+ printf("uv_interface_addresses:\n");
+ for (i = 0; i < count; i++) {
+ printf(" name: %s\n", interfaces[i].name);
+ printf(" internal: %d\n", interfaces[i].is_internal);
+ printf(" physical address: ");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)interfaces[i].phys_addr[0],
+ (unsigned char)interfaces[i].phys_addr[1],
+ (unsigned char)interfaces[i].phys_addr[2],
+ (unsigned char)interfaces[i].phys_addr[3],
+ (unsigned char)interfaces[i].phys_addr[4],
+ (unsigned char)interfaces[i].phys_addr[5]);
+
+ if (interfaces[i].address.address4.sin_family == AF_INET) {
+ uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer));
+ } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
+ uv_ip6_name(&interfaces[i].address.address6, buffer, sizeof(buffer));
+ }
+
+ printf(" address: %s\n", buffer);
+
+ if (interfaces[i].netmask.netmask4.sin_family == AF_INET) {
+ uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer));
+ printf(" netmask: %s\n", buffer);
+ } else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) {
+ uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer));
+ printf(" netmask: %s\n", buffer);
+ } else {
+ printf(" netmask: none\n");
+ }
+ }
+ uv_free_interface_addresses(interfaces, count);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c b/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c
new file mode 100644
index 00000000000..fc2cc004f16
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c
@@ -0,0 +1,114 @@
+/* Copyright Bert Belder, and other libuv contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _MSC_VER /* msvc */
+# define NO_INLINE __declspec(noinline)
+#else /* gcc */
+# define NO_INLINE __attribute__ ((noinline))
+#endif
+
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ ASSERT(0 && "should never get here");
+}
+
+
+static void NO_INLINE close_socket_and_verify_stack() {
+ const uint32_t MARKER = 0xDEADBEEF;
+ const int VERIFY_AFTER = 10; /* ms */
+ int r;
+
+ volatile uint32_t data[65536];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ data[i] = MARKER;
+
+ r = closesocket(sock);
+ ASSERT(r == 0);
+
+ uv_sleep(VERIFY_AFTER);
+
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ ASSERT(data[i] == MARKER);
+}
+
+
+TEST_IMPL(poll_close_doesnt_corrupt_stack) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+ close_socket_and_verify_stack();
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-poll-close.c b/3rdparty/libuv/test/test-poll-close.c
new file mode 100644
index 00000000000..2eccddf5b0b
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-close.c
@@ -0,0 +1,73 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+#define NUM_SOCKETS 64
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+TEST_IMPL(poll_close) {
+ uv_os_sock_t sockets[NUM_SOCKETS];
+ uv_poll_t poll_handles[NUM_SOCKETS];
+ int i;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ sockets[i] = socket(AF_INET, SOCK_STREAM, 0);
+ uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]);
+ uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL);
+ }
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ uv_close((uv_handle_t*) &poll_handles[i], close_cb);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == NUM_SOCKETS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-poll-closesocket.c b/3rdparty/libuv/test/test-poll-closesocket.c
new file mode 100644
index 00000000000..4db74a01f63
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-closesocket.c
@@ -0,0 +1,89 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+#include "uv.h"
+#include "task.h"
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(h == &handle);
+
+ r = uv_poll_start(&handle, UV_READABLE, poll_cb);
+ ASSERT(r == 0);
+
+ closesocket(sock);
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+}
+
+
+TEST_IMPL(poll_closesocket) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
diff --git a/3rdparty/libuv/test/test-poll.c b/3rdparty/libuv/test/test-poll.c
new file mode 100644
index 00000000000..be8b00c32ca
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll.c
@@ -0,0 +1,560 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+
+#define NUM_CLIENTS 5
+#define TRANSFER_BYTES (1 << 16)
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b));
+
+
+typedef enum {
+ UNIDIRECTIONAL,
+ DUPLEX
+} test_mode_t;
+
+typedef struct connection_context_s {
+ uv_poll_t poll_handle;
+ uv_timer_t timer_handle;
+ uv_os_sock_t sock;
+ size_t read, sent;
+ int is_server_connection;
+ int open_handles;
+ int got_fin, sent_fin;
+ unsigned int events, delayed_events;
+} connection_context_t;
+
+typedef struct server_context_s {
+ uv_poll_t poll_handle;
+ uv_os_sock_t sock;
+ int connections;
+} server_context_t;
+
+
+static void delay_timer_cb(uv_timer_t* timer);
+
+
+static test_mode_t test_mode = DUPLEX;
+
+static int closed_connections = 0;
+
+static int valid_writable_wakeups = 0;
+static int spurious_writable_wakeups = 0;
+
+
+static int got_eagain(void) {
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEWOULDBLOCK;
+#else
+ return errno == EAGAIN
+ || errno == EINPROGRESS
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK;
+#endif
+ ;
+#endif
+}
+
+
+static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) {
+ uv_os_sock_t sock;
+ int r;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr);
+ ASSERT(r == 0);
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static connection_context_t* create_connection_context(
+ uv_os_sock_t sock, int is_server_connection) {
+ int r;
+ connection_context_t* context;
+
+ context = (connection_context_t*) malloc(sizeof *context);
+ ASSERT(context != NULL);
+
+ context->sock = sock;
+ context->is_server_connection = is_server_connection;
+ context->read = 0;
+ context->sent = 0;
+ context->open_handles = 0;
+ context->events = 0;
+ context->delayed_events = 0;
+ context->got_fin = 0;
+ context->sent_fin = 0;
+
+ r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+ context->open_handles++;
+ context->poll_handle.data = context;
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &context->timer_handle);
+ context->open_handles++;
+ context->timer_handle.data = context;
+ ASSERT(r == 0);
+
+ return context;
+}
+
+
+static void connection_close_cb(uv_handle_t* handle) {
+ connection_context_t* context = (connection_context_t*) handle->data;
+
+ if (--context->open_handles == 0) {
+ if (test_mode == DUPLEX || context->is_server_connection) {
+ ASSERT(context->read == TRANSFER_BYTES);
+ } else {
+ ASSERT(context->read == 0);
+ }
+
+ if (test_mode == DUPLEX || !context->is_server_connection) {
+ ASSERT(context->sent == TRANSFER_BYTES);
+ } else {
+ ASSERT(context->sent == 0);
+ }
+
+ closed_connections++;
+
+ free(context);
+ }
+}
+
+
+static void destroy_connection_context(connection_context_t* context) {
+ uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb);
+ uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb);
+}
+
+
+static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
+ connection_context_t* context = (connection_context_t*) handle->data;
+ unsigned int new_events;
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(events & context->events);
+ ASSERT(!(events & ~context->events));
+
+ new_events = context->events;
+
+ if (events & UV_READABLE) {
+ int action = rand() % 7;
+
+ switch (action) {
+ case 0:
+ case 1: {
+ /* Read a couple of bytes. */
+ static char buffer[74];
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ ASSERT(r >= 0);
+
+ if (r > 0) {
+ context->read += r;
+ } else {
+ /* Got FIN. */
+ context->got_fin = 1;
+ new_events &= ~UV_READABLE;
+ }
+
+ break;
+ }
+
+ case 2:
+ case 3: {
+ /* Read until EAGAIN. */
+ static char buffer[931];
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ ASSERT(r >= 0);
+
+ while (r > 0) {
+ context->read += r;
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ }
+
+ if (r == 0) {
+ /* Got FIN. */
+ context->got_fin = 1;
+ new_events &= ~UV_READABLE;
+ } else {
+ ASSERT(got_eagain());
+ }
+
+ break;
+ }
+
+ case 4:
+ /* Ignore. */
+ break;
+
+ case 5:
+ /* Stop reading for a while. Restart in timer callback. */
+ new_events &= ~UV_READABLE;
+ if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+ context->delayed_events = UV_READABLE;
+ uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0);
+ } else {
+ context->delayed_events |= UV_READABLE;
+ }
+ break;
+
+ case 6:
+ /* Fudge with the event mask. */
+ uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb);
+ uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb);
+ context->events = UV_READABLE;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+ }
+
+ if (events & UV_WRITABLE) {
+ if (context->sent < TRANSFER_BYTES &&
+ !(test_mode == UNIDIRECTIONAL && context->is_server_connection)) {
+ /* We have to send more bytes. */
+ int action = rand() % 7;
+
+ switch (action) {
+ case 0:
+ case 1: {
+ /* Send a couple of bytes. */
+ static char buffer[103];
+
+ int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r < 0) {
+ ASSERT(got_eagain());
+ spurious_writable_wakeups++;
+ break;
+ }
+
+ ASSERT(r > 0);
+ context->sent += r;
+ valid_writable_wakeups++;
+ break;
+ }
+
+ case 2:
+ case 3: {
+ /* Send until EAGAIN. */
+ static char buffer[1234];
+
+ int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r < 0) {
+ ASSERT(got_eagain());
+ spurious_writable_wakeups++;
+ break;
+ }
+
+ ASSERT(r > 0);
+ valid_writable_wakeups++;
+ context->sent += r;
+
+ while (context->sent < TRANSFER_BYTES) {
+ send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r <= 0) break;
+ context->sent += r;
+ }
+ ASSERT(r > 0 || got_eagain());
+ break;
+ }
+
+ case 4:
+ /* Ignore. */
+ break;
+
+ case 5:
+ /* Stop sending for a while. Restart in timer callback. */
+ new_events &= ~UV_WRITABLE;
+ if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+ context->delayed_events = UV_WRITABLE;
+ uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0);
+ } else {
+ context->delayed_events |= UV_WRITABLE;
+ }
+ break;
+
+ case 6:
+ /* Fudge with the event mask. */
+ uv_poll_start(&context->poll_handle,
+ UV_READABLE,
+ connection_poll_cb);
+ uv_poll_start(&context->poll_handle,
+ UV_WRITABLE,
+ connection_poll_cb);
+ context->events = UV_WRITABLE;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+ } else {
+ /* Nothing more to write. Send FIN. */
+ int r;
+#ifdef _WIN32
+ r = shutdown(context->sock, SD_SEND);
+#else
+ r = shutdown(context->sock, SHUT_WR);
+#endif
+ ASSERT(r == 0);
+ context->sent_fin = 1;
+ new_events &= ~UV_WRITABLE;
+ }
+ }
+
+ if (context->got_fin && context->sent_fin) {
+ /* Sent and received FIN. Close and destroy context. */
+ close_socket(context->sock);
+ destroy_connection_context(context);
+ context->events = 0;
+
+ } else if (new_events != context->events) {
+ /* Poll mask changed. Call uv_poll_start again. */
+ context->events = new_events;
+ uv_poll_start(handle, new_events, connection_poll_cb);
+ }
+
+ /* Assert that uv_is_active works correctly for poll handles. */
+ if (context->events != 0) {
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+ } else {
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+ }
+}
+
+
+static void delay_timer_cb(uv_timer_t* timer) {
+ connection_context_t* context = (connection_context_t*) timer->data;
+ int r;
+
+ /* Timer should auto stop. */
+ ASSERT(0 == uv_is_active((uv_handle_t*) timer));
+
+ /* Add the requested events to the poll mask. */
+ ASSERT(context->delayed_events != 0);
+ context->events |= context->delayed_events;
+ context->delayed_events = 0;
+
+ r = uv_poll_start(&context->poll_handle,
+ context->events,
+ connection_poll_cb);
+ ASSERT(r == 0);
+}
+
+
+static server_context_t* create_server_context(
+ uv_os_sock_t sock) {
+ int r;
+ server_context_t* context;
+
+ context = (server_context_t*) malloc(sizeof *context);
+ ASSERT(context != NULL);
+
+ context->sock = sock;
+ context->connections = 0;
+
+ r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+ context->poll_handle.data = context;
+ ASSERT(r == 0);
+
+ return context;
+}
+
+
+static void server_close_cb(uv_handle_t* handle) {
+ server_context_t* context = (server_context_t*) handle->data;
+ free(context);
+}
+
+
+static void destroy_server_context(server_context_t* context) {
+ uv_close((uv_handle_t*) &context->poll_handle, server_close_cb);
+}
+
+
+static void server_poll_cb(uv_poll_t* handle, int status, int events) {
+ server_context_t* server_context = (server_context_t*)
+ handle->data;
+ connection_context_t* connection_context;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+ uv_os_sock_t sock;
+ int r;
+
+ addr_len = sizeof addr;
+ sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+ connection_context = create_connection_context(sock, 1);
+ connection_context->events = UV_READABLE | UV_WRITABLE;
+ r = uv_poll_start(&connection_context->poll_handle,
+ UV_READABLE | UV_WRITABLE,
+ connection_poll_cb);
+ ASSERT(r == 0);
+
+ if (++server_context->connections == NUM_CLIENTS) {
+ close_socket(server_context->sock);
+ destroy_server_context(server_context);
+ }
+}
+
+
+static void start_server(void) {
+ server_context_t* context;
+ struct sockaddr_in addr;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ sock = create_bound_socket(addr);
+ context = create_server_context(sock);
+
+ r = listen(sock, 100);
+ ASSERT(r == 0);
+
+ r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb);
+ ASSERT(r == 0);
+}
+
+
+static void start_client(void) {
+ uv_os_sock_t sock;
+ connection_context_t* context;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));
+
+ sock = create_bound_socket(addr);
+ context = create_connection_context(sock, 0);
+
+ context->events = UV_READABLE | UV_WRITABLE;
+ r = uv_poll_start(&context->poll_handle,
+ UV_READABLE | UV_WRITABLE,
+ connection_poll_cb);
+ ASSERT(r == 0);
+
+ r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr);
+ ASSERT(r == 0 || got_eagain());
+}
+
+
+static void start_poll_test(void) {
+ int i, r;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ start_server();
+
+ for (i = 0; i < NUM_CLIENTS; i++)
+ start_client();
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Assert that at most five percent of the writable wakeups was spurious. */
+ ASSERT(spurious_writable_wakeups == 0 ||
+ (valid_writable_wakeups + spurious_writable_wakeups) /
+ spurious_writable_wakeups > 20);
+
+ ASSERT(closed_connections == NUM_CLIENTS * 2);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+TEST_IMPL(poll_duplex) {
+ test_mode = DUPLEX;
+ start_poll_test();
+ return 0;
+}
+
+
+TEST_IMPL(poll_unidirectional) {
+ test_mode = UNIDIRECTIONAL;
+ start_poll_test();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-process-title.c b/3rdparty/libuv/test/test-process-title.c
new file mode 100644
index 00000000000..42ade441604
--- /dev/null
+++ b/3rdparty/libuv/test/test-process-title.c
@@ -0,0 +1,53 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+static void set_title(const char* title) {
+ char buffer[512];
+ int err;
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+
+ err = uv_set_process_title(title);
+ ASSERT(err == 0);
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+
+ ASSERT(strcmp(buffer, title) == 0);
+}
+
+
+TEST_IMPL(process_title) {
+#if defined(__sun) || defined(_AIX)
+ RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
+#else
+ /* Check for format string vulnerabilities. */
+ set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
+ set_title("new title");
+ return 0;
+#endif
+}
diff --git a/3rdparty/libuv/test/test-queue-foreach-delete.c b/3rdparty/libuv/test/test-queue-foreach-delete.c
new file mode 100644
index 00000000000..45da225381f
--- /dev/null
+++ b/3rdparty/libuv/test/test-queue-foreach-delete.c
@@ -0,0 +1,200 @@
+/* Copyright The libuv project and contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+
+
+/*
+ * The idea behind the test is as follows.
+ * Certain handle types are stored in a queue internally.
+ * Extra care should be taken for removal of a handle from the queue while iterating over the queue.
+ * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH())
+ * This usually happens when someone closes or stops a handle from within its callback.
+ * So we need to check that we haven't screwed the queue on close/stop.
+ * To do so we do the following (for each handle type):
+ * 1. Create and start 3 handles (#0, #1, and #2).
+ *
+ * The queue after the start() calls:
+ * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=..
+ *
+ * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do).
+ *
+ * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type)
+ * stop the handle and the next one (#1).
+ * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed,
+ * so callback for handle #2 will be called first)
+ *
+ * The queue after the stop() calls:
+ * correct foreach "next" |
+ * \/
+ * ..=> [queue head] <==============================> [handle] <=..
+ * [ ] <- [handle] <=> [handle #1] -> [ ]
+ * /\
+ * wrong foreach "next" |
+ *
+ * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step.
+ * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called.
+ */
+
+static const unsigned first_handle_number_idle = 2;
+static const unsigned first_handle_number_prepare = 2;
+static const unsigned first_handle_number_check = 2;
+#ifdef __linux__
+static const unsigned first_handle_number_fs_event = 0;
+#endif
+
+
+#define DEFINE_GLOBALS_AND_CBS(name) \
+ static uv_##name##_t (name)[3]; \
+ static unsigned name##_cb_calls[3]; \
+ \
+ static void name##2_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[2]); \
+ if (first_handle_number_##name == 2) { \
+ uv_close((uv_handle_t*)&(name)[2], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[2]++; \
+ } \
+ \
+ static void name##1_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[1]); \
+ ASSERT(0 && "Shouldn't be called" && (&name[0])); \
+ } \
+ \
+ static void name##0_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[0]); \
+ if (first_handle_number_##name == 0) { \
+ uv_close((uv_handle_t*)&(name)[0], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[0]++; \
+ } \
+ \
+ static const uv_##name##_cb name##_cbs[] = { \
+ (uv_##name##_cb)name##0_cb, \
+ (uv_##name##_cb)name##1_cb, \
+ (uv_##name##_cb)name##2_cb, \
+ };
+
+#define INIT_AND_START(name, loop) \
+ do { \
+ size_t i; \
+ for (i = 0; i < ARRAY_SIZE(name); i++) { \
+ int r; \
+ r = uv_##name##_init((loop), &(name)[i]); \
+ ASSERT(r == 0); \
+ \
+ r = uv_##name##_start(&(name)[i], name##_cbs[i]); \
+ ASSERT(r == 0); \
+ } \
+ } while (0)
+
+#define END_ASSERTS(name) \
+ do { \
+ ASSERT(name##_cb_calls[0] == 1); \
+ ASSERT(name##_cb_calls[1] == 0); \
+ ASSERT(name##_cb_calls[2] == 1); \
+ } while (0)
+
+DEFINE_GLOBALS_AND_CBS(idle)
+DEFINE_GLOBALS_AND_CBS(prepare)
+DEFINE_GLOBALS_AND_CBS(check)
+
+#ifdef __linux__
+DEFINE_GLOBALS_AND_CBS(fs_event)
+
+static const char watched_dir[] = ".";
+static uv_timer_t timer;
+static unsigned helper_timer_cb_calls;
+
+
+static void init_and_start_fs_events(uv_loop_t* loop) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(fs_event); i++) {
+ int r;
+ r = uv_fs_event_init(loop, &fs_event[i]);
+ ASSERT(r == 0);
+
+ r = uv_fs_event_start(&fs_event[i],
+ (uv_fs_event_cb)fs_event_cbs[i],
+ watched_dir,
+ 0);
+ ASSERT(r == 0);
+ }
+}
+
+static void helper_timer_cb(uv_timer_t* thandle) {
+ int r;
+ uv_fs_t fs_req;
+
+ /* fire all fs_events */
+ r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(fs_req.result == 0);
+ ASSERT(fs_req.fs_type == UV_FS_UTIME);
+ ASSERT(strcmp(fs_req.path, watched_dir) == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ helper_timer_cb_calls++;
+}
+#endif
+
+
+TEST_IMPL(queue_foreach_delete) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ INIT_AND_START(idle, loop);
+ INIT_AND_START(prepare, loop);
+ INIT_AND_START(check, loop);
+
+#ifdef __linux__
+ init_and_start_fs_events(loop);
+
+ /* helper timer to trigger async and fs_event callbacks */
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, helper_timer_cb, 0, 0);
+ ASSERT(r == 0);
+#endif
+
+ r = uv_run(loop, UV_RUN_NOWAIT);
+ ASSERT(r == 1);
+
+ END_ASSERTS(idle);
+ END_ASSERTS(prepare);
+ END_ASSERTS(check);
+
+#ifdef __linux__
+ ASSERT(helper_timer_cb_calls == 1);
+#endif
+
+ MAKE_VALGRIND_HAPPY();
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ref.c b/3rdparty/libuv/test/test-ref.c
new file mode 100644
index 00000000000..ddaa1738083
--- /dev/null
+++ b/3rdparty/libuv/test/test-ref.c
@@ -0,0 +1,442 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static char buffer[32767];
+
+static int req_cb_called;
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void do_close(void* handle) {
+ close_cb_called = 0;
+ uv_close((uv_handle_t*)handle, close_cb);
+ ASSERT(close_cb_called == 0);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+}
+
+
+static void fail_cb(void) {
+ FATAL("fail_cb should not have been called");
+}
+
+
+static void fail_cb2(void) {
+ ASSERT(0 && "fail_cb2 should not have been called");
+}
+
+
+static void req_cb(uv_handle_t* req, int status) {
+ req_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ shutdown_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req == &write_req);
+ uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ write_cb_called++;
+}
+
+
+static void connect_and_write(uv_connect_t* req, int status) {
+ uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+ uv_write(&write_req, req->handle, &buf, 1, write_cb);
+ connect_cb_called++;
+}
+
+
+
+static void connect_and_shutdown(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+ uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(ref) {
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(idle_ref) {
+ uv_idle_t h;
+ uv_idle_init(uv_default_loop(), &h);
+ uv_idle_start(&h, (uv_idle_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(async_ref) {
+ uv_async_t h;
+ uv_async_init(uv_default_loop(), &h, NULL);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(prepare_ref) {
+ uv_prepare_t h;
+ uv_prepare_init(uv_default_loop(), &h);
+ uv_prepare_start(&h, (uv_prepare_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(check_ref) {
+ uv_check_t h;
+ uv_check_init(uv_default_loop(), &h);
+ uv_check_start(&h, (uv_check_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void prepare_cb(uv_prepare_t* h) {
+ ASSERT(h != NULL);
+ uv_unref((uv_handle_t*)h);
+}
+
+
+TEST_IMPL(unref_in_prepare_cb) {
+ uv_prepare_t h;
+ uv_prepare_init(uv_default_loop(), &h);
+ uv_prepare_start(&h, prepare_cb);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_ref) {
+ uv_timer_t h;
+ uv_timer_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_ref2) {
+ uv_timer_t h;
+ uv_timer_init(uv_default_loop(), &h);
+ uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_event_ref) {
+ uv_fs_event_t h;
+ uv_fs_event_init(uv_default_loop(), &h);
+ uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_poll_ref) {
+ uv_fs_poll_t h;
+ uv_fs_poll_init(uv_default_loop(), &h);
+ uv_fs_poll_start(&h, NULL, ".", 999);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref2) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref2b) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_close((uv_handle_t*)&h, close_cb);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref3) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_and_shutdown);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref4) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_and_write);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref) {
+ uv_udp_t h;
+ uv_udp_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref2) {
+ struct sockaddr_in addr;
+ uv_udp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_udp_init(uv_default_loop(), &h);
+ uv_udp_bind(&h, (const struct sockaddr*) &addr, 0);
+ uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref3) {
+ struct sockaddr_in addr;
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_udp_send_t req;
+ uv_udp_t h;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_udp_init(uv_default_loop(), &h);
+ uv_udp_send(&req,
+ &h,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ (uv_udp_send_cb) req_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(req_cb_called == 1);
+ do_close(&h);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref2) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref3) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref4) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(process_ref) {
+ /* spawn_helper4 blocks indefinitely. */
+ char *argv[] = { NULL, "spawn_helper4", NULL };
+ uv_process_options_t options;
+ size_t exepath_size;
+ char exepath[256];
+ uv_process_t h;
+ int r;
+
+ memset(&options, 0, sizeof(options));
+ exepath_size = sizeof(exepath);
+
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+
+ argv[0] = exepath;
+ options.file = exepath;
+ options.args = argv;
+ options.exit_cb = NULL;
+
+ r = uv_spawn(uv_default_loop(), &h, &options);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ r = uv_process_kill(&h, /* SIGTERM */ 15);
+ ASSERT(r == 0);
+
+ do_close(&h);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(has_ref) {
+ uv_idle_t h;
+ uv_idle_init(uv_default_loop(), &h);
+ uv_ref((uv_handle_t*)&h);
+ ASSERT(uv_has_ref((uv_handle_t*)&h) == 1);
+ uv_unref((uv_handle_t*)&h);
+ ASSERT(uv_has_ref((uv_handle_t*)&h) == 0);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-run-nowait.c b/3rdparty/libuv/test/test-run-nowait.c
new file mode 100644
index 00000000000..43524f636d8
--- /dev/null
+++ b/3rdparty/libuv/test/test-run-nowait.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+static int timer_called = 0;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+ timer_called = 1;
+}
+
+
+TEST_IMPL(run_nowait) {
+ int r;
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-run-once.c b/3rdparty/libuv/test/test-run-once.c
new file mode 100644
index 00000000000..10cbf95e4ad
--- /dev/null
+++ b/3rdparty/libuv/test/test-run-once.c
@@ -0,0 +1,48 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#define NUM_TICKS 64
+
+static uv_idle_t idle_handle;
+static int idle_counter;
+
+
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(handle == &idle_handle);
+
+ if (++idle_counter == NUM_TICKS)
+ uv_idle_stop(handle);
+}
+
+
+TEST_IMPL(run_once) {
+ uv_idle_init(uv_default_loop(), &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+
+ while (uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(idle_counter == NUM_TICKS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-semaphore.c b/3rdparty/libuv/test/test-semaphore.c
new file mode 100644
index 00000000000..ac03bb08f17
--- /dev/null
+++ b/3rdparty/libuv/test/test-semaphore.c
@@ -0,0 +1,111 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ uv_mutex_t mutex;
+ uv_sem_t sem;
+ int delay;
+ volatile int posted;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ uv_mutex_lock(&c->mutex);
+ ASSERT(c->posted == 0);
+ uv_sem_post(&c->sem);
+ c->posted = 1;
+ uv_mutex_unlock(&c->mutex);
+}
+
+
+TEST_IMPL(semaphore_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sleep(100);
+ uv_mutex_lock(&wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_sem_wait(&wc.sem); /* should not block */
+ uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sem_wait(&wc.sem);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_3) {
+ uv_sem_t sem;
+
+ ASSERT(0 == uv_sem_init(&sem, 3));
+ uv_sem_wait(&sem); /* should not block */
+ uv_sem_wait(&sem); /* should not block */
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
+
+ uv_sem_post(&sem);
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
+
+ uv_sem_destroy(&sem);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-shutdown-close.c b/3rdparty/libuv/test/test-shutdown-close.c
new file mode 100644
index 00000000000..78c369be2d9
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-close.c
@@ -0,0 +1,108 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * These tests verify that the uv_shutdown callback is always made, even when
+ * it is immediately followed by an uv_close call.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static int connect_cb_called = 0;
+static int shutdown_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0 || status == UV_ECANCELED);
+ shutdown_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+ ASSERT(0 == uv_is_closing((uv_handle_t*) req->handle));
+ uv_close((uv_handle_t*) req->handle, close_cb);
+ ASSERT(1 == uv_is_closing((uv_handle_t*) req->handle));
+
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(shutdown_close_tcp) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ r = uv_tcp_init(uv_default_loop(), &h);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(shutdown_close_pipe) {
+ uv_pipe_t h;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &h, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-shutdown-eof.c b/3rdparty/libuv/test/test-shutdown-eof.c
new file mode 100644
index 00000000000..9f95e7561f2
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-eof.c
@@ -0,0 +1,182 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_timer_t timer;
+static uv_tcp_t tcp;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+static uv_buf_t qbuf;
+static int got_q;
+static int got_eof;
+static int called_connect_cb;
+static int called_shutdown_cb;
+static int called_tcp_close_cb;
+static int called_timer_close_cb;
+static int called_timer_cb;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT((uv_tcp_t*)t == &tcp);
+
+ if (nread == 0) {
+ free(buf->base);
+ return;
+ }
+
+ if (!got_q) {
+ ASSERT(nread == 1);
+ ASSERT(!got_eof);
+ ASSERT(buf->base[0] == 'Q');
+ free(buf->base);
+ got_q = 1;
+ puts("got Q");
+ } else {
+ ASSERT(nread == UV_EOF);
+ if (buf->base) {
+ free(buf->base);
+ }
+ got_eof = 1;
+ puts("got EOF");
+ }
+}
+
+
+static void shutdown_cb(uv_shutdown_t *req, int status) {
+ ASSERT(req == &shutdown_req);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(!got_eof);
+ ASSERT(called_tcp_close_cb == 0);
+ ASSERT(called_timer_close_cb == 0);
+ ASSERT(called_timer_cb == 0);
+
+ called_shutdown_cb++;
+}
+
+
+static void connect_cb(uv_connect_t *req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req == &connect_req);
+
+ /* Start reading from our connection so we can receive the EOF. */
+ uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb);
+
+ /*
+ * Write the letter 'Q' to gracefully kill the echo-server. This will not
+ * effect our connection.
+ */
+ uv_write(&write_req, (uv_stream_t*) &tcp, &qbuf, 1, NULL);
+
+ /* Shutdown our end of the connection. */
+ uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb);
+
+ called_connect_cb++;
+ ASSERT(called_shutdown_cb == 0);
+}
+
+
+static void tcp_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &tcp);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(got_q);
+ ASSERT(got_eof);
+ ASSERT(called_timer_cb == 1);
+
+ called_tcp_close_cb++;
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &timer);
+ called_timer_close_cb++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ uv_close((uv_handle_t*) handle, timer_close_cb);
+
+ /*
+ * The most important assert of the test: we have not received
+ * tcp_close_cb yet.
+ */
+ ASSERT(called_tcp_close_cb == 0);
+ uv_close((uv_handle_t*) &tcp, tcp_close_cb);
+
+ called_timer_cb++;
+}
+
+
+/*
+ * This test has a client which connects to the echo_server and immediately
+ * issues a shutdown. The echo-server, in response, will also shutdown their
+ * connection. We check, with a timer, that libuv is not automatically
+ * calling uv_close when the client receives the EOF from echo-server.
+ */
+TEST_IMPL(shutdown_eof) {
+ struct sockaddr_in server_addr;
+ int r;
+
+ qbuf.base = "Q";
+ qbuf.len = 1;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ uv_timer_start(&timer, timer_cb, 100, 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ r = uv_tcp_init(uv_default_loop(), &tcp);
+ ASSERT(!r);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ connect_cb);
+ ASSERT(!r);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(called_shutdown_cb == 1);
+ ASSERT(got_eof);
+ ASSERT(got_q);
+ ASSERT(called_tcp_close_cb == 1);
+ ASSERT(called_timer_close_cb == 1);
+ ASSERT(called_timer_cb == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
diff --git a/3rdparty/libuv/test/test-shutdown-twice.c b/3rdparty/libuv/test/test-shutdown-twice.c
new file mode 100644
index 00000000000..75c05435499
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-twice.c
@@ -0,0 +1,84 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This is a regression test for issue #1113 (calling uv_shutdown twice will
+ * leave a ghost request in the system)
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_shutdown_t req1;
+static uv_shutdown_t req2;
+
+static int shutdown_cb_called = 0;
+
+static void close_cb(uv_handle_t* handle) {
+
+}
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &req1);
+ ASSERT(status == 0);
+ shutdown_cb_called++;
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+
+ r = uv_shutdown(&req1, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+ r = uv_shutdown(&req2, req->handle, shutdown_cb);
+ ASSERT(r != 0);
+
+}
+
+TEST_IMPL(shutdown_twice) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+ uv_tcp_t h;
+
+ uv_connect_t connect_req;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ r = uv_tcp_init(loop, &h);
+
+ r = uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(shutdown_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-signal-multiple-loops.c b/3rdparty/libuv/test/test-signal-multiple-loops.c
new file mode 100644
index 00000000000..158129919bd
--- /dev/null
+++ b/3rdparty/libuv/test/test-signal-multiple-loops.c
@@ -0,0 +1,290 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/* This test does not pretend to be cross-platform. */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* The value of NUM_SIGNAL_HANDLING_THREADS is not arbitrary; it needs to be a
+ * multiple of three for reasons that will become clear when you scroll down.
+ * We're basically creating three different thread groups. The total needs
+ * to be divisible by three in order for the numbers in the final check to
+ * match up.
+ */
+#define NUM_SIGNAL_HANDLING_THREADS 24
+#define NUM_LOOP_CREATING_THREADS 10
+
+enum signal_action {
+ ONLY_SIGUSR1,
+ ONLY_SIGUSR2,
+ SIGUSR1_AND_SIGUSR2
+};
+
+static uv_sem_t sem;
+static uv_mutex_t counter_lock;
+static volatile int stop = 0;
+
+static volatile int signal1_cb_counter = 0;
+static volatile int signal2_cb_counter = 0;
+static volatile int loop_creation_counter = 0;
+
+
+static void increment_counter(volatile int* counter) {
+ uv_mutex_lock(&counter_lock);
+ ++(*counter);
+ uv_mutex_unlock(&counter_lock);
+}
+
+
+static void signal1_cb(uv_signal_t* handle, int signum) {
+ ASSERT(signum == SIGUSR1);
+ increment_counter(&signal1_cb_counter);
+ uv_signal_stop(handle);
+}
+
+
+static void signal2_cb(uv_signal_t* handle, int signum) {
+ ASSERT(signum == SIGUSR2);
+ increment_counter(&signal2_cb_counter);
+ uv_signal_stop(handle);
+}
+
+
+static void signal_handling_worker(void* context) {
+ enum signal_action action;
+ uv_signal_t signal1a;
+ uv_signal_t signal1b;
+ uv_signal_t signal2;
+ uv_loop_t loop;
+ int r;
+
+ action = (enum signal_action) (uintptr_t) context;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ /* Setup the signal watchers and start them. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_init(&loop, &signal1a);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ r = uv_signal_init(&loop, &signal1b);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_init(&loop, &signal2);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
+ ASSERT(r == 0);
+ }
+
+ /* Signal watchers are now set up. */
+ uv_sem_post(&sem);
+
+ /* Wait for all signals. The signal callbacks stop the watcher, so uv_run
+ * will return when all signal watchers caught a signal.
+ */
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Restart the signal watchers. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
+ ASSERT(r == 0);
+ }
+
+ /* Wait for signals once more. */
+ uv_sem_post(&sem);
+
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Close the watchers. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ uv_close((uv_handle_t*) &signal1a, NULL);
+ uv_close((uv_handle_t*) &signal1b, NULL);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ uv_close((uv_handle_t*) &signal2, NULL);
+ }
+
+ /* Wait for the signal watchers to close. */
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_loop_close(&loop);
+}
+
+
+static void signal_unexpected_cb(uv_signal_t* handle, int signum) {
+ ASSERT(0 && "signal_unexpected_cb should never be called");
+}
+
+
+static void loop_creating_worker(void* context) {
+ (void) context;
+
+ do {
+ uv_loop_t *loop;
+ uv_signal_t signal;
+ int r;
+
+ loop = malloc(sizeof(*loop));
+ ASSERT(loop != NULL);
+ ASSERT(0 == uv_loop_init(loop));
+
+ r = uv_signal_init(loop, &signal);
+ ASSERT(r == 0);
+
+ r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &signal, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_loop_close(loop);
+ free(loop);
+
+ increment_counter(&loop_creation_counter);
+ } while (!stop);
+}
+
+
+TEST_IMPL(signal_multiple_loops) {
+ uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS];
+ uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS];
+ enum signal_action action;
+ sigset_t sigset;
+ int i;
+ int r;
+
+ r = uv_sem_init(&sem, 0);
+ ASSERT(r == 0);
+
+ r = uv_mutex_init(&counter_lock);
+ ASSERT(r == 0);
+
+ /* Create a couple of threads that create a destroy loops continuously. */
+ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
+ r = uv_thread_create(&loop_creating_threads[i],
+ loop_creating_worker,
+ NULL);
+ ASSERT(r == 0);
+ }
+
+ /* Create a couple of threads that actually handle signals. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
+ switch (i % 3) {
+ case 0: action = ONLY_SIGUSR1; break;
+ case 1: action = ONLY_SIGUSR2; break;
+ case 2: action = SIGUSR1_AND_SIGUSR2; break;
+ }
+
+ r = uv_thread_create(&signal_handling_threads[i],
+ signal_handling_worker,
+ (void*) (uintptr_t) action);
+ ASSERT(r == 0);
+ }
+
+ /* Wait until all threads have started and set up their signal watchers. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
+ uv_sem_wait(&sem);
+
+ r = kill(getpid(), SIGUSR1);
+ ASSERT(r == 0);
+ r = kill(getpid(), SIGUSR2);
+ ASSERT(r == 0);
+
+ /* Wait for all threads to handle these signals. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
+ uv_sem_wait(&sem);
+
+ /* Block all signals to this thread, so we are sure that from here the signal
+ * handler runs in another thread. This is is more likely to catch thread and
+ * signal safety issues if there are any.
+ */
+ sigfillset(&sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, NULL);
+
+ r = kill(getpid(), SIGUSR1);
+ ASSERT(r == 0);
+ r = kill(getpid(), SIGUSR2);
+ ASSERT(r == 0);
+
+ /* Wait for all signal handling threads to exit. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
+ r = uv_thread_join(&signal_handling_threads[i]);
+ ASSERT(r == 0);
+ }
+
+ /* Tell all loop creating threads to stop. */
+ stop = 1;
+
+ /* Wait for all loop creating threads to exit. */
+ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
+ r = uv_thread_join(&loop_creating_threads[i]);
+ ASSERT(r == 0);
+ }
+
+ printf("signal1_cb calls: %d\n", signal1_cb_counter);
+ printf("signal2_cb calls: %d\n", signal2_cb_counter);
+ printf("loops created and destroyed: %d\n", loop_creation_counter);
+
+ /* The division by three reflects the fact that we spawn three different
+ * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each.
+ */
+ ASSERT(signal1_cb_counter == 8 * (NUM_SIGNAL_HANDLING_THREADS / 3));
+ ASSERT(signal2_cb_counter == 4 * (NUM_SIGNAL_HANDLING_THREADS / 3));
+
+ /* We don't know exactly how much loops will be created and destroyed, but at
+ * least there should be 1 for every loop creating thread.
+ */
+ ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-signal.c b/3rdparty/libuv/test/test-signal.c
new file mode 100644
index 00000000000..fcdd8e4d2dd
--- /dev/null
+++ b/3rdparty/libuv/test/test-signal.c
@@ -0,0 +1,152 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/* This test does not pretend to be cross-platform. */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NSIGNALS 10
+
+struct timer_ctx {
+ unsigned int ncalls;
+ uv_timer_t handle;
+ int signum;
+};
+
+struct signal_ctx {
+ enum { CLOSE, STOP } stop_or_close;
+ unsigned int ncalls;
+ uv_signal_t handle;
+ int signum;
+};
+
+
+static void signal_cb(uv_signal_t* handle, int signum) {
+ struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle);
+ ASSERT(signum == ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS) {
+ if (ctx->stop_or_close == STOP)
+ uv_signal_stop(handle);
+ else if (ctx->stop_or_close == CLOSE)
+ uv_close((uv_handle_t*)handle, NULL);
+ else
+ ASSERT(0);
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);
+
+ raise(ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS)
+ uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ ctx->stop_or_close = CLOSE;
+ ASSERT(0 == uv_signal_init(loop, &ctx->handle));
+ ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum));
+}
+
+
+static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ ASSERT(0 == uv_timer_init(loop, &ctx->handle));
+ ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5));
+}
+
+
+TEST_IMPL(we_get_signal) {
+ struct signal_ctx sc;
+ struct timer_ctx tc;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ start_timer(loop, SIGCHLD, &tc);
+ start_watcher(loop, SIGCHLD, &sc);
+ sc.stop_or_close = STOP; /* stop, don't close the signal handle */
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ start_timer(loop, SIGCHLD, &tc);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ sc.ncalls = 0;
+ sc.stop_or_close = CLOSE; /* now close it when it's done */
+ uv_signal_start(&sc.handle, signal_cb, SIGCHLD);
+
+ start_timer(loop, SIGCHLD, &tc);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(we_get_signals) {
+ struct signal_ctx sc[4];
+ struct timer_ctx tc[2];
+ uv_loop_t* loop;
+ unsigned int i;
+
+ loop = uv_default_loop();
+ start_watcher(loop, SIGUSR1, sc + 0);
+ start_watcher(loop, SIGUSR1, sc + 1);
+ start_watcher(loop, SIGUSR2, sc + 2);
+ start_watcher(loop, SIGUSR2, sc + 3);
+ start_timer(loop, SIGUSR1, tc + 0);
+ start_timer(loop, SIGUSR2, tc + 1);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ for (i = 0; i < ARRAY_SIZE(sc); i++)
+ ASSERT(sc[i].ncalls == NSIGNALS);
+
+ for (i = 0; i < ARRAY_SIZE(tc); i++)
+ ASSERT(tc[i].ncalls == NSIGNALS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-socket-buffer-size.c b/3rdparty/libuv/test/test-socket-buffer-size.c
new file mode 100644
index 00000000000..72f8c2524c0
--- /dev/null
+++ b/3rdparty/libuv/test/test-socket-buffer-size.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static uv_udp_t udp;
+static uv_tcp_t tcp;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void check_buffer_size(uv_handle_t* handle) {
+ int value;
+
+ value = 0;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+ ASSERT(value > 0);
+
+ value = 10000;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+
+ value = 0;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+ /* linux sets double the value */
+ ASSERT(value == 10000 || value == 20000);
+}
+
+
+TEST_IMPL(socket_buffer_size) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp));
+ ASSERT(0 == uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0));
+ check_buffer_size((uv_handle_t*) &tcp);
+ uv_close((uv_handle_t*) &tcp, close_cb);
+
+ ASSERT(0 == uv_udp_init(uv_default_loop(), &udp));
+ ASSERT(0 == uv_udp_bind(&udp, (struct sockaddr*) &addr, 0));
+ check_buffer_size((uv_handle_t*) &udp);
+ uv_close((uv_handle_t*) &udp, close_cb);
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-spawn.c b/3rdparty/libuv/test/test-spawn.c
new file mode 100644
index 00000000000..eba54ae7054
--- /dev/null
+++ b/3rdparty/libuv/test/test-spawn.c
@@ -0,0 +1,1706 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+# if defined(__MINGW32__)
+# include <basetyps.h>
+# endif
+# include <shellapi.h>
+# include <wchar.h>
+#else
+# include <unistd.h>
+# include <sys/wait.h>
+#endif
+
+
+static int close_cb_called;
+static int exit_cb_called;
+static uv_process_t process;
+static uv_timer_t timer;
+static uv_process_options_t options;
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static int no_term_signal;
+static int timer_counter;
+
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+
+static void close_cb(uv_handle_t* handle) {
+ printf("close_cb\n");
+ close_cb_called++;
+}
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 1);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+}
+
+
+static void fail_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void kill_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ int err;
+
+ printf("exit_cb\n");
+ exit_cb_called++;
+#ifdef _WIN32
+ ASSERT(exit_status == 1);
+#else
+ ASSERT(exit_status == 0);
+#endif
+ ASSERT(no_term_signal || term_signal == 15);
+ uv_close((uv_handle_t*)process, close_cb);
+
+ /*
+ * Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ * This process should be dead.
+ */
+ err = uv_kill(process->pid, 0);
+ ASSERT(err == UV_ESRCH);
+}
+
+static void detach_failure_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("detach_cb\n");
+ exit_cb_called++;
+}
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread > 0) {
+ output_used += nread;
+ } else if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ uv_read_stop(tcp);
+ on_read(tcp, nread, buf);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void init_process_options(char* test, uv_exit_cb exit_cb) {
+ /* Note spawn_helper1 defined in test/run-tests.c */
+ int r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = test;
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+ options.flags = 0;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_process_kill(&process, /* SIGTERM */ 15);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+static void timer_counter_cb(uv_timer_t* handle) {
+ ++timer_counter;
+}
+
+
+TEST_IMPL(spawn_fails) {
+ int r;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
+ int r;
+ int status;
+ int err;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ /* verify the child is successfully cleaned up within libuv */
+ do
+ err = waitpid(process.pid, &status, 0);
+ while (err == -1 && errno == EINTR);
+
+ ASSERT(err == -1);
+ ASSERT(errno == ECHILD);
+
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_exit_code) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[2];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
+#ifndef _WIN32
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* Replace stderr with our file */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ file = dup2(r, STDERR_FILENO);
+ ASSERT(file != -1);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Unix only test");
+#endif
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
+#ifndef _WIN32
+ int r;
+ uv_file stdout_file;
+ uv_file stderr_file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* open 'stdout_file' and replace STDOUT_FILENO with it */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stdout_file = dup2(r, STDOUT_FILENO);
+ ASSERT(stdout_file != -1);
+
+ /* open 'stderr_file' and replace STDERR_FILENO with it */
+ r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stderr_file = dup2(r, STDERR_FILENO);
+ ASSERT(stderr_file != -1);
+
+ /* now we're going to swap them: the child process' stdout will be our
+ * stderr_file and vice versa */
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = stderr_file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = stdout_file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+
+ /* check the content of stdout_file */
+ r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
+ ASSERT(r >= 15);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strncmp("hello errworld\n", output, 15) == 0);
+
+ /* check the content of stderr_file */
+ r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
+ ASSERT(r >= 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strncmp("hello world\n", output, 12) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Unix only test");
+#endif
+}
+
+
+TEST_IMPL(spawn_stdin) {
+ int r;
+ uv_pipe_t out;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ char buffer[] = "hello-from-spawn_stdin";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ buf.base = buffer;
+ buf.len = sizeof(buffer);
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
+ ASSERT(strcmp(buffer, output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdio_greater_than_3) {
+ int r;
+ uv_pipe_t pipe;
+ uv_stdio_container_t stdio[4];
+
+ init_process_options("spawn_helper5", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &pipe, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+ options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[3].data.stream = (uv_stream_t*)&pipe;
+ options.stdio_count = 4;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output from stdio[3] is: %s", output);
+ ASSERT(strcmp("fourth stdio!\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_ignored_stdio) {
+ int r;
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ options.stdio = NULL;
+ options.stdio_count = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_kill) {
+ int r;
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_preserve_env) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper7", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*) &out;
+ options.stdio_count = 2;
+
+ r = putenv("ENV_TEST=testval");
+ ASSERT(r == 0);
+
+ /* Explicitly set options.env to NULL to test for env clobbering. */
+ options.env = NULL;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("testval", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_detached) {
+ int r;
+
+ init_process_options("spawn_helper4", detach_failure_cb);
+
+ options.flags |= UV_PROCESS_DETACHED;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&process);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_kill(process.pid, 0);
+ ASSERT(r == 0);
+
+ r = uv_kill(process.pid, 15);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(spawn_and_kill_with_std) {
+ int r;
+ uv_pipe_t in, out, err;
+ uv_write_t write;
+ char message[] = "Nancy's joining me because the message this evening is "
+ "not my message but ours.";
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_pipe_init(uv_default_loop(), &in, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &out, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &err, 0);
+ ASSERT(r == 0);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[2].data.stream = (uv_stream_t*)&err;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(message, sizeof message);
+ r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_ping) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(strcmp(output, "TEST") == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_same_stdout_stderr) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(strcmp(output, "TEST") == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_closed_process_io) {
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ static char buffer[] = "hello-from-spawn_stdin\n";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) &in;
+ options.stdio_count = 1;
+
+ close(0); /* Close process stdin. */
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init(buffer, sizeof(buffer));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* process, child stdin */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(kill) {
+ int r;
+
+#ifdef _WIN32
+ no_term_signal = 1;
+#endif
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_kill(process.pid, 0);
+ ASSERT(r == 0);
+
+ /* Kill the process. */
+ r = uv_kill(process.pid, /* SIGTERM */ 15);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
+ int r;
+ uv_pipe_t out;
+ char name[64];
+ HANDLE pipe_handle;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ /* Create a pipe that'll cause a collision. */
+ snprintf(name,
+ sizeof(name),
+ "\\\\.\\pipe\\uv\\%p-%d",
+ &out,
+ GetCurrentProcessId());
+ pipe_handle = CreateNamedPipeA(name,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 10,
+ 65536,
+ 65536,
+ 0,
+ NULL);
+ ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#if !defined(USING_UV_SHARED)
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
+
+TEST_IMPL(argument_escaping) {
+ const WCHAR* test_str[] = {
+ L"",
+ L"HelloWorld",
+ L"Hello World",
+ L"Hello\"World",
+ L"Hello World\\",
+ L"Hello\\\"World",
+ L"Hello\\World",
+ L"Hello\\\\World",
+ L"Hello World\\",
+ L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
+ };
+ const int count = sizeof(test_str) / sizeof(*test_str);
+ WCHAR** test_output;
+ WCHAR* command_line;
+ WCHAR** cracked;
+ size_t total_size = 0;
+ int i;
+ int num_args;
+ int result;
+
+ char* verbatim[] = {
+ "cmd.exe",
+ "/c",
+ "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
+ NULL
+ };
+ WCHAR* verbatim_output;
+ WCHAR* non_verbatim_output;
+
+ test_output = calloc(count, sizeof(WCHAR*));
+ ASSERT(test_output != NULL);
+ for (i = 0; i < count; ++i) {
+ test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
+ quote_cmd_arg(test_str[i], test_output[i]);
+ wprintf(L"input : %s\n", test_str[i]);
+ wprintf(L"output: %s\n", test_output[i]);
+ total_size += wcslen(test_output[i]) + 1;
+ }
+ command_line = calloc(total_size + 1, sizeof(WCHAR));
+ ASSERT(command_line != NULL);
+ for (i = 0; i < count; ++i) {
+ wcscat(command_line, test_output[i]);
+ wcscat(command_line, L" ");
+ }
+ command_line[total_size - 1] = L'\0';
+
+ wprintf(L"command_line: %s\n", command_line);
+
+ cracked = CommandLineToArgvW(command_line, &num_args);
+ for (i = 0; i < num_args; ++i) {
+ wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
+ ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
+ }
+
+ LocalFree(cracked);
+ for (i = 0; i < count; ++i) {
+ free(test_output[i]);
+ }
+
+ result = make_program_args(verbatim, 1, &verbatim_output);
+ ASSERT(result == 0);
+ result = make_program_args(verbatim, 0, &non_verbatim_output);
+ ASSERT(result == 0);
+
+ wprintf(L" verbatim_output: %s\n", verbatim_output);
+ wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
+
+ ASSERT(wcscmp(verbatim_output,
+ L"cmd.exe /c c:\\path\\to\\node.exe --eval "
+ L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
+ ASSERT(wcscmp(non_verbatim_output,
+ L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
+ L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
+
+ free(verbatim_output);
+ free(non_verbatim_output);
+
+ return 0;
+}
+
+int make_program_env(char** env_block, WCHAR** dst_ptr);
+
+TEST_IMPL(environment_creation) {
+ int i;
+ char* environment[] = {
+ "FOO=BAR",
+ "SYSTEM=ROOT", /* substring of a supplied var name */
+ "SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ "TEMP=C:\\Temp",
+ "INVALID",
+ "BAZ=QUX",
+ "B_Z=QUX",
+ "B\xe2\x82\xacZ=QUX",
+ "B\xf0\x90\x80\x82Z=QUX",
+ "B\xef\xbd\xa1Z=QUX",
+ "B\xf0\xa3\x91\x96Z=QUX",
+ "BAZ", /* repeat, invalid variable */
+ NULL
+ };
+ WCHAR* wenvironment[] = {
+ L"BAZ=QUX",
+ L"B_Z=QUX",
+ L"B\x20acZ=QUX",
+ L"B\xd800\xdc02Z=QUX",
+ L"B\xd84d\xdc56Z=QUX",
+ L"B\xff61Z=QUX",
+ L"FOO=BAR",
+ L"SYSTEM=ROOT", /* substring of a supplied var name */
+ L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ L"TEMP=C:\\Temp",
+ };
+ WCHAR* from_env[] = {
+ /* list should be kept in sync with list
+ * in process.c, minus variables in wenvironment */
+ L"HOMEDRIVE",
+ L"HOMEPATH",
+ L"LOGONSERVER",
+ L"PATH",
+ L"USERDOMAIN",
+ L"USERNAME",
+ L"USERPROFILE",
+ L"SYSTEMDRIVE",
+ L"SYSTEMROOT",
+ L"WINDIR",
+ /* test for behavior in the absence of a
+ * required-environment variable: */
+ L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
+ };
+ int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
+ int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
+ WCHAR *expected[ARRAY_SIZE(from_env)];
+ int result;
+ WCHAR* str;
+ WCHAR* prev;
+ WCHAR* env;
+
+ for (i = 0; i < ARRAY_SIZE(from_env); i++) {
+ /* copy expected additions to environment locally */
+ size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
+ if (len == 0) {
+ found_in_usr_env[i] = 1;
+ str = malloc(1 * sizeof(WCHAR));
+ *str = 0;
+ expected[i] = str;
+ } else {
+ size_t name_len = wcslen(from_env[i]);
+ str = malloc((name_len+1+len) * sizeof(WCHAR));
+ wmemcpy(str, from_env[i], name_len);
+ expected[i] = str;
+ str += name_len;
+ *str++ = L'=';
+ GetEnvironmentVariableW(from_env[i], str, len);
+ }
+ }
+
+ result = make_program_env(environment, &env);
+ ASSERT(result == 0);
+
+ for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
+ int found = 0;
+#if 0
+ _cputws(str);
+ putchar('\n');
+#endif
+ for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
+ if (!wcscmp(str, wenvironment[i])) {
+ ASSERT(!found_in_loc_env[i]);
+ found_in_loc_env[i] = 1;
+ found = 1;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
+ if (!wcscmp(str, expected[i])) {
+ ASSERT(!found_in_usr_env[i]);
+ found_in_usr_env[i] = 1;
+ found = 1;
+ }
+ }
+ if (prev) { /* verify sort order -- requires Vista */
+#if _WIN32_WINNT >= 0x0600 && \
+ (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
+ ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
+#endif
+ }
+ ASSERT(found); /* verify that we expected this variable */
+ }
+
+ /* verify that we found all expected variables */
+ for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
+ ASSERT(found_in_loc_env[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(expected); i++) {
+ ASSERT(found_in_usr_env[i]);
+ }
+
+ return 0;
+}
+#endif
+
+/* Regression test for issue #909 */
+TEST_IMPL(spawn_with_an_odd_path) {
+ int r;
+
+ char newpath[2048];
+ char *path = getenv("PATH");
+ ASSERT(path != NULL);
+ snprintf(newpath, 2048, ";.;%s", path);
+ SetEnvironmentVariable("PATH", newpath);
+
+ init_process_options("", exit_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_setgid) {
+ int r;
+ struct passwd* pw;
+
+ /* if not root, then this will fail. */
+ uv_uid_t uid = getuid();
+ if (uid != 0) {
+ fprintf(stderr, "spawn_setuid_setgid skipped: not root\n");
+ return 0;
+ }
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* become the "nobody" user. */
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ options.uid = pw->pw_uid;
+ options.gid = pw->pw_gid;
+ options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ if (r == UV_EACCES)
+ RETURN_SKIP("user 'nobody' cannot access the test runner");
+
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ ASSERT(0 == setgid(pw->pw_gid));
+ ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ ASSERT(0 == setgid(pw->pw_gid));
+ ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+#ifdef _WIN32
+
+static void exit_cb_unexpected(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(0 && "should not have been called");
+}
+
+
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = (uv_uid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = (uv_gid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_auto_unref) {
+ init_process_options("spawn_helper1", NULL);
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fs_open) {
+ int fd;
+ uv_fs_t fs_req;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[1];
+
+ fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
+ ASSERT(fd >= 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ init_process_options("spawn_helper8", exit_cb);
+
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) &in;
+ options.stdio_count = 1;
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init((char*) &fd, sizeof(fd));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* One for `in`, one for process */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif /* !_WIN32 */
+
+
+#ifndef _WIN32
+TEST_IMPL(closed_fd_events) {
+ uv_stdio_container_t stdio[3];
+ uv_pipe_t pipe_handle;
+ int fd[2];
+
+ /* create a pipe and share it with a child process */
+ ASSERT(0 == pipe(fd));
+
+ /* spawn_helper4 blocks indefinitely. */
+ init_process_options("spawn_helper4", exit_cb);
+ options.stdio_count = 3;
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_INHERIT_FD;
+ options.stdio[0].data.fd = fd[0];
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ uv_unref((uv_handle_t*) &process);
+
+ /* read from the pipe with uv */
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ fd[0] = -1;
+
+ ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
+
+ ASSERT(1 == write(fd[1], "", 1));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ /* should have received just one byte */
+ ASSERT(output_used == 1);
+
+ /* close the pipe and see if we still get events */
+ uv_close((uv_handle_t*) &pipe_handle, close_cb);
+
+ ASSERT(1 == write(fd[1], "", 1));
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
+
+ /* see if any spurious events interrupt the timer */
+ if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
+ /* have to run again to really trigger the timer */
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ ASSERT(timer_counter == 1);
+
+ /* cleanup */
+ ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
+ ASSERT(0 == close(fd[1]));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_reads_child_path) {
+ int r;
+ int len;
+ char file[64];
+ char path[1024];
+ char* env[3];
+
+ /* Need to carry over the dynamic linker path when the test runner is
+ * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
+ */
+#if defined(__APPLE__)
+ static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
+#else
+ static const char dyld_path_var[] = "LD_LIBRARY_PATH";
+#endif
+
+ /* Set up the process, but make sure that the file to run is relative and */
+ /* requires a lookup into PATH */
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* Set up the PATH env variable */
+ for (len = strlen(exepath);
+ exepath[len - 1] != '/' && exepath[len - 1] != '\\';
+ len--);
+ strcpy(file, exepath + len);
+ exepath[len] = 0;
+ strcpy(path, "PATH=");
+ strcpy(path + 5, exepath);
+
+ env[0] = path;
+ env[1] = getenv(dyld_path_var);
+ env[2] = NULL;
+
+ if (env[1] != NULL) {
+ static char buf[1024 + sizeof(dyld_path_var)];
+ snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
+ env[1] = buf;
+ }
+
+ options.file = file;
+ options.args[0] = file;
+ options.env = env;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#ifndef _WIN32
+static int mpipe(int *fds) {
+ if (pipe(fds) == -1)
+ return -1;
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+ return 0;
+}
+#else
+static int mpipe(int *fds) {
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return -1;
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return -1;
+ }
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_inherit_streams) {
+ uv_process_t child_req;
+ uv_stdio_container_t child_stdio[2];
+ int fds_stdin[2];
+ int fds_stdout[2];
+ uv_pipe_t pipe_stdin_child;
+ uv_pipe_t pipe_stdout_child;
+ uv_pipe_t pipe_stdin_parent;
+ uv_pipe_t pipe_stdout_parent;
+ unsigned char ubuf[OUTPUT_SIZE - 1];
+ uv_buf_t buf;
+ unsigned int i;
+ int r;
+ uv_write_t write_req;
+ uv_loop_t* loop;
+
+ init_process_options("spawn_helper9", exit_cb);
+
+ loop = uv_default_loop();
+ ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
+
+ ASSERT(mpipe(fds_stdin) != -1);
+ ASSERT(mpipe(fds_stdout) != -1);
+
+ ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
+
+ child_stdio[0].flags = UV_INHERIT_STREAM;
+ child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
+
+ child_stdio[1].flags = UV_INHERIT_STREAM;
+ child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
+
+ options.stdio = child_stdio;
+ options.stdio_count = 2;
+
+ ASSERT(uv_spawn(loop, &child_req, &options) == 0);
+
+ uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
+ uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
+
+ buf = uv_buf_init((char*)ubuf, sizeof ubuf);
+ for (i = 0; i < sizeof ubuf; ++i)
+ ubuf[i] = i & 255u;
+ memset(output, 0, sizeof ubuf);
+
+ r = uv_write(&write_req,
+ (uv_stream_t*)&pipe_stdin_parent,
+ &buf,
+ 1,
+ write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+
+ r = memcmp(ubuf, output, sizeof ubuf);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Helper for child process of spawn_inherit_streams */
+#ifndef _WIN32
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ for (;;) {
+ ssize_t r, w, c;
+ do {
+ r = read(0, buf, sizeof buf);
+ } while (r == -1 && errno == EINTR);
+ if (r == 0) {
+ return 1;
+ }
+ ASSERT(r > 0);
+ c = r;
+ pbuf = buf;
+ while (c) {
+ do {
+ w = write(1, pbuf, (size_t)c);
+ } while (w == -1 && errno == EINTR);
+ ASSERT(w >= 0);
+ pbuf = pbuf + w;
+ c = c - w;
+ }
+ }
+ return 2;
+}
+#else
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ ASSERT(h_stdin != INVALID_HANDLE_VALUE);
+ ASSERT(h_stdout != INVALID_HANDLE_VALUE);
+ for (;;) {
+ DWORD n_read;
+ DWORD n_written;
+ DWORD to_write;
+ if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
+ ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
+ return 1;
+ }
+ to_write = n_read;
+ pbuf = buf;
+ while (to_write) {
+ ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
+ to_write -= n_written;
+ pbuf += n_written;
+ }
+ }
+ return 2;
+}
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-stdio-over-pipes.c b/3rdparty/libuv/test/test-stdio-over-pipes.c
new file mode 100644
index 00000000000..15744761049
--- /dev/null
+++ b/3rdparty/libuv/test/test-stdio-over-pipes.c
@@ -0,0 +1,255 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static uv_process_options_t options;
+static int close_cb_called;
+static int exit_cb_called;
+static int on_read_cb_called;
+static int after_write_cb_called;
+static uv_pipe_t in;
+static uv_pipe_t out;
+static uv_loop_t* loop;
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 0);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+ uv_close((uv_handle_t*)&in, close_cb);
+ uv_close((uv_handle_t*)&out, close_cb);
+}
+
+
+static void init_process_options(char* test, uv_exit_cb exit_cb) {
+ int r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = test;
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void after_write(uv_write_t* req, int status) {
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ /* Free the read/write buffer and the request */
+ free(req);
+
+ after_write_cb_called++;
+}
+
+
+static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) {
+ uv_write_t* req;
+ uv_buf_t wrbuf;
+ int r;
+
+ ASSERT(nread > 0 || nread == UV_EOF);
+
+ if (nread > 0) {
+ output_used += nread;
+ if (output_used == 12) {
+ ASSERT(memcmp("hello world\n", output, 12) == 0);
+ wrbuf = uv_buf_init(output, output_used);
+ req = malloc(sizeof(*req));
+ r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write);
+ ASSERT(r == 0);
+ }
+ }
+
+ on_read_cb_called++;
+}
+
+
+TEST_IMPL(stdio_over_pipes) {
+ int r;
+ uv_process_t process;
+ uv_stdio_container_t stdio[2];
+
+ loop = uv_default_loop();
+
+ init_process_options("stdio_over_pipes_helper", exit_cb);
+
+ uv_pipe_init(loop, &out, 0);
+ uv_pipe_init(loop, &in, 0);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(loop, &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(on_read_cb_called > 1);
+ ASSERT(after_write_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(memcmp("hello world\n", output, 12) == 0);
+ ASSERT(output_used == 12);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+/* Everything here runs in a child process. */
+
+static int on_pipe_read_called;
+static int after_write_called;
+static uv_pipe_t stdin_pipe;
+static uv_pipe_t stdout_pipe;
+
+static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(memcmp("hello world\n", buf->base, nread) == 0);
+ on_pipe_read_called++;
+
+ free(buf->base);
+
+ uv_close((uv_handle_t*)&stdin_pipe, close_cb);
+ uv_close((uv_handle_t*)&stdout_pipe, close_cb);
+}
+
+
+static void after_pipe_write(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ after_write_called++;
+}
+
+
+static void on_read_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+int stdio_over_pipes_helper(void) {
+ /* Write several buffers to test that the write order is preserved. */
+ char* buffers[] = {
+ "he",
+ "ll",
+ "o ",
+ "wo",
+ "rl",
+ "d",
+ "\n"
+ };
+
+ uv_write_t write_req[ARRAY_SIZE(buffers)];
+ uv_buf_t buf[ARRAY_SIZE(buffers)];
+ unsigned int i;
+ int r;
+ uv_loop_t* loop = uv_default_loop();
+
+ ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
+ ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
+
+ r = uv_pipe_init(loop, &stdin_pipe, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_init(loop, &stdout_pipe, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&stdin_pipe, 0);
+ uv_pipe_open(&stdout_pipe, 1);
+
+ /* Unref both stdio handles to make sure that all writes complete. */
+ uv_unref((uv_handle_t*)&stdin_pipe);
+ uv_unref((uv_handle_t*)&stdout_pipe);
+
+ for (i = 0; i < ARRAY_SIZE(buffers); i++) {
+ buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i]));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(buffers); i++) {
+ r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1,
+ after_pipe_write);
+ ASSERT(r == 0);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(after_write_called == 7);
+ ASSERT(on_pipe_read_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ uv_ref((uv_handle_t*)&stdout_pipe);
+ uv_ref((uv_handle_t*)&stdin_pipe);
+
+ r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(after_write_called == 7);
+ ASSERT(on_pipe_read_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-bind-error.c b/3rdparty/libuv/test/test-tcp-bind-error.c
new file mode 100644
index 00000000000..10ed68e10ec
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-bind-error.c
@@ -0,0 +1,216 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrinuse) {
+ struct sockaddr_in addr;
+ uv_tcp_t server1, server2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ r = uv_tcp_init(uv_default_loop(), &server1);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &server2);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server1, 128, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, 128, NULL);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrnotavail_1) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.255.255.255", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ /* It seems that Linux is broken here - bind succeeds. */
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0 || r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrnotavail_2) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("4.4.4.4", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_fault) {
+ char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ struct sockaddr_in* garbage_addr;
+ uv_tcp_t server;
+ int r;
+
+ garbage_addr = (struct sockaddr_in*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Notes: On Linux uv_bind(server, NULL) will segfault the program. */
+
+TEST_IMPL(tcp_bind_error_inval) {
+ struct sockaddr_in addr1;
+ struct sockaddr_in addr2;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1));
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_localhost_ok) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_invalid_flags) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY);
+ ASSERT(r == UV_EINVAL);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_listen_without_bind) {
+ int r;
+ uv_tcp_t server;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server, 128, NULL);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-bind6-error.c b/3rdparty/libuv/test/test-tcp-bind6-error.c
new file mode 100644
index 00000000000..b762bcb3d1b
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-bind6-error.c
@@ -0,0 +1,176 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_bind6_error_addrinuse) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server1, server2;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server1);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &server2);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server1, 128, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, 128, NULL);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_error_addrnotavail) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_error_fault) {
+ char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ struct sockaddr_in6* garbage_addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ garbage_addr = (struct sockaddr_in6*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Notes: On Linux uv_bind6(server, NULL) will segfault the program. */
+
+TEST_IMPL(tcp_bind6_error_inval) {
+ struct sockaddr_in6 addr1;
+ struct sockaddr_in6 addr2;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1));
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_localhost_ok) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-close-accept.c b/3rdparty/libuv/test/test-tcp-close-accept.c
new file mode 100644
index 00000000000..5517aaf99e6
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close-accept.c
@@ -0,0 +1,188 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* this test is Unix only */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static struct sockaddr_in addr;
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_outgoing[2];
+static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)];
+static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)];
+static uv_tcp_t tcp_check;
+static uv_connect_t tcp_check_req;
+static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)];
+static unsigned int got_connections;
+static unsigned int close_cb_called;
+static unsigned int write_cb_called;
+static unsigned int read_cb_called;
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ unsigned int i;
+ uv_buf_t buf;
+ uv_stream_t* outgoing;
+
+ if (req == &tcp_check_req) {
+ ASSERT(status != 0);
+
+ /* Close check and incoming[0], time to finish test */
+ uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
+ uv_close((uv_handle_t*) &tcp_check, close_cb);
+ return;
+ }
+
+ ASSERT(status == 0);
+ ASSERT(connect_reqs <= req);
+ ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs));
+ i = req - connect_reqs;
+
+ buf = uv_buf_init("x", 1);
+ outgoing = (uv_stream_t*) &tcp_outgoing[i];
+ ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb));
+}
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char slab[1];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ uv_loop_t* loop;
+ unsigned int i;
+
+ /* Only first stream should receive read events */
+ ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
+ ASSERT(0 == uv_read_stop(stream));
+ ASSERT(1 == nread);
+
+ loop = stream->loop;
+ read_cb_called++;
+
+ /* Close all active incomings, except current one */
+ for (i = 1; i < got_connections; i++)
+ uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
+
+ /* Create new fd that should be one of the closed incomings */
+ ASSERT(0 == uv_tcp_init(loop, &tcp_check));
+ ASSERT(0 == uv_tcp_connect(&tcp_check_req,
+ &tcp_check,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb));
+
+ /* Close server, so no one will connect to it */
+ uv_close((uv_handle_t*) &tcp_server, close_cb);
+}
+
+static void connection_cb(uv_stream_t* server, int status) {
+ unsigned int i;
+ uv_tcp_t* incoming;
+
+ ASSERT(server == (uv_stream_t*) &tcp_server);
+
+ /* Ignore tcp_check connection */
+ if (got_connections == ARRAY_SIZE(tcp_incoming))
+ return;
+
+ /* Accept everyone */
+ incoming = &tcp_incoming[got_connections++];
+ ASSERT(0 == uv_tcp_init(server->loop, incoming));
+ ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming));
+
+ if (got_connections != ARRAY_SIZE(tcp_incoming))
+ return;
+
+ /* Once all clients are accepted - start reading */
+ for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) {
+ incoming = &tcp_incoming[i];
+ ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb));
+ }
+}
+
+TEST_IMPL(tcp_close_accept) {
+ unsigned int i;
+ uv_loop_t* loop;
+ uv_tcp_t* client;
+
+ /*
+ * A little explanation of what goes on below:
+ *
+ * We'll create server and connect to it using two clients, each writing one
+ * byte once connected.
+ *
+ * When all clients will be accepted by server - we'll start reading from them
+ * and, on first client's first byte, will close second client and server.
+ * After that, we'll immediately initiate new connection to server using
+ * tcp_check handle (thus, reusing fd from second client).
+ *
+ * In this situation uv__io_poll()'s event list should still contain read
+ * event for second client, and, if not cleaned up properly, `tcp_check` will
+ * receive stale event of second incoming and invoke `connect_cb` with zero
+ * status.
+ */
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(loop, &tcp_server));
+ ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server,
+ ARRAY_SIZE(tcp_outgoing),
+ connection_cb));
+
+ for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) {
+ client = tcp_outgoing + i;
+
+ ASSERT(0 == uv_tcp_init(loop, client));
+ ASSERT(0 == uv_tcp_connect(&connect_reqs[i],
+ client,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections);
+ ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called);
+ ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called);
+ ASSERT(1 == read_cb_called);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-tcp-close-while-connecting.c b/3rdparty/libuv/test/test-tcp-close-while-connecting.c
new file mode 100644
index 00000000000..2c39b652b61
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close-while-connecting.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer1_handle;
+static uv_timer_t timer2_handle;
+static uv_tcp_t tcp_handle;
+
+static int connect_cb_called;
+static int timer1_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ uv_timer_stop(&timer2_handle);
+ connect_cb_called++;
+}
+
+
+static void timer1_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*)handle, close_cb);
+ uv_close((uv_handle_t*)&tcp_handle, close_cb);
+ timer1_cb_called++;
+}
+
+
+static void timer2_cb(uv_timer_t* handle) {
+ ASSERT(0 && "should not be called");
+}
+
+
+TEST_IMPL(tcp_close_while_connecting) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("1.2.3.4", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_init(loop, &tcp_handle));
+ r = uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r == UV_ENETUNREACH)
+ RETURN_SKIP("Network unreachable.");
+ ASSERT(r == 0);
+ ASSERT(0 == uv_timer_init(loop, &timer1_handle));
+ ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0));
+ ASSERT(0 == uv_timer_init(loop, &timer2_handle));
+ ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(timer1_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-close.c b/3rdparty/libuv/test/test-tcp-close.c
new file mode 100644
index 00000000000..e65885aa556
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <string.h> /* memset */
+
+#define NUM_WRITE_REQS 32
+
+static uv_tcp_t tcp_handle;
+static uv_connect_t connect_req;
+
+static int write_cb_called;
+static int close_cb_called;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* conn_req, int status) {
+ uv_write_t* req;
+ uv_buf_t buf;
+ int i, r;
+
+ buf = uv_buf_init("PING", 4);
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ req = malloc(sizeof *req);
+ ASSERT(req != NULL);
+
+ r = uv_write(req, (uv_stream_t*)&tcp_handle, &buf, 1, write_cb);
+ ASSERT(r == 0);
+ }
+
+ uv_close((uv_handle_t*)&tcp_handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ /* write callbacks should run before the close callback */
+ ASSERT(close_cb_called == 0);
+ ASSERT(req->handle == (uv_stream_t*)&tcp_handle);
+ write_cb_called++;
+ free(req);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&tcp_handle);
+ close_cb_called++;
+}
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ ASSERT(status == 0);
+}
+
+
+static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)handle);
+}
+
+
+/* Check that pending write requests have their callbacks
+ * invoked when the handle is closed.
+ */
+TEST_IMPL(tcp_close) {
+ struct sockaddr_in addr;
+ uv_tcp_t tcp_server;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ /* We can't use the echo server, it doesn't handle ECONNRESET. */
+ start_server(loop, &tcp_server);
+
+ r = uv_tcp_init(loop, &tcp_handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ ASSERT(write_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ printf("%d of %d write reqs seen\n", write_cb_called, NUM_WRITE_REQS);
+
+ ASSERT(write_cb_called == NUM_WRITE_REQS);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-error-after-write.c b/3rdparty/libuv/test/test-tcp-connect-error-after-write.c
new file mode 100644
index 00000000000..3f2e3572da9
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-error-after-write.c
@@ -0,0 +1,98 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int connect_cb_called;
+static int write_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status < 0);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status < 0);
+ write_cb_called++;
+}
+
+
+/*
+ * Try to connect to an address on which nothing listens, get ECONNREFUSED
+ * (uv errno 12) and get connect_cb() called once with status != 0.
+ * Related issue: https://github.com/joyent/libuv/issues/443
+ */
+TEST_IMPL(tcp_connect_error_after_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_tcp_t conn;
+ uv_buf_t buf;
+ int r;
+
+#ifdef _WIN32
+ fprintf(stderr, "This test is disabled on Windows for now.\n");
+ fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n");
+ return 0; /* windows slackers... */
+#endif
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ buf = uv_buf_init("TEST", 4);
+
+ r = uv_tcp_init(uv_default_loop(), &conn);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-error.c b/3rdparty/libuv/test/test-tcp-connect-error.c
new file mode 100644
index 00000000000..eab1eeb2545
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-error.c
@@ -0,0 +1,73 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called = 0;
+static int close_cb_called = 0;
+
+
+
+static void connect_cb(uv_connect_t* handle, int status) {
+ ASSERT(handle != NULL);
+ connect_cb_called++;
+}
+
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_connect_error_fault) {
+ const char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ const struct sockaddr_in* garbage_addr;
+ uv_tcp_t server;
+ int r;
+ uv_connect_t req;
+
+ garbage_addr = (const struct sockaddr_in*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&req,
+ &server,
+ (const struct sockaddr*) garbage_addr,
+ connect_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-timeout.c b/3rdparty/libuv/test/test-tcp-connect-timeout.c
new file mode 100644
index 00000000000..081424b8002
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-timeout.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called;
+static int close_cb_called;
+
+static uv_connect_t connect_req;
+static uv_timer_t timer;
+static uv_tcp_t conn;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void timer_cb(uv_timer_t* handle);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == UV_ECANCELED);
+ connect_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ uv_close((uv_handle_t*)&conn, close_cb);
+ uv_close((uv_handle_t*)&timer, close_cb);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer);
+ close_cb_called++;
+}
+
+
+/* Verify that connecting to an unreachable address or port doesn't hang
+ * the event loop.
+ */
+TEST_IMPL(tcp_connect_timeout) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("8.8.8.8", 9999, &addr));
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 50, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &conn);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r == UV_ENETUNREACH)
+ RETURN_SKIP("Network unreachable.");
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect6-error.c b/3rdparty/libuv/test/test-tcp-connect6-error.c
new file mode 100644
index 00000000000..91ac0a3a101
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect6-error.c
@@ -0,0 +1,71 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void connect_cb(uv_connect_t* handle, int status) {
+ ASSERT(handle != NULL);
+ connect_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_connect6_error_fault) {
+ const char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ const struct sockaddr_in6* garbage_addr;
+ uv_tcp_t server;
+ int r;
+ uv_connect_t req;
+
+ garbage_addr = (const struct sockaddr_in6*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&req,
+ &server,
+ (const struct sockaddr*) garbage_addr,
+ connect_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-create-socket-early.c b/3rdparty/libuv/test/test-tcp-create-socket-early.c
new file mode 100644
index 00000000000..65650adcc27
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-create-socket-early.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+static void on_connect(uv_connect_t* req, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*) req->handle, NULL);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_tcp_t* handle;
+ int r;
+
+ ASSERT(status == 0);
+
+ handle = malloc(sizeof(*handle));
+ ASSERT(handle != NULL);
+
+ r = uv_tcp_init_ex(server->loop, handle, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == UV_EBUSY);
+
+ uv_close((uv_handle_t*) server, NULL);
+ uv_close((uv_handle_t*) handle, (uv_close_cb)free);
+}
+
+
+static void tcp_listener(uv_loop_t* loop, uv_tcp_t* server) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*) server, 128, on_connection);
+ ASSERT(r == 0);
+}
+
+
+static void tcp_connector(uv_loop_t* loop, uv_tcp_t* client, uv_connect_t* req) {
+ struct sockaddr_in server_addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+
+ r = uv_tcp_init(loop, client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(req,
+ client,
+ (const struct sockaddr*) &server_addr,
+ on_connect);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_create_early) {
+ struct sockaddr_in addr;
+ struct sockaddr_in sockname;
+ uv_tcp_t client;
+ uv_os_fd_t fd;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+ r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(memcmp(&addr.sin_addr,
+ &sockname.sin_addr,
+ sizeof(addr.sin_addr)) == 0);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_bind) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ uv_os_fd_t fd;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ {
+ int namelen;
+ struct sockaddr_in6 sockname;
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin6_family == AF_INET6);
+ }
+#endif
+
+ r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+ ASSERT(r == UV_EINVAL);
+#else
+ ASSERT(r == UV_EFAULT);
+#endif
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_domain) {
+ uv_tcp_t client;
+ int r;
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, 47);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, 1024);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_accept) {
+ uv_tcp_t client, server;
+ uv_connect_t connect_req;
+
+ tcp_listener(uv_default_loop(), &server);
+ tcp_connector(uv_default_loop(), &client, &connect_req);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-flags.c b/3rdparty/libuv/test/test-tcp-flags.c
new file mode 100644
index 00000000000..68afb39f456
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-flags.c
@@ -0,0 +1,52 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+TEST_IMPL(tcp_flags) {
+ uv_loop_t* loop;
+ uv_tcp_t handle;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_tcp_init(loop, &handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_nodelay(&handle, 1);
+ ASSERT(r == 0);
+
+ r = uv_tcp_keepalive(&handle, 1, 60);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&handle, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-oob.c b/3rdparty/libuv/test/test-tcp-oob.c
new file mode 100644
index 00000000000..fc011ee495f
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-oob.c
@@ -0,0 +1,128 @@
+/* Copyright Fedor Indutny. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+static uv_tcp_t peer_handle;
+static uv_idle_t idle;
+static uv_connect_t connect_req;
+static int ticks;
+static const int kMaxTicks = 10;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char storage[1024];
+ *buf = uv_buf_init(storage, sizeof(storage));
+}
+
+
+static void idle_cb(uv_idle_t* idle) {
+ if (++ticks < kMaxTicks)
+ return;
+
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+ uv_close((uv_handle_t*) &peer_handle, NULL);
+ uv_close((uv_handle_t*) idle, NULL);
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(0 == uv_idle_start(&idle, idle_cb));
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &client_handle);
+ ASSERT(0 == status);
+}
+
+
+static void connection_cb(uv_stream_t* handle, int status) {
+ int r;
+ uv_os_fd_t fd;
+
+ ASSERT(0 == status);
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
+
+ /* Send some OOB data */
+ ASSERT(0 == uv_fileno((uv_handle_t*) &client_handle, &fd));
+
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 1));
+
+ /* The problem triggers only on a second message, it seem that xnu is not
+ * triggering `kevent()` for the first one
+ */
+ do {
+ r = send(fd, "hello", 5, MSG_OOB);
+ } while (r < 0 && errno == EINTR);
+ ASSERT(5 == r);
+
+ do {
+ r = send(fd, "hello", 5, MSG_OOB);
+ } while (r < 0 && errno == EINTR);
+ ASSERT(5 == r);
+
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 0));
+}
+
+
+TEST_IMPL(tcp_oob) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_init(loop, &peer_handle));
+ ASSERT(0 == uv_idle_init(loop, &idle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
+
+ /* Ensure two separate packets */
+ ASSERT(0 == uv_tcp_nodelay(&client_handle, 1));
+
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(ticks == kMaxTicks);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
diff --git a/3rdparty/libuv/test/test-tcp-open.c b/3rdparty/libuv/test/test-tcp-open.c
new file mode 100644
index 00000000000..6c8d43d0009
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-open.c
@@ -0,0 +1,220 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+static uv_write_t write_req;
+
+
+static void startup(void) {
+#ifdef _WIN32
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+#endif
+}
+
+
+static uv_os_sock_t create_tcp_socket(void) {
+ uv_os_sock_t sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0);
+
+ /* Now we wait for the EOF */
+ shutdown_cb_called++;
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(tcp != NULL);
+
+ if (nread >= 0) {
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", buf->base, nread) == 0);
+ }
+ else {
+ ASSERT(nread == UV_EOF);
+ printf("GOT EOF\n");
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ r = uv_write(&write_req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ /* Shutdown on drain. */
+ r = uv_shutdown(&shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+
+ /* Start reading */
+ r = uv_read_start(stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_open) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ startup();
+ sock = create_tcp_socket();
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_open_twice) {
+ uv_tcp_t client;
+ uv_os_sock_t sock1, sock2;
+ int r;
+
+ startup();
+ sock1 = create_tcp_socket();
+ sock2 = create_tcp_socket();
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock1);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock2);
+ ASSERT(r == UV_EBUSY);
+ close_socket(sock2);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-read-stop.c b/3rdparty/libuv/test/test-tcp-read-stop.c
new file mode 100644
index 00000000000..488e8fb49a9
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-read-stop.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+static uv_tcp_t tcp_handle;
+static uv_write_t write_req;
+
+
+static void fail_cb(void) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ uv_close((uv_handle_t*) &tcp_handle, NULL);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_write(&write_req,
+ (uv_stream_t*) &tcp_handle,
+ &buf,
+ 1,
+ write_cb));
+ ASSERT(0 == uv_read_stop((uv_stream_t*) &tcp_handle));
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(0 == status);
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_handle,
+ (uv_alloc_cb) fail_cb,
+ (uv_read_cb) fail_cb));
+}
+
+
+TEST_IMPL(tcp_read_stop) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp_handle));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-shutdown-after-write.c b/3rdparty/libuv/test/test-tcp-shutdown-after-write.c
new file mode 100644
index 00000000000..463b4b0d79c
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-shutdown-after-write.c
@@ -0,0 +1,138 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static void write_cb(uv_write_t* req, int status);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+
+static uv_tcp_t conn;
+static uv_timer_t timer;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+
+static int conn_close_cb_called;
+static int timer_close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ if (handle == (uv_handle_t*)&conn)
+ conn_close_cb_called++;
+ else if (handle == (uv_handle_t*)&timer)
+ timer_close_cb_called++;
+ else
+ ASSERT(0 && "bad handle in close_cb");
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[64];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_buf_t buf;
+ int r;
+
+ uv_close((uv_handle_t*)handle, close_cb);
+
+ buf = uv_buf_init("TEST", 4);
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ shutdown_cb_called++;
+ uv_close((uv_handle_t*)&conn, close_cb);
+}
+
+
+TEST_IMPL(tcp_shutdown_after_write) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 125, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(loop, &conn);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(conn_close_cb_called == 1);
+ ASSERT(timer_close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-try-write.c b/3rdparty/libuv/test/test-tcp-try-write.c
new file mode 100644
index 00000000000..97a1d6e3d57
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-try-write.c
@@ -0,0 +1,135 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_BYTES 1024 * 1024
+
+static uv_tcp_t server;
+static uv_tcp_t client;
+static uv_tcp_t incoming;
+static int connect_cb_called;
+static int close_cb_called;
+static int connection_cb_called;
+static int bytes_read;
+static int bytes_written;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+ uv_buf_t buf;
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ do {
+ buf = uv_buf_init("PING", 4);
+ r = uv_try_write((uv_stream_t*) &client, &buf, 1);
+ ASSERT(r > 0 || r == UV_EAGAIN);
+ if (r > 0) {
+ bytes_written += r;
+ break;
+ }
+ } while (1);
+
+ do {
+ buf = uv_buf_init("", 0);
+ r = uv_try_write((uv_stream_t*) &client, &buf, 1);
+ } while (r != 0);
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1024];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread < 0) {
+ uv_close((uv_handle_t*) tcp, close_cb);
+ uv_close((uv_handle_t*) &server, close_cb);
+ return;
+ }
+
+ bytes_read += nread;
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
+ ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
+
+ connection_cb_called++;
+ ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb));
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
+ ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
+}
+
+
+TEST_IMPL(tcp_try_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ start_server();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client,
+ (struct sockaddr*) &addr,
+ connect_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(connection_cb_called == 1);
+ ASSERT(bytes_read == bytes_written);
+ ASSERT(bytes_written > 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-unexpected-read.c b/3rdparty/libuv/test/test-tcp-unexpected-read.c
new file mode 100644
index 00000000000..c7b981456be
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-unexpected-read.c
@@ -0,0 +1,117 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+static uv_tcp_t peer_handle;
+static uv_write_t write_req;
+static uv_connect_t connect_req;
+
+static unsigned long ticks; /* event loop ticks */
+
+
+static void check_cb(uv_check_t* handle) {
+ ticks++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+ uv_close((uv_handle_t*) &peer_handle, NULL);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ ASSERT(0 && "alloc_cb should not have been called");
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(0 && "read_cb should not have been called");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &client_handle);
+ ASSERT(0 == status);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &peer_handle);
+ ASSERT(0 == status);
+}
+
+
+static void connection_cb(uv_stream_t* handle, int status) {
+ uv_buf_t buf;
+
+ buf = uv_buf_init("PING", 4);
+
+ ASSERT(0 == status);
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle,
+ &buf, 1, write_cb));
+}
+
+
+TEST_IMPL(tcp_unexpected_read) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0));
+ ASSERT(0 == uv_check_init(loop, &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_init(loop, &peer_handle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ /* This is somewhat inexact but the idea is that the event loop should not
+ * start busy looping when the server sends a message and the client isn't
+ * reading.
+ */
+ ASSERT(ticks <= 20);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-after-connect.c b/3rdparty/libuv/test/test-tcp-write-after-connect.c
new file mode 100644
index 00000000000..aa03228f134
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-after-connect.c
@@ -0,0 +1,68 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+uv_loop_t loop;
+uv_tcp_t tcp_client;
+uv_connect_t connection_request;
+uv_write_t write_request;
+uv_buf_t buf = { "HELLO", 4 };
+
+
+static void write_cb(uv_write_t *req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ uv_close((uv_handle_t*) req->handle, NULL);
+}
+
+
+static void connect_cb(uv_connect_t *req, int status) {
+ ASSERT(status == UV_ECONNREFUSED);
+}
+
+
+TEST_IMPL(tcp_write_after_connect) {
+ struct sockaddr_in sa;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa));
+ ASSERT(0 == uv_loop_init(&loop));
+ ASSERT(0 == uv_tcp_init(&loop, &tcp_client));
+
+ ASSERT(0 == uv_tcp_connect(&connection_request,
+ &tcp_client,
+ (const struct sockaddr *)
+ &sa,
+ connect_cb));
+
+ ASSERT(0 == uv_write(&write_request,
+ (uv_stream_t *)&tcp_client,
+ &buf, 1,
+ write_cb));
+
+ uv_run(&loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif
diff --git a/3rdparty/libuv/test/test-tcp-write-fail.c b/3rdparty/libuv/test/test-tcp-write-fail.c
new file mode 100644
index 00000000000..5256a9f4a79
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-fail.c
@@ -0,0 +1,115 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+
+static void close_socket(uv_tcp_t* sock) {
+ uv_os_fd_t fd;
+ int r;
+
+ r = uv_fileno((uv_handle_t*)sock, &fd);
+ ASSERT(r == 0);
+#ifdef _WIN32
+ r = closesocket((uv_os_sock_t)fd);
+#else
+ r = close(fd);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ ASSERT(status != 0);
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ write_cb_called++;
+
+ uv_close((uv_handle_t*)(req->handle), close_cb);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf;
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ /* close the socket, the hard way */
+ close_socket((uv_tcp_t*)stream);
+
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write(&write_req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_write_fail) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-queue-order.c b/3rdparty/libuv/test/test-tcp-write-queue-order.c
new file mode 100644
index 00000000000..aa4d2acc24a
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-queue-order.c
@@ -0,0 +1,137 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "uv.h"
+#include "task.h"
+
+#define REQ_COUNT 10000
+
+static uv_timer_t timer;
+static uv_tcp_t server;
+static uv_tcp_t client;
+static uv_tcp_t incoming;
+static int connect_cb_called;
+static int close_cb_called;
+static int connection_cb_called;
+static int write_callbacks;
+static int write_cancelled_callbacks;
+static int write_error_callbacks;
+
+static uv_write_t write_requests[REQ_COUNT];
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) &client, close_cb);
+ uv_close((uv_handle_t*) &server, close_cb);
+ uv_close((uv_handle_t*) &incoming, close_cb);
+}
+
+void write_cb(uv_write_t* req, int status) {
+ if (status == 0)
+ write_callbacks++;
+ else if (status == UV_ECANCELED)
+ write_cancelled_callbacks++;
+ else
+ write_error_callbacks++;
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ static char base[1024];
+ int r;
+ int i;
+ uv_buf_t buf;
+
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ buf = uv_buf_init(base, sizeof(base));
+
+ for (i = 0; i < REQ_COUNT; i++) {
+ r = uv_write(&write_requests[i],
+ req->handle,
+ &buf,
+ 1,
+ write_cb);
+ ASSERT(r == 0);
+ }
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
+ ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
+
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
+ ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
+}
+
+
+TEST_IMPL(tcp_write_queue_order) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ start_server();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client,
+ (struct sockaddr*) &addr,
+ connect_cb));
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(connection_cb_called == 1);
+ ASSERT(write_callbacks > 0);
+ ASSERT(write_cancelled_callbacks > 0);
+ ASSERT(write_callbacks +
+ write_error_callbacks +
+ write_cancelled_callbacks == REQ_COUNT);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c b/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c
new file mode 100644
index 00000000000..2fa2ae72253
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void connection_cb(uv_stream_t* server, int status);
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_client;
+static uv_tcp_t tcp_peer; /* client socket as accept()-ed by server */
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+static int write_cb_called;
+static int read_cb_called;
+
+static void connection_cb(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(server == (uv_stream_t*)&tcp_server);
+ ASSERT(status == 0);
+
+ r = uv_tcp_init(server->loop, &tcp_peer);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)&tcp_peer);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ buf.base = "hello\n";
+ buf.len = 6;
+
+ r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[1024];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ if (nread < 0) {
+ fprintf(stderr, "read_cb error: %s\n", uv_err_name(nread));
+ ASSERT(nread == UV_ECONNRESET || nread == UV_EOF);
+
+ uv_close((uv_handle_t*)&tcp_server, NULL);
+ uv_close((uv_handle_t*)&tcp_peer, NULL);
+ }
+
+ read_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ /* Close the client. */
+ uv_close((uv_handle_t*)&tcp_client, NULL);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+TEST_IMPL(tcp_write_to_half_open_connection) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_tcp_init(loop, &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(loop, &tcp_client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(write_cb_called > 0);
+ ASSERT(read_cb_called > 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-writealot.c b/3rdparty/libuv/test/test-tcp-writealot.c
new file mode 100644
index 00000000000..6cfe2ebb18d
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-writealot.c
@@ -0,0 +1,176 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define WRITES 3
+#define CHUNKS_PER_WRITE 4096
+#define CHUNK_SIZE 10024 /* 10 kb */
+
+#define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE)
+
+static char* send_buffer;
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+static size_t bytes_sent = 0;
+static size_t bytes_sent_done = 0;
+static size_t bytes_received_done = 0;
+
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+static uv_write_t write_reqs[WRITES];
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ uv_tcp_t* tcp;
+
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0);
+
+ tcp = (uv_tcp_t*)(req->handle);
+
+ /* The write buffer should be empty by now. */
+ ASSERT(tcp->write_queue_size == 0);
+
+ /* Now we wait for the EOF */
+ shutdown_cb_called++;
+
+ /* We should have had all the writes called already. */
+ ASSERT(write_cb_called == WRITES);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(tcp != NULL);
+
+ if (nread >= 0) {
+ bytes_received_done += nread;
+ }
+ else {
+ ASSERT(nread == UV_EOF);
+ printf("GOT EOF\n");
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+
+ free(buf->base);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ bytes_sent_done += CHUNKS_PER_WRITE * CHUNK_SIZE;
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t send_bufs[CHUNKS_PER_WRITE];
+ uv_stream_t* stream;
+ int i, j, r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ /* Write a lot of data */
+ for (i = 0; i < WRITES; i++) {
+ uv_write_t* write_req = write_reqs + i;
+
+ for (j = 0; j < CHUNKS_PER_WRITE; j++) {
+ send_bufs[j] = uv_buf_init(send_buffer + bytes_sent, CHUNK_SIZE);
+ bytes_sent += CHUNK_SIZE;
+ }
+
+ r = uv_write(write_req, stream, send_bufs, CHUNKS_PER_WRITE, write_cb);
+ ASSERT(r == 0);
+ }
+
+ /* Shutdown on drain. */
+ r = uv_shutdown(&shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+
+ /* Start reading */
+ r = uv_read_start(stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_writealot) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ send_buffer = calloc(1, TOTAL_BYTES);
+ ASSERT(send_buffer != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == WRITES);
+ ASSERT(close_cb_called == 1);
+ ASSERT(bytes_sent == TOTAL_BYTES);
+ ASSERT(bytes_sent_done == TOTAL_BYTES);
+ ASSERT(bytes_received_done == TOTAL_BYTES);
+
+ free(send_buffer);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-thread-equal.c b/3rdparty/libuv/test/test-thread-equal.c
new file mode 100644
index 00000000000..27c07ee2c7d
--- /dev/null
+++ b/3rdparty/libuv/test/test-thread-equal.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+uv_thread_t main_thread_id;
+uv_thread_t subthreads[2];
+
+static void check_thread(void* arg) {
+ uv_thread_t *thread_id = arg;
+ uv_thread_t self_id = uv_thread_self();
+ ASSERT(uv_thread_equal(&main_thread_id, &self_id) == 0);
+ *thread_id = uv_thread_self();
+}
+
+TEST_IMPL(thread_equal) {
+ uv_thread_t threads[2];
+ main_thread_id = uv_thread_self();
+ ASSERT(0 != uv_thread_equal(&main_thread_id, &main_thread_id));
+ ASSERT(0 == uv_thread_create(threads + 0, check_thread, subthreads + 0));
+ ASSERT(0 == uv_thread_create(threads + 1, check_thread, subthreads + 1));
+ ASSERT(0 == uv_thread_join(threads + 0));
+ ASSERT(0 == uv_thread_join(threads + 1));
+ ASSERT(0 == uv_thread_equal(subthreads + 0, subthreads + 1));
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-thread.c b/3rdparty/libuv/test/test-thread.c
new file mode 100644
index 00000000000..7f3321aa06d
--- /dev/null
+++ b/3rdparty/libuv/test/test-thread.c
@@ -0,0 +1,211 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* memset */
+
+struct getaddrinfo_req {
+ uv_thread_t thread_id;
+ unsigned int counter;
+ uv_loop_t* loop;
+ uv_getaddrinfo_t handle;
+};
+
+
+struct fs_req {
+ uv_thread_t thread_id;
+ unsigned int counter;
+ uv_loop_t* loop;
+ uv_fs_t handle;
+};
+
+
+struct test_thread {
+ uv_thread_t thread_id;
+ volatile int thread_called;
+};
+
+static void getaddrinfo_do(struct getaddrinfo_req* req);
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res);
+static void fs_do(struct fs_req* req);
+static void fs_cb(uv_fs_t* handle);
+
+static volatile int thread_called;
+static uv_key_t tls_key;
+
+
+static void getaddrinfo_do(struct getaddrinfo_req* req) {
+ int r;
+
+ r = uv_getaddrinfo(req->loop,
+ &req->handle,
+ getaddrinfo_cb,
+ "localhost",
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+}
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ struct getaddrinfo_req* req;
+
+ ASSERT(status == 0);
+
+ req = container_of(handle, struct getaddrinfo_req, handle);
+ uv_freeaddrinfo(res);
+
+ if (--req->counter)
+ getaddrinfo_do(req);
+}
+
+
+static void fs_do(struct fs_req* req) {
+ int r;
+
+ r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb);
+ ASSERT(r == 0);
+}
+
+
+static void fs_cb(uv_fs_t* handle) {
+ struct fs_req* req = container_of(handle, struct fs_req, handle);
+
+ uv_fs_req_cleanup(handle);
+
+ if (--req->counter)
+ fs_do(req);
+}
+
+
+static void do_work(void* arg) {
+ struct getaddrinfo_req getaddrinfo_reqs[16];
+ struct fs_req fs_reqs[16];
+ uv_loop_t* loop;
+ size_t i;
+ int r;
+ struct test_thread* thread = arg;
+
+ loop = malloc(sizeof *loop);
+ ASSERT(loop != NULL);
+ ASSERT(0 == uv_loop_init(loop));
+
+ for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) {
+ struct getaddrinfo_req* req = getaddrinfo_reqs + i;
+ req->counter = 16;
+ req->loop = loop;
+ getaddrinfo_do(req);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) {
+ struct fs_req* req = fs_reqs + i;
+ req->counter = 16;
+ req->loop = loop;
+ fs_do(req);
+ }
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_loop_close(loop));
+ free(loop);
+ thread->thread_called = 1;
+}
+
+
+static void thread_entry(void* arg) {
+ ASSERT(arg == (void *) 42);
+ thread_called++;
+}
+
+
+TEST_IMPL(thread_create) {
+ uv_thread_t tid;
+ int r;
+
+ r = uv_thread_create(&tid, thread_entry, (void *) 42);
+ ASSERT(r == 0);
+
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+
+ ASSERT(thread_called == 1);
+
+ return 0;
+}
+
+
+/* Hilariously bad test name. Run a lot of tasks in the thread pool and verify
+ * that each "finished" callback is run in its originating thread.
+ */
+TEST_IMPL(threadpool_multiple_event_loops) {
+ struct test_thread threads[8];
+ size_t i;
+ int r;
+
+ memset(threads, 0, sizeof(threads));
+
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
+ r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]);
+ ASSERT(r == 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
+ r = uv_thread_join(&threads[i].thread_id);
+ ASSERT(r == 0);
+ ASSERT(threads[i].thread_called);
+ }
+
+ return 0;
+}
+
+
+static void tls_thread(void* arg) {
+ ASSERT(NULL == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, arg);
+ ASSERT(arg == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, NULL);
+ ASSERT(NULL == uv_key_get(&tls_key));
+}
+
+
+TEST_IMPL(thread_local_storage) {
+ char name[] = "main";
+ uv_thread_t threads[2];
+ ASSERT(0 == uv_key_create(&tls_key));
+ ASSERT(NULL == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, name);
+ ASSERT(name == uv_key_get(&tls_key));
+ ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0));
+ ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1));
+ ASSERT(0 == uv_thread_join(threads + 0));
+ ASSERT(0 == uv_thread_join(threads + 1));
+ uv_key_delete(&tls_key);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-threadpool-cancel.c b/3rdparty/libuv/test/test-threadpool-cancel.c
new file mode 100644
index 00000000000..784c1739f6d
--- /dev/null
+++ b/3rdparty/libuv/test/test-threadpool-cancel.c
@@ -0,0 +1,362 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#define INIT_CANCEL_INFO(ci, what) \
+ do { \
+ (ci)->reqs = (what); \
+ (ci)->nreqs = ARRAY_SIZE(what); \
+ (ci)->stride = sizeof((what)[0]); \
+ } \
+ while (0)
+
+struct cancel_info {
+ void* reqs;
+ unsigned nreqs;
+ unsigned stride;
+ uv_timer_t timer_handle;
+};
+
+static uv_cond_t signal_cond;
+static uv_mutex_t signal_mutex;
+static uv_mutex_t wait_mutex;
+static unsigned num_threads;
+static unsigned fs_cb_called;
+static unsigned work_cb_called;
+static unsigned done_cb_called;
+static unsigned done2_cb_called;
+static unsigned timer_cb_called;
+
+
+static void work_cb(uv_work_t* req) {
+ uv_mutex_lock(&signal_mutex);
+ uv_cond_signal(&signal_cond);
+ uv_mutex_unlock(&signal_mutex);
+
+ uv_mutex_lock(&wait_mutex);
+ uv_mutex_unlock(&wait_mutex);
+
+ work_cb_called++;
+}
+
+
+static void done_cb(uv_work_t* req, int status) {
+ done_cb_called++;
+ free(req);
+}
+
+
+static void saturate_threadpool(void) {
+ uv_work_t* req;
+
+ ASSERT(0 == uv_cond_init(&signal_cond));
+ ASSERT(0 == uv_mutex_init(&signal_mutex));
+ ASSERT(0 == uv_mutex_init(&wait_mutex));
+
+ uv_mutex_lock(&signal_mutex);
+ uv_mutex_lock(&wait_mutex);
+
+ for (num_threads = 0; /* empty */; num_threads++) {
+ req = malloc(sizeof(*req));
+ ASSERT(req != NULL);
+ ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb));
+
+ /* Expect to get signalled within 350 ms, otherwise assume that
+ * the thread pool is saturated. As with any timing dependent test,
+ * this is obviously not ideal.
+ */
+ if (uv_cond_timedwait(&signal_cond,
+ &signal_mutex,
+ (uint64_t) (350 * 1e6))) {
+ ASSERT(0 == uv_cancel((uv_req_t*) req));
+ break;
+ }
+ }
+}
+
+
+static void unblock_threadpool(void) {
+ uv_mutex_unlock(&signal_mutex);
+ uv_mutex_unlock(&wait_mutex);
+}
+
+
+static void cleanup_threadpool(void) {
+ ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */
+ ASSERT(work_cb_called == num_threads);
+
+ uv_cond_destroy(&signal_cond);
+ uv_mutex_destroy(&signal_mutex);
+ uv_mutex_destroy(&wait_mutex);
+}
+
+
+static void fs_cb(uv_fs_t* req) {
+ ASSERT(req->result == UV_ECANCELED);
+ uv_fs_req_cleanup(req);
+ fs_cb_called++;
+}
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(res == NULL);
+ uv_freeaddrinfo(res); /* Should not crash. */
+}
+
+
+static void getnameinfo_cb(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(hostname == NULL);
+ ASSERT(service == NULL);
+}
+
+
+static void work2_cb(uv_work_t* req) {
+ ASSERT(0 && "work2_cb called");
+}
+
+
+static void done2_cb(uv_work_t* req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ done2_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ struct cancel_info* ci;
+ uv_req_t* req;
+ unsigned i;
+
+ ci = container_of(handle, struct cancel_info, timer_handle);
+
+ for (i = 0; i < ci->nreqs; i++) {
+ req = (uv_req_t*) ((char*) ci->reqs + i * ci->stride);
+ ASSERT(0 == uv_cancel(req));
+ }
+
+ uv_close((uv_handle_t*) &ci->timer_handle, NULL);
+ unblock_threadpool();
+ timer_cb_called++;
+}
+
+
+static void nop_work_cb(uv_work_t* req) {
+}
+
+
+static void nop_done_cb(uv_work_t* req, int status) {
+ req->data = "OK";
+}
+
+
+TEST_IMPL(threadpool_cancel_getaddrinfo) {
+ uv_getaddrinfo_t reqs[4];
+ struct cancel_info ci;
+ struct addrinfo hints;
+ uv_loop_t* loop;
+ int r;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getaddrinfo(loop, reqs + 0, getaddrinfo_cb, "fail", NULL, NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 1, getaddrinfo_cb, NULL, "fail", NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 2, getaddrinfo_cb, "fail", "fail", NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 3, getaddrinfo_cb, "fail", NULL, &hints);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_getnameinfo) {
+ uv_getnameinfo_t reqs[4];
+ struct sockaddr_in addr4;
+ struct cancel_info ci;
+ uv_loop_t* loop;
+ int r;
+
+ r = uv_ip4_addr("127.0.0.1", 80, &addr4);
+ ASSERT(r == 0);
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getnameinfo(loop, reqs + 0, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 1, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 2, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 3, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_work) {
+ struct cancel_info ci;
+ uv_work_t reqs[16];
+ uv_loop_t* loop;
+ unsigned i;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ for (i = 0; i < ARRAY_SIZE(reqs); i++)
+ ASSERT(0 == uv_queue_work(loop, reqs + i, work2_cb, done2_cb));
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+ ASSERT(ARRAY_SIZE(reqs) == done2_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_fs) {
+ struct cancel_info ci;
+ uv_fs_t reqs[26];
+ uv_loop_t* loop;
+ unsigned n;
+ uv_buf_t iov;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+ iov = uv_buf_init(NULL, 0);
+
+ /* Needs to match ARRAY_SIZE(fs_reqs). */
+ n = 0;
+ ASSERT(0 == uv_fs_chmod(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_chown(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_close(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fchmod(loop, reqs + n++, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_fchown(loop, reqs + n++, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_fdatasync(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fstat(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fsync(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_ftruncate(loop, reqs + n++, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_futime(loop, reqs + n++, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_link(loop, reqs + n++, "/", "/", fs_cb));
+ ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
+ ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb));
+ ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_stat(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
+ ASSERT(n == ARRAY_SIZE(reqs));
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(n == fs_cb_called);
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_single) {
+ uv_loop_t* loop;
+ uv_work_t req;
+ int cancelled;
+ int i;
+
+ loop = uv_default_loop();
+ for (i = 0; i < 5000; i++) {
+ req.data = NULL;
+ ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb));
+
+ cancelled = uv_cancel((uv_req_t*) &req);
+ if (cancelled == 0)
+ break;
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ }
+
+ if (cancelled != 0) {
+ fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n",
+ stderr);
+ return 1;
+ }
+
+ ASSERT(req.data == NULL);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-threadpool.c b/3rdparty/libuv/test/test-threadpool.c
new file mode 100644
index 00000000000..e3d17d7546f
--- /dev/null
+++ b/3rdparty/libuv/test/test-threadpool.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int work_cb_count;
+static int after_work_cb_count;
+static uv_work_t work_req;
+static char data;
+
+
+static void work_cb(uv_work_t* req) {
+ ASSERT(req == &work_req);
+ ASSERT(req->data == &data);
+ work_cb_count++;
+}
+
+
+static void after_work_cb(uv_work_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req == &work_req);
+ ASSERT(req->data == &data);
+ after_work_cb_count++;
+}
+
+
+TEST_IMPL(threadpool_queue_work_simple) {
+ int r;
+
+ work_req.data = &data;
+ r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb);
+ ASSERT(r == 0);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(work_cb_count == 1);
+ ASSERT(after_work_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_queue_work_einval) {
+ int r;
+
+ work_req.data = &data;
+ r = uv_queue_work(uv_default_loop(), &work_req, NULL, after_work_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(work_cb_count == 0);
+ ASSERT(after_work_cb_count == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer-again.c b/3rdparty/libuv/test/test-timer-again.c
new file mode 100644
index 00000000000..f93c509be5d
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer-again.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int close_cb_called = 0;
+static int repeat_1_cb_called = 0;
+static int repeat_2_cb_called = 0;
+
+static int repeat_2_cb_allowed = 0;
+
+static uv_timer_t dummy, repeat_1, repeat_2;
+
+static uint64_t start_time;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+
+ close_cb_called++;
+}
+
+
+static void repeat_1_cb(uv_timer_t* handle) {
+ int r;
+
+ ASSERT(handle == &repeat_1);
+ ASSERT(uv_timer_get_repeat((uv_timer_t*)handle) == 50);
+
+ fprintf(stderr, "repeat_1_cb called after %ld ms\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ repeat_1_cb_called++;
+
+ r = uv_timer_again(&repeat_2);
+ ASSERT(r == 0);
+
+ if (repeat_1_cb_called == 10) {
+ uv_close((uv_handle_t*)handle, close_cb);
+ /* We're not calling uv_timer_again on repeat_2 any more, so after this */
+ /* timer_2_cb is expected. */
+ repeat_2_cb_allowed = 1;
+ return;
+ }
+}
+
+
+static void repeat_2_cb(uv_timer_t* handle) {
+ ASSERT(handle == &repeat_2);
+ ASSERT(repeat_2_cb_allowed);
+
+ fprintf(stderr, "repeat_2_cb called after %ld ms\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ repeat_2_cb_called++;
+
+ if (uv_timer_get_repeat(&repeat_2) == 0) {
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+ return;
+ }
+
+ fprintf(stderr, "uv_timer_get_repeat %ld ms\n",
+ (long int)uv_timer_get_repeat(&repeat_2));
+ fflush(stderr);
+ ASSERT(uv_timer_get_repeat(&repeat_2) == 100);
+
+ /* This shouldn't take effect immediately. */
+ uv_timer_set_repeat(&repeat_2, 0);
+}
+
+
+TEST_IMPL(timer_again) {
+ int r;
+
+ start_time = uv_now(uv_default_loop());
+ ASSERT(0 < start_time);
+
+ /* Verify that it is not possible to uv_timer_again a never-started timer. */
+ r = uv_timer_init(uv_default_loop(), &dummy);
+ ASSERT(r == 0);
+ r = uv_timer_again(&dummy);
+ ASSERT(r == UV_EINVAL);
+ uv_unref((uv_handle_t*)&dummy);
+
+ /* Start timer repeat_1. */
+ r = uv_timer_init(uv_default_loop(), &repeat_1);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat_1, repeat_1_cb, 50, 0);
+ ASSERT(r == 0);
+ ASSERT(uv_timer_get_repeat(&repeat_1) == 0);
+
+ /* Actually make repeat_1 repeating. */
+ uv_timer_set_repeat(&repeat_1, 50);
+ ASSERT(uv_timer_get_repeat(&repeat_1) == 50);
+
+ /*
+ * Start another repeating timer. It'll be again()ed by the repeat_1 so
+ * it should not time out until repeat_1 stops.
+ */
+ r = uv_timer_init(uv_default_loop(), &repeat_2);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat_2, repeat_2_cb, 100, 100);
+ ASSERT(r == 0);
+ ASSERT(uv_timer_get_repeat(&repeat_2) == 100);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(repeat_1_cb_called == 10);
+ ASSERT(repeat_2_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ fprintf(stderr, "Test took %ld ms (expected ~700 ms)\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer-from-check.c b/3rdparty/libuv/test/test-timer-from-check.c
new file mode 100644
index 00000000000..a18c7e1fb99
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer-from-check.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_prepare_t prepare_handle;
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+
+static int prepare_cb_called;
+static int check_cb_called;
+static int timer_cb_called;
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(0 == uv_prepare_stop(&prepare_handle));
+ ASSERT(0 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ prepare_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(0 == uv_timer_stop(&timer_handle));
+ ASSERT(1 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ timer_cb_called++;
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(0 == uv_check_stop(&check_handle));
+ ASSERT(0 == uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_prepare_start(&prepare_handle, prepare_cb));
+ ASSERT(0 == prepare_cb_called);
+ ASSERT(0 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ check_cb_called++;
+}
+
+
+TEST_IMPL(timer_from_check) {
+ ASSERT(0 == uv_prepare_init(uv_default_loop(), &prepare_handle));
+ ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(1 == timer_cb_called);
+ uv_close((uv_handle_t*) &prepare_handle, NULL);
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer.c b/3rdparty/libuv/test/test-timer.c
new file mode 100644
index 00000000000..aba050fd64c
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer.c
@@ -0,0 +1,303 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int once_cb_called = 0;
+static int once_close_cb_called = 0;
+static int repeat_cb_called = 0;
+static int repeat_close_cb_called = 0;
+static int order_cb_called = 0;
+static uint64_t start_time;
+static uv_timer_t tiny_timer;
+static uv_timer_t huge_timer1;
+static uv_timer_t huge_timer2;
+
+
+static void once_close_cb(uv_handle_t* handle) {
+ printf("ONCE_CLOSE_CB\n");
+
+ ASSERT(handle != NULL);
+ ASSERT(0 == uv_is_active(handle));
+
+ once_close_cb_called++;
+}
+
+
+static void once_cb(uv_timer_t* handle) {
+ printf("ONCE_CB %d\n", once_cb_called);
+
+ ASSERT(handle != NULL);
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+
+ once_cb_called++;
+
+ uv_close((uv_handle_t*)handle, once_close_cb);
+
+ /* Just call this randomly for the code coverage. */
+ uv_update_time(uv_default_loop());
+}
+
+
+static void repeat_close_cb(uv_handle_t* handle) {
+ printf("REPEAT_CLOSE_CB\n");
+
+ ASSERT(handle != NULL);
+
+ repeat_close_cb_called++;
+}
+
+
+static void repeat_cb(uv_timer_t* handle) {
+ printf("REPEAT_CB\n");
+
+ ASSERT(handle != NULL);
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+
+ repeat_cb_called++;
+
+ if (repeat_cb_called == 5) {
+ uv_close((uv_handle_t*)handle, repeat_close_cb);
+ }
+}
+
+
+static void never_cb(uv_timer_t* handle) {
+ FATAL("never_cb should never be called");
+}
+
+
+TEST_IMPL(timer) {
+ uv_timer_t once_timers[10];
+ uv_timer_t *once;
+ uv_timer_t repeat, never;
+ unsigned int i;
+ int r;
+
+ start_time = uv_now(uv_default_loop());
+ ASSERT(0 < start_time);
+
+ /* Let 10 timers time out in 500 ms total. */
+ for (i = 0; i < ARRAY_SIZE(once_timers); i++) {
+ once = once_timers + i;
+ r = uv_timer_init(uv_default_loop(), once);
+ ASSERT(r == 0);
+ r = uv_timer_start(once, once_cb, i * 50, 0);
+ ASSERT(r == 0);
+ }
+
+ /* The 11th timer is a repeating timer that runs 4 times */
+ r = uv_timer_init(uv_default_loop(), &repeat);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat, repeat_cb, 100, 100);
+ ASSERT(r == 0);
+
+ /* The 12th timer should not do anything. */
+ r = uv_timer_init(uv_default_loop(), &never);
+ ASSERT(r == 0);
+ r = uv_timer_start(&never, never_cb, 100, 100);
+ ASSERT(r == 0);
+ r = uv_timer_stop(&never);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*)&never);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(once_cb_called == 10);
+ ASSERT(once_close_cb_called == 10);
+ printf("repeat_cb_called %d\n", repeat_cb_called);
+ ASSERT(repeat_cb_called == 5);
+ ASSERT(repeat_close_cb_called == 1);
+
+ ASSERT(500 <= uv_now(uv_default_loop()) - start_time);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_start_twice) {
+ uv_timer_t once;
+ int r;
+
+ r = uv_timer_init(uv_default_loop(), &once);
+ ASSERT(r == 0);
+ r = uv_timer_start(&once, never_cb, 86400 * 1000, 0);
+ ASSERT(r == 0);
+ r = uv_timer_start(&once, once_cb, 10, 0);
+ ASSERT(r == 0);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(once_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_init) {
+ uv_timer_t handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle));
+ ASSERT(0 == uv_timer_get_repeat(&handle));
+ ASSERT(0 == uv_is_active((uv_handle_t*) &handle));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void order_cb_a(uv_timer_t *handle) {
+ ASSERT(order_cb_called++ == *(int*)handle->data);
+}
+
+
+static void order_cb_b(uv_timer_t *handle) {
+ ASSERT(order_cb_called++ == *(int*)handle->data);
+}
+
+
+TEST_IMPL(timer_order) {
+ int first;
+ int second;
+ uv_timer_t handle_a;
+ uv_timer_t handle_b;
+
+ first = 0;
+ second = 1;
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_a));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_b));
+
+ /* Test for starting handle_a then handle_b */
+ handle_a.data = &first;
+ ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
+ handle_b.data = &second;
+ ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(order_cb_called == 2);
+
+ ASSERT(0 == uv_timer_stop(&handle_a));
+ ASSERT(0 == uv_timer_stop(&handle_b));
+
+ /* Test for starting handle_b then handle_a */
+ order_cb_called = 0;
+ handle_b.data = &first;
+ ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
+
+ handle_a.data = &second;
+ ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(order_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void tiny_timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &tiny_timer);
+ uv_close((uv_handle_t*) &tiny_timer, NULL);
+ uv_close((uv_handle_t*) &huge_timer1, NULL);
+ uv_close((uv_handle_t*) &huge_timer2, NULL);
+}
+
+
+TEST_IMPL(timer_huge_timeout) {
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer2));
+ ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0));
+ ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0));
+ ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void huge_repeat_cb(uv_timer_t* handle) {
+ static int ncalls;
+
+ if (ncalls == 0)
+ ASSERT(handle == &huge_timer1);
+ else
+ ASSERT(handle == &tiny_timer);
+
+ if (++ncalls == 10) {
+ uv_close((uv_handle_t*) &tiny_timer, NULL);
+ uv_close((uv_handle_t*) &huge_timer1, NULL);
+ }
+}
+
+
+TEST_IMPL(timer_huge_repeat) {
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1));
+ ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2));
+ ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static unsigned int timer_run_once_timer_cb_called;
+
+
+static void timer_run_once_timer_cb(uv_timer_t* handle) {
+ timer_run_once_timer_cb_called++;
+}
+
+
+TEST_IMPL(timer_run_once) {
+ uv_timer_t timer_handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(1 == timer_run_once_timer_cb_called);
+
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(2 == timer_run_once_timer_cb_called);
+
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_null_callback) {
+ uv_timer_t handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle));
+ ASSERT(UV_EINVAL == uv_timer_start(&handle, NULL, 100, 100));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tty.c b/3rdparty/libuv/test/test-tty.c
new file mode 100644
index 00000000000..b844959d526
--- /dev/null
+++ b/3rdparty/libuv/test/test-tty.c
@@ -0,0 +1,184 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+#else /* Unix */
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+
+TEST_IMPL(tty) {
+ int r, width, height;
+ int ttyin_fd, ttyout_fd;
+ uv_tty_t tty_in, tty_out;
+ uv_loop_t* loop = uv_default_loop();
+
+ /* Make sure we have an FD that refers to a tty */
+#ifdef _WIN32
+ HANDLE handle;
+ handle = CreateFileA("conin$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
+
+ handle = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
+
+#else /* unix */
+ ttyin_fd = open("/dev/tty", O_RDONLY, 0);
+ if (ttyin_fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ ttyout_fd = open("/dev/tty", O_WRONLY, 0);
+ if (ttyout_fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as write-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+#endif
+
+ ASSERT(ttyin_fd >= 0);
+ ASSERT(ttyout_fd >= 0);
+
+ ASSERT(UV_UNKNOWN_HANDLE == uv_guess_handle(-1));
+
+ ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
+ ASSERT(UV_TTY == uv_guess_handle(ttyout_fd));
+
+ r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
+ ASSERT(r == 0);
+
+ r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
+ ASSERT(r == 0);
+
+ r = uv_tty_get_winsize(&tty_out, &width, &height);
+ ASSERT(r == 0);
+
+ printf("width=%d height=%d\n", width, height);
+
+ if (width == 0 && height == 0) {
+ /* Some environments such as containers or Jenkins behave like this
+ * sometimes */
+ MAKE_VALGRIND_HAPPY();
+ return TEST_SKIP;
+ }
+
+ /*
+ * Is it a safe assumption that most people have terminals larger than
+ * 10x10?
+ */
+ ASSERT(width > 10);
+ ASSERT(height > 10);
+
+ /* Turn on raw mode. */
+ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
+ ASSERT(r == 0);
+
+ /* Turn off raw mode. */
+ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_NORMAL);
+ ASSERT(r == 0);
+
+ /* Calling uv_tty_reset_mode() repeatedly should not clobber errno. */
+ errno = 0;
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == errno);
+
+ /* TODO check the actual mode! */
+
+ uv_close((uv_handle_t*) &tty_in, NULL);
+ uv_close((uv_handle_t*) &tty_out, NULL);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tty_file) {
+#ifndef _WIN32
+ uv_loop_t loop;
+ uv_tty_t tty;
+ int fd;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ fd = open("test/fixtures/empty_file", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+
+/* Bug on AIX where '/dev/random' returns 1 from isatty() */
+#ifndef _AIX
+ fd = open("/dev/random", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+#endif /* _AIX */
+
+ fd = open("/dev/zero", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ uv_close((uv_handle_t*) &tty, NULL);
+ }
+
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+ ASSERT(0 == uv_loop_close(&loop));
+
+ MAKE_VALGRIND_HAPPY();
+#endif
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-bind.c b/3rdparty/libuv/test/test-udp-bind.c
new file mode 100644
index 00000000000..a1e080ee70c
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-bind.c
@@ -0,0 +1,93 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+TEST_IMPL(udp_bind) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uv_udp_t h1, h2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h1);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(loop, &h2);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*) &h1, NULL);
+ uv_close((uv_handle_t*) &h2, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_bind_reuseaddr) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uv_udp_t h1, h2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h1);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(loop, &h2);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &h1, NULL);
+ uv_close((uv_handle_t*) &h2, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-create-socket-early.c b/3rdparty/libuv/test/test-udp-create-socket-early.c
new file mode 100644
index 00000000000..3d0152428b8
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-create-socket-early.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+TEST_IMPL(udp_create_early) {
+ struct sockaddr_in addr;
+ struct sockaddr_in sockname;
+ uv_udp_t client;
+ uv_os_fd_t fd;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(memcmp(&addr.sin_addr,
+ &sockname.sin_addr,
+ sizeof(addr.sin_addr)) == 0);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_bind) {
+ struct sockaddr_in addr;
+ uv_udp_t client;
+ uv_os_fd_t fd;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ {
+ int namelen;
+ struct sockaddr_in6 sockname;
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin6_family == AF_INET6);
+ }
+#endif
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+ ASSERT(r == UV_EINVAL);
+#else
+ ASSERT(r == UV_EFAULT);
+#endif
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_domain) {
+ uv_udp_t client;
+ int r;
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, 47);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, 1024);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-dgram-too-big.c b/3rdparty/libuv/test/test-udp-dgram-too-big.c
new file mode 100644
index 00000000000..bd44c425287
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-dgram-too-big.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &handle_)
+
+#define CHECK_REQ(req) \
+ ASSERT((req) == &req_);
+
+static uv_udp_t handle_;
+static uv_udp_send_t req_;
+
+static int send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ CHECK_REQ(req);
+ CHECK_HANDLE(req->handle);
+
+ ASSERT(status == UV_EMSGSIZE);
+
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ send_cb_called++;
+}
+
+
+TEST_IMPL(udp_dgram_too_big) {
+ char dgram[65536]; /* 64K MTU is unlikely, even on localhost */
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ int r;
+
+ memset(dgram, 42, sizeof dgram); /* silence valgrind */
+
+ r = uv_udp_init(uv_default_loop(), &handle_);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(dgram, sizeof dgram);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_send(&req_,
+ &handle_,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(send_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-ipv6.c b/3rdparty/libuv/test/test-udp-ipv6.c
new file mode 100644
index 00000000000..1b0db78b8ef
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-ipv6.c
@@ -0,0 +1,193 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server \
+ || (uv_udp_t*)(handle) == &client \
+ || (uv_timer_t*)(handle) == &timeout)
+
+#define CHECK_REQ(req) \
+ ASSERT((req) == &req_);
+
+static uv_udp_t client;
+static uv_udp_t server;
+static uv_udp_send_t req_;
+static uv_timer_t timeout;
+
+static int send_cb_called;
+static int recv_cb_called;
+static int close_cb_called;
+
+#ifdef __FreeBSD__
+static int can_ipv6_ipv4_dual() {
+ int v6only;
+ size_t size = sizeof(int);
+
+ if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0))
+ return 0;
+
+ return v6only != 1;
+}
+#endif
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ CHECK_REQ(req);
+ CHECK_HANDLE(req->handle);
+ ASSERT(status == 0);
+ send_cb_called++;
+}
+
+
+static void ipv6_recv_fail(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ASSERT(0 && "this function should not have been called");
+}
+
+
+static void ipv6_recv_ok(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(nread >= 0);
+
+ if (nread)
+ recv_cb_called++;
+}
+
+
+static void timeout_cb(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)&server, close_cb);
+ uv_close((uv_handle_t*)&client, close_cb);
+ uv_close((uv_handle_t*)&timeout, close_cb);
+}
+
+
+static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) {
+ struct sockaddr_in6 addr6;
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip6_addr("::0", TEST_PORT, &addr6));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_send(&req_,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timeout);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timeout, timeout_cb, 500, 0);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(send_cb_called == 0);
+ ASSERT(recv_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+TEST_IMPL(udp_dual_stack) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+#ifdef __FreeBSD__
+ if (!can_ipv6_ipv4_dual())
+ RETURN_SKIP("IPv6-IPv4 dual stack not supported");
+#endif
+
+ do_test(ipv6_recv_ok, 0);
+
+ ASSERT(recv_cb_called == 1);
+ ASSERT(send_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(udp_ipv6_only) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY);
+
+ ASSERT(recv_cb_called == 0);
+ ASSERT(send_cb_called == 1);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-interface.c b/3rdparty/libuv/test/test-udp-multicast-interface.c
new file mode 100644
index 00000000000..71001a77e03
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-interface.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0 || status == UV_ENETUNREACH);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_interface) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+ struct sockaddr_in baddr;
+
+ ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr));
+ r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_multicast_interface(&server, "0.0.0.0");
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*)&addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-interface6.c b/3rdparty/libuv/test/test-udp-multicast-interface6.c
new file mode 100644
index 00000000000..d3881e83bb1
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-interface6.c
@@ -0,0 +1,103 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_interface6) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in6 addr;
+ struct sockaddr_in6 baddr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip6_addr("::", 0, &baddr));
+ r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
+ ASSERT(r == 0);
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ r = uv_udp_set_multicast_interface(&server, "::1%lo0");
+#else
+ r = uv_udp_set_multicast_interface(&server, NULL);
+#endif
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*)&addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-join.c b/3rdparty/libuv/test/test-udp-multicast-join.c
new file mode 100644
index 00000000000..6110a8d922a
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-join.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+
+static int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ cl_recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", buf->base, nread));
+
+ /* we are done with the client handle, we can close it */
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_join) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* bind to the desired port */
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ /* join the multicast channel */
+ r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP);
+ if (r == UV_ENODEV)
+ RETURN_SKIP("No multicast support.");
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+
+ /* server sends "PING" */
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-join6.c b/3rdparty/libuv/test/test-udp-multicast-join6.c
new file mode 100644
index 00000000000..f635bdb9e14
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-join6.c
@@ -0,0 +1,161 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+
+static int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ cl_recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", buf->base, nread));
+
+ /* we are done with the client handle, we can close it */
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_join6) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in6 addr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* bind to the desired port */
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ /* join the multicast channel */
+#if defined(__APPLE__) || defined(_AIX)
+ r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP);
+#else
+ r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP);
+#endif
+ if (r == UV_ENODEV) {
+ MAKE_VALGRIND_HAPPY();
+ RETURN_SKIP("No ipv6 multicast route");
+ }
+
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+
+ /* server sends "PING" */
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-ttl.c b/3rdparty/libuv/test/test-udp-multicast-ttl.c
new file mode 100644
index 00000000000..7f1af9b9dd9
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-ttl.c
@@ -0,0 +1,94 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0 || status == UV_ENETUNREACH);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_ttl) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_multicast_ttl(&server, 32);
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-open.c b/3rdparty/libuv/test/test-udp-open.c
new file mode 100644
index 00000000000..4d77f45d367
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-open.c
@@ -0,0 +1,204 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+static int send_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_udp_send_t send_req;
+
+
+static void startup(void) {
+#ifdef _WIN32
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+#endif
+}
+
+
+static uv_os_sock_t create_udp_socket(void) {
+ uv_os_sock_t sock;
+
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ int r;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", buf->base, nread) == 0);
+
+ r = uv_udp_recv_stop(handle);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ send_cb_called++;
+}
+
+
+TEST_IMPL(udp_open) {
+ struct sockaddr_in addr;
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_udp_t client;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ startup();
+ sock = create_udp_socket();
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ r = uv_udp_send(&send_req,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_open_twice) {
+ uv_udp_t client;
+ uv_os_sock_t sock1, sock2;
+ int r;
+
+ startup();
+ sock1 = create_udp_socket();
+ sock2 = create_udp_socket();
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock1);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock2);
+ ASSERT(r == UV_EBUSY);
+ close_socket(sock2);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-options.c b/3rdparty/libuv/test/test-udp-options.c
new file mode 100644
index 00000000000..0da1786f506
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-options.c
@@ -0,0 +1,126 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static int udp_options_test(const struct sockaddr* addr) {
+ static int invalid_ttls[] = { -1, 0, 256 };
+ uv_loop_t* loop;
+ uv_udp_t h;
+ int i, r;
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */
+
+ r = uv_udp_bind(&h, addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_broadcast(&h, 1);
+ r |= uv_udp_set_broadcast(&h, 1);
+ r |= uv_udp_set_broadcast(&h, 0);
+ r |= uv_udp_set_broadcast(&h, 0);
+ ASSERT(r == 0);
+
+ /* values 1-255 should work */
+ for (i = 1; i <= 255; i++) {
+ r = uv_udp_set_ttl(&h, i);
+ ASSERT(r == 0);
+ }
+
+ for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) {
+ r = uv_udp_set_ttl(&h, invalid_ttls[i]);
+ ASSERT(r == UV_EINVAL);
+ }
+
+ r = uv_udp_set_multicast_loop(&h, 1);
+ r |= uv_udp_set_multicast_loop(&h, 1);
+ r |= uv_udp_set_multicast_loop(&h, 0);
+ r |= uv_udp_set_multicast_loop(&h, 0);
+ ASSERT(r == 0);
+
+ /* values 0-255 should work */
+ for (i = 0; i <= 255; i++) {
+ r = uv_udp_set_multicast_ttl(&h, i);
+ ASSERT(r == 0);
+ }
+
+ /* anything >255 should fail */
+ r = uv_udp_set_multicast_ttl(&h, 256);
+ ASSERT(r == UV_EINVAL);
+ /* don't test ttl=-1, it's a valid value on some platforms */
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_options) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ return udp_options_test((const struct sockaddr*) &addr);
+}
+
+
+TEST_IMPL(udp_options6) {
+ struct sockaddr_in6 addr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
+ return udp_options_test((const struct sockaddr*) &addr);
+}
+
+
+TEST_IMPL(udp_no_autobind) {
+ uv_loop_t* loop;
+ uv_udp_t h;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_udp_init(loop, &h));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32));
+ ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0"));
+
+ uv_close((uv_handle_t*) &h, NULL);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-and-recv.c b/3rdparty/libuv/test/test-udp-send-and-recv.c
new file mode 100644
index 00000000000..633a16727b2
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-and-recv.c
@@ -0,0 +1,214 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_send_cb_called;
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+static int sv_recv_cb_called;
+
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PONG", buf->base, nread));
+
+ cl_recv_cb_called++;
+
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+
+static void cl_send_cb(uv_udp_send_t* req, int status) {
+ int r;
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ r = uv_udp_recv_start(req->handle, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ cl_send_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+ free(req);
+
+ sv_send_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ uv_udp_send_t* req;
+ uv_buf_t sndbuf;
+ int r;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", rcvbuf->base, nread));
+
+ /* FIXME? `uv_udp_recv_stop` does what it says: recv_cb is not called
+ * anymore. That's problematic because the read buffer won't be returned
+ * either... Not sure I like that but it's consistent with `uv_read_stop`.
+ */
+ r = uv_udp_recv_stop(handle);
+ ASSERT(r == 0);
+
+ req = malloc(sizeof *req);
+ ASSERT(req != NULL);
+
+ sndbuf = uv_buf_init("PONG", 4);
+ r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb);
+ ASSERT(r == 0);
+
+ sv_recv_cb_called++;
+}
+
+
+TEST_IMPL(udp_send_and_recv) {
+ struct sockaddr_in addr;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* client sends "PING", expects "PONG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_send_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+ ASSERT(sv_recv_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_send_cb_called == 1);
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(sv_recv_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-immediate.c b/3rdparty/libuv/test/test-udp-send-immediate.c
new file mode 100644
index 00000000000..0999f6b3425
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-immediate.c
@@ -0,0 +1,148 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_send_cb_called;
+static int sv_recv_cb_called;
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void cl_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ cl_send_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", rcvbuf->base, nread) == 0 ||
+ memcmp("PANG", rcvbuf->base, nread) == 0);
+
+ if (++sv_recv_cb_called == 2) {
+ uv_close((uv_handle_t*) &server, close_cb);
+ uv_close((uv_handle_t*) &client, close_cb);
+ }
+}
+
+
+TEST_IMPL(udp_send_immediate) {
+ struct sockaddr_in addr;
+ uv_udp_send_t req1, req2;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* client sends "PING", then "PANG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req1,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PANG", 4);
+
+ r = uv_udp_send(&req2,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_send_cb_called == 2);
+ ASSERT(sv_recv_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-unreachable.c b/3rdparty/libuv/test/test-udp-send-unreachable.c
new file mode 100644
index 00000000000..c6500320d78
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-unreachable.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &client)
+
+static uv_udp_t client;
+static uv_timer_t timer;
+
+static int send_cb_called;
+static int recv_cb_called;
+static int close_cb_called;
+static int alloc_cb_called;
+static int timer_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+ alloc_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+ send_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ } else if (nread == 0) {
+ /* Returning unused buffer */
+ ASSERT(addr == NULL);
+ } else {
+ ASSERT(addr != NULL);
+ }
+}
+
+
+static void timer_cb(uv_timer_t* h) {
+ ASSERT(h == &timer);
+ timer_cb_called++;
+ uv_close((uv_handle_t*) &client, close_cb);
+ uv_close((uv_handle_t*) h, close_cb);
+}
+
+
+TEST_IMPL(udp_send_unreachable) {
+ struct sockaddr_in addr;
+ struct sockaddr_in addr2;
+ uv_udp_send_t req1, req2;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2));
+
+ r = uv_timer_init( uv_default_loop(), &timer );
+ ASSERT(r == 0);
+
+ r = uv_timer_start( &timer, timer_cb, 1000, 0 );
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ /* client sends "PING", then "PANG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req1,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PANG", 4);
+
+ r = uv_udp_send(&req2,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 2);
+ ASSERT(recv_cb_called == alloc_cb_called);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-try-send.c b/3rdparty/libuv/test/test-udp-try-send.c
new file mode 100644
index 00000000000..7b6de365487
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-try-send.c
@@ -0,0 +1,133 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+
+TEST_IMPL(udp_try_send) {
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_recv_cb_called;
+
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ASSERT(nread > 0);
+
+ if (nread == 0) {
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(nread == 4);
+ ASSERT(addr != NULL);
+
+ ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0);
+ uv_close((uv_handle_t*) handle, close_cb);
+ uv_close((uv_handle_t*) &client, close_cb);
+
+ sv_recv_cb_called++;
+}
+
+
+TEST_IMPL(udp_try_send) {
+ struct sockaddr_in addr;
+ static char buffer[64 * 1024];
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(buffer, sizeof(buffer));
+ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
+ ASSERT(r == UV_EMSGSIZE);
+
+ buf = uv_buf_init("EXIT", 4);
+ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
+ ASSERT(r == 4);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+ ASSERT(sv_recv_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-walk-handles.c b/3rdparty/libuv/test/test-walk-handles.c
new file mode 100644
index 00000000000..4b0ca6ebc55
--- /dev/null
+++ b/3rdparty/libuv/test/test-walk-handles.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static char magic_cookie[] = "magic cookie";
+static int seen_timer_handle;
+static uv_timer_t timer;
+
+
+static void walk_cb(uv_handle_t* handle, void* arg) {
+ ASSERT(arg == (void*)magic_cookie);
+
+ if (handle == (uv_handle_t*)&timer) {
+ seen_timer_handle++;
+ } else {
+ ASSERT(0 && "unexpected handle");
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+
+ uv_walk(handle->loop, walk_cb, magic_cookie);
+ uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+TEST_IMPL(walk_handles) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 1, 0);
+ ASSERT(r == 0);
+
+ /* Start event loop, expect to see the timer handle in walk_cb. */
+ ASSERT(seen_timer_handle == 0);
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(seen_timer_handle == 1);
+
+ /* Loop is finished, walk_cb should not see our timer handle. */
+ seen_timer_handle = 0;
+ uv_walk(loop, walk_cb, magic_cookie);
+ ASSERT(seen_timer_handle == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-watcher-cross-stop.c b/3rdparty/libuv/test/test-watcher-cross-stop.c
new file mode 100644
index 00000000000..910ed0fb613
--- /dev/null
+++ b/3rdparty/libuv/test/test-watcher-cross-stop.c
@@ -0,0 +1,103 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+/* NOTE: Number should be big enough to trigger this problem */
+static uv_udp_t sockets[2500];
+static uv_udp_send_t reqs[ARRAY_SIZE(sockets)];
+static char slab[1];
+static unsigned int recv_cb_called;
+static unsigned int send_cb_called;
+static unsigned int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ recv_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ send_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+TEST_IMPL(watcher_cross_stop) {
+ uv_loop_t* loop = uv_default_loop();
+ unsigned int i;
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ char big_string[1024];
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(sockets) + 32);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ memset(big_string, 'A', sizeof(big_string));
+ buf = uv_buf_init(big_string, sizeof(big_string));
+
+ for (i = 0; i < ARRAY_SIZE(sockets); i++) {
+ ASSERT(0 == uv_udp_init(loop, &sockets[i]));
+ ASSERT(0 == uv_udp_bind(&sockets[i],
+ (const struct sockaddr*) &addr,
+ UV_UDP_REUSEADDR));
+ ASSERT(0 == uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb));
+ ASSERT(0 == uv_udp_send(&reqs[i],
+ &sockets[i],
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb));
+ }
+
+ while (recv_cb_called == 0)
+ uv_run(loop, UV_RUN_ONCE);
+
+ for (i = 0; i < ARRAY_SIZE(sockets); i++)
+ uv_close((uv_handle_t*) &sockets[i], close_cb);
+
+ ASSERT(recv_cb_called > 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(ARRAY_SIZE(sockets) == send_cb_called);
+ ASSERT(ARRAY_SIZE(sockets) == close_cb_called);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/uv.gyp b/3rdparty/libuv/uv.gyp
new file mode 100644
index 00000000000..635a234ea6e
--- /dev/null
+++ b/3rdparty/libuv/uv.gyp
@@ -0,0 +1,508 @@
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [
+ '_LARGEFILE_SOURCE',
+ '_FILE_OFFSET_BITS=64',
+ ],
+ 'conditions': [
+ ['OS=="solaris"', {
+ 'cflags': [ '-pthreads' ],
+ }],
+ ['OS not in "solaris android"', {
+ 'cflags': [ '-pthread' ],
+ }],
+ ],
+ }],
+ ],
+ 'xcode_settings': {
+ 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ],
+ 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ],
+ }
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'libuv',
+ 'type': '<(uv_library)',
+ 'include_dirs': [
+ 'include',
+ 'src/',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [ 'include' ],
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [
+ '_LARGEFILE_SOURCE',
+ '_FILE_OFFSET_BITS=64',
+ ],
+ }],
+ ['OS in "mac ios"', {
+ 'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ],
+ }],
+ ['OS == "linux"', {
+ 'defines': [ '_POSIX_C_SOURCE=200112' ],
+ }],
+ ],
+ },
+ 'sources': [
+ 'common.gypi',
+ 'include/uv.h',
+ 'include/tree.h',
+ 'include/uv-errno.h',
+ 'include/uv-threadpool.h',
+ 'include/uv-version.h',
+ 'src/fs-poll.c',
+ 'src/heap-inl.h',
+ 'src/inet.c',
+ 'src/queue.h',
+ 'src/threadpool.c',
+ 'src/uv-common.c',
+ 'src/uv-common.h',
+ 'src/version.c'
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'defines': [
+ '_WIN32_WINNT=0x0600',
+ '_GNU_SOURCE',
+ ],
+ 'sources': [
+ 'include/uv-win.h',
+ 'src/win/async.c',
+ 'src/win/atomicops-inl.h',
+ 'src/win/core.c',
+ 'src/win/dl.c',
+ 'src/win/error.c',
+ 'src/win/fs.c',
+ 'src/win/fs-event.c',
+ 'src/win/getaddrinfo.c',
+ 'src/win/getnameinfo.c',
+ 'src/win/handle.c',
+ 'src/win/handle-inl.h',
+ 'src/win/internal.h',
+ 'src/win/loop-watcher.c',
+ 'src/win/pipe.c',
+ 'src/win/thread.c',
+ 'src/win/poll.c',
+ 'src/win/process.c',
+ 'src/win/process-stdio.c',
+ 'src/win/req.c',
+ 'src/win/req-inl.h',
+ 'src/win/signal.c',
+ 'src/win/stream.c',
+ 'src/win/stream-inl.h',
+ 'src/win/tcp.c',
+ 'src/win/tty.c',
+ 'src/win/timer.c',
+ 'src/win/udp.c',
+ 'src/win/util.c',
+ 'src/win/winapi.c',
+ 'src/win/winapi.h',
+ 'src/win/winsock.c',
+ 'src/win/winsock.h',
+ ],
+ 'conditions': [
+ ['MSVS_VERSION < "2015"', {
+ 'sources': [
+ 'src/win/snprintf.c'
+ ]
+ }]
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-ladvapi32',
+ '-liphlpapi',
+ '-lpsapi',
+ '-lshell32',
+ '-luserenv',
+ '-lws2_32'
+ ],
+ },
+ }, { # Not Windows i.e. POSIX
+ 'cflags': [
+ '-g',
+ '--std=gnu89',
+ '-pedantic',
+ '-Wall',
+ '-Wextra',
+ '-Wno-unused-parameter',
+ ],
+ 'sources': [
+ 'include/uv-unix.h',
+ 'include/uv-linux.h',
+ 'include/uv-sunos.h',
+ 'include/uv-darwin.h',
+ 'include/uv-bsd.h',
+ 'include/uv-aix.h',
+ 'src/unix/async.c',
+ 'src/unix/atomic-ops.h',
+ 'src/unix/core.c',
+ 'src/unix/dl.c',
+ 'src/unix/fs.c',
+ 'src/unix/getaddrinfo.c',
+ 'src/unix/getnameinfo.c',
+ 'src/unix/internal.h',
+ 'src/unix/loop.c',
+ 'src/unix/loop-watcher.c',
+ 'src/unix/pipe.c',
+ 'src/unix/poll.c',
+ 'src/unix/process.c',
+ 'src/unix/signal.c',
+ 'src/unix/spinlock.h',
+ 'src/unix/stream.c',
+ 'src/unix/tcp.c',
+ 'src/unix/thread.c',
+ 'src/unix/timer.c',
+ 'src/unix/tty.c',
+ 'src/unix/udp.c',
+ ],
+ 'link_settings': {
+ 'libraries': [ '-lm' ],
+ 'conditions': [
+ ['OS=="solaris"', {
+ 'ldflags': [ '-pthreads' ],
+ }],
+ ['OS != "solaris" and OS != "android"', {
+ 'ldflags': [ '-pthread' ],
+ }],
+ ],
+ },
+ 'conditions': [
+ ['uv_library=="shared_library"', {
+ 'cflags': [ '-fPIC' ],
+ }],
+ ['uv_library=="shared_library" and OS!="mac"', {
+ # This will cause gyp to set soname
+ # Must correspond with UV_VERSION_MAJOR
+ # in include/uv-version.h
+ 'product_extension': 'so.1',
+ }],
+ ],
+ }],
+ [ 'OS in "linux mac ios android"', {
+ 'sources': [ 'src/unix/proctitle.c' ],
+ }],
+ [ 'OS in "mac ios"', {
+ 'sources': [
+ 'src/unix/darwin.c',
+ 'src/unix/fsevents.c',
+ 'src/unix/darwin-proctitle.c',
+ ],
+ 'defines': [
+ '_DARWIN_USE_64_BIT_INODE=1',
+ '_DARWIN_UNLIMITED_SELECT=1',
+ ]
+ }],
+ [ 'OS!="mac"', {
+ # Enable on all platforms except OS X. The antique gcc/clang that
+ # ships with Xcode emits waaaay too many false positives.
+ 'cflags': [ '-Wstrict-aliasing' ],
+ }],
+ [ 'OS=="linux"', {
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'src/unix/linux-core.c',
+ 'src/unix/linux-inotify.c',
+ 'src/unix/linux-syscalls.c',
+ 'src/unix/linux-syscalls.h',
+ ],
+ 'link_settings': {
+ 'libraries': [ '-ldl', '-lrt' ],
+ },
+ }],
+ [ 'OS=="android"', {
+ 'sources': [
+ 'src/unix/linux-core.c',
+ 'src/unix/linux-inotify.c',
+ 'src/unix/linux-syscalls.c',
+ 'src/unix/linux-syscalls.h',
+ 'src/unix/pthread-fixes.c',
+ 'src/unix/android-ifaddrs.c'
+ ],
+ 'link_settings': {
+ 'libraries': [ '-ldl' ],
+ },
+ }],
+ [ 'OS=="solaris"', {
+ 'sources': [ 'src/unix/sunos.c' ],
+ 'defines': [
+ '__EXTENSIONS__',
+ '_XOPEN_SOURCE=500',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lkstat',
+ '-lnsl',
+ '-lsendfile',
+ '-lsocket',
+ ],
+ },
+ }],
+ [ 'OS=="aix"', {
+ 'sources': [ 'src/unix/aix.c' ],
+ 'defines': [
+ '_ALL_SOURCE',
+ '_XOPEN_SOURCE=500',
+ '_LINUX_SOURCE_COMPAT',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lperfstat',
+ ],
+ },
+ }],
+ [ 'OS=="freebsd" or OS=="dragonflybsd"', {
+ 'sources': [ 'src/unix/freebsd.c' ],
+ }],
+ [ 'OS=="openbsd"', {
+ 'sources': [ 'src/unix/openbsd.c' ],
+ }],
+ [ 'OS=="netbsd"', {
+ 'sources': [ 'src/unix/netbsd.c' ],
+ }],
+ [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', {
+ 'link_settings': {
+ 'libraries': [ '-lkvm' ],
+ },
+ }],
+ [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', {
+ 'sources': [ 'src/unix/kqueue.c' ],
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'BUILDING_UV_SHARED=1' ]
+ }],
+ ]
+ },
+
+ {
+ 'target_name': 'run-tests',
+ 'type': 'executable',
+ 'dependencies': [ 'libuv' ],
+ 'sources': [
+ 'test/blackhole-server.c',
+ 'test/echo-server.c',
+ 'test/run-tests.c',
+ 'test/runner.c',
+ 'test/runner.h',
+ 'test/test-get-loadavg.c',
+ 'test/task.h',
+ 'test/test-active.c',
+ 'test/test-async.c',
+ 'test/test-async-null-cb.c',
+ 'test/test-callback-stack.c',
+ 'test/test-callback-order.c',
+ 'test/test-close-fd.c',
+ 'test/test-close-order.c',
+ 'test/test-connection-fail.c',
+ 'test/test-cwd-and-chdir.c',
+ 'test/test-default-loop-close.c',
+ 'test/test-delayed-accept.c',
+ 'test/test-error.c',
+ 'test/test-embed.c',
+ 'test/test-emfile.c',
+ 'test/test-fail-always.c',
+ 'test/test-fs.c',
+ 'test/test-fs-event.c',
+ 'test/test-get-currentexe.c',
+ 'test/test-get-memory.c',
+ 'test/test-getaddrinfo.c',
+ 'test/test-getnameinfo.c',
+ 'test/test-getsockname.c',
+ 'test/test-handle-fileno.c',
+ 'test/test-homedir.c',
+ 'test/test-hrtime.c',
+ 'test/test-idle.c',
+ 'test/test-ip6-addr.c',
+ 'test/test-ipc.c',
+ 'test/test-ipc-send-recv.c',
+ 'test/test-list.h',
+ 'test/test-loop-handles.c',
+ 'test/test-loop-alive.c',
+ 'test/test-loop-close.c',
+ 'test/test-loop-stop.c',
+ 'test/test-loop-time.c',
+ 'test/test-loop-configure.c',
+ 'test/test-walk-handles.c',
+ 'test/test-watcher-cross-stop.c',
+ 'test/test-multiple-listen.c',
+ 'test/test-osx-select.c',
+ 'test/test-pass-always.c',
+ 'test/test-ping-pong.c',
+ 'test/test-pipe-bind-error.c',
+ 'test/test-pipe-connect-error.c',
+ 'test/test-pipe-connect-multiple.c',
+ 'test/test-pipe-connect-prepare.c',
+ 'test/test-pipe-getsockname.c',
+ 'test/test-pipe-pending-instances.c',
+ 'test/test-pipe-sendmsg.c',
+ 'test/test-pipe-server-close.c',
+ 'test/test-pipe-close-stdout-read-stdin.c',
+ 'test/test-pipe-set-non-blocking.c',
+ 'test/test-platform-output.c',
+ 'test/test-poll.c',
+ 'test/test-poll-close.c',
+ 'test/test-poll-close-doesnt-corrupt-stack.c',
+ 'test/test-poll-closesocket.c',
+ 'test/test-process-title.c',
+ 'test/test-queue-foreach-delete.c',
+ 'test/test-ref.c',
+ 'test/test-run-nowait.c',
+ 'test/test-run-once.c',
+ 'test/test-semaphore.c',
+ 'test/test-shutdown-close.c',
+ 'test/test-shutdown-eof.c',
+ 'test/test-shutdown-twice.c',
+ 'test/test-signal.c',
+ 'test/test-signal-multiple-loops.c',
+ 'test/test-socket-buffer-size.c',
+ 'test/test-spawn.c',
+ 'test/test-fs-poll.c',
+ 'test/test-stdio-over-pipes.c',
+ 'test/test-tcp-bind-error.c',
+ 'test/test-tcp-bind6-error.c',
+ 'test/test-tcp-close.c',
+ 'test/test-tcp-close-accept.c',
+ 'test/test-tcp-close-while-connecting.c',
+ 'test/test-tcp-create-socket-early.c',
+ 'test/test-tcp-connect-error-after-write.c',
+ 'test/test-tcp-shutdown-after-write.c',
+ 'test/test-tcp-flags.c',
+ 'test/test-tcp-connect-error.c',
+ 'test/test-tcp-connect-timeout.c',
+ 'test/test-tcp-connect6-error.c',
+ 'test/test-tcp-open.c',
+ 'test/test-tcp-write-to-half-open-connection.c',
+ 'test/test-tcp-write-after-connect.c',
+ 'test/test-tcp-writealot.c',
+ 'test/test-tcp-write-fail.c',
+ 'test/test-tcp-try-write.c',
+ 'test/test-tcp-unexpected-read.c',
+ 'test/test-tcp-oob.c',
+ 'test/test-tcp-read-stop.c',
+ 'test/test-tcp-write-queue-order.c',
+ 'test/test-threadpool.c',
+ 'test/test-threadpool-cancel.c',
+ 'test/test-thread-equal.c',
+ 'test/test-mutexes.c',
+ 'test/test-thread.c',
+ 'test/test-barrier.c',
+ 'test/test-condvar.c',
+ 'test/test-timer-again.c',
+ 'test/test-timer-from-check.c',
+ 'test/test-timer.c',
+ 'test/test-tty.c',
+ 'test/test-udp-bind.c',
+ 'test/test-udp-create-socket-early.c',
+ 'test/test-udp-dgram-too-big.c',
+ 'test/test-udp-ipv6.c',
+ 'test/test-udp-open.c',
+ 'test/test-udp-options.c',
+ 'test/test-udp-send-and-recv.c',
+ 'test/test-udp-send-immediate.c',
+ 'test/test-udp-send-unreachable.c',
+ 'test/test-udp-multicast-join.c',
+ 'test/test-udp-multicast-join6.c',
+ 'test/test-dlerror.c',
+ 'test/test-udp-multicast-ttl.c',
+ 'test/test-ip4-addr.c',
+ 'test/test-ip6-addr.c',
+ 'test/test-udp-multicast-interface.c',
+ 'test/test-udp-multicast-interface6.c',
+ 'test/test-udp-try-send.c',
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'sources': [
+ 'test/runner-win.c',
+ 'test/runner-win.h'
+ ],
+ 'libraries': [ '-lws2_32' ]
+ }, { # POSIX
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'test/runner-unix.c',
+ 'test/runner-unix.h',
+ ],
+ }],
+ [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
+ 'defines': [
+ '__EXTENSIONS__',
+ '_XOPEN_SOURCE=500',
+ ],
+ }],
+ [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
+ 'defines': [
+ '_ALL_SOURCE',
+ '_XOPEN_SOURCE=500',
+ ],
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'USING_UV_SHARED=1' ]
+ }],
+ ],
+ 'msvs-settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': 1, # /subsystem:console
+ },
+ },
+ },
+
+ {
+ 'target_name': 'run-benchmarks',
+ 'type': 'executable',
+ 'dependencies': [ 'libuv' ],
+ 'sources': [
+ 'test/benchmark-async.c',
+ 'test/benchmark-async-pummel.c',
+ 'test/benchmark-fs-stat.c',
+ 'test/benchmark-getaddrinfo.c',
+ 'test/benchmark-list.h',
+ 'test/benchmark-loop-count.c',
+ 'test/benchmark-million-async.c',
+ 'test/benchmark-million-timers.c',
+ 'test/benchmark-multi-accept.c',
+ 'test/benchmark-ping-pongs.c',
+ 'test/benchmark-pound.c',
+ 'test/benchmark-pump.c',
+ 'test/benchmark-sizes.c',
+ 'test/benchmark-spawn.c',
+ 'test/benchmark-thread.c',
+ 'test/benchmark-tcp-write-batch.c',
+ 'test/benchmark-udp-pummel.c',
+ 'test/dns-server.c',
+ 'test/echo-server.c',
+ 'test/blackhole-server.c',
+ 'test/run-benchmarks.c',
+ 'test/runner.c',
+ 'test/runner.h',
+ 'test/task.h',
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'sources': [
+ 'test/runner-win.c',
+ 'test/runner-win.h',
+ ],
+ 'libraries': [ '-lws2_32' ]
+ }, { # POSIX
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'test/runner-unix.c',
+ 'test/runner-unix.h',
+ ]
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'USING_UV_SHARED=1' ]
+ }],
+ ],
+ 'msvs-settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': 1, # /subsystem:console
+ },
+ },
+ },
+ ]
+}
diff --git a/3rdparty/libuv/vcbuild.bat b/3rdparty/libuv/vcbuild.bat
new file mode 100644
index 00000000000..696f0db30e1
--- /dev/null
+++ b/3rdparty/libuv/vcbuild.bat
@@ -0,0 +1,153 @@
+@echo off
+
+cd %~dp0
+
+if /i "%1"=="help" goto help
+if /i "%1"=="--help" goto help
+if /i "%1"=="-help" goto help
+if /i "%1"=="/help" goto help
+if /i "%1"=="?" goto help
+if /i "%1"=="-?" goto help
+if /i "%1"=="--?" goto help
+if /i "%1"=="/?" goto help
+
+@rem Process arguments.
+set config=
+set target=Build
+set noprojgen=
+set nobuild=
+set run=
+set target_arch=ia32
+set vs_toolset=x86
+set platform=WIN32
+set library=static_library
+
+:next-arg
+if "%1"=="" goto args-done
+if /i "%1"=="debug" set config=Debug&goto arg-ok
+if /i "%1"=="release" set config=Release&goto arg-ok
+if /i "%1"=="test" set run=run-tests.exe&goto arg-ok
+if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok
+if /i "%1"=="clean" set target=Clean&goto arg-ok
+if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok
+if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
+if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
+if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
+if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok
+if /i "%1"=="shared" set library=shared_library&goto arg-ok
+if /i "%1"=="static" set library=static_library&goto arg-ok
+:arg-ok
+shift
+goto next-arg
+:args-done
+
+if defined WindowsSDKDir goto select-target
+if defined VCINSTALLDIR goto select-target
+
+@rem Look for Visual Studio 2015
+if not defined VS140COMNTOOLS goto vc-set-2013
+if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013
+call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2015
+goto select-target
+
+:vc-set-2013
+@rem Look for Visual Studio 2013
+if not defined VS120COMNTOOLS goto vc-set-2012
+if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012
+call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2013
+goto select-target
+
+:vc-set-2012
+@rem Look for Visual Studio 2012
+if not defined VS110COMNTOOLS goto vc-set-2010
+if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010
+call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2012
+goto select-target
+
+:vc-set-2010
+@rem Look for Visual Studio 2010
+if not defined VS100COMNTOOLS goto vc-set-2008
+if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008
+call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2010
+goto select-target
+
+:vc-set-2008
+@rem Look for Visual Studio 2008
+if not defined VS90COMNTOOLS goto vc-set-notfound
+if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound
+call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2008
+goto select-target
+
+:vc-set-notfound
+echo Warning: Visual Studio not found
+
+:select-target
+if not "%config%"=="" goto project-gen
+if "%run%"=="run-tests.exe" set config=Debug& goto project-gen
+if "%run%"=="run-benchmarks.exe" set config=Release& goto project-gen
+set config=Debug
+
+:project-gen
+@rem Skip project generation if requested.
+if defined noprojgen goto msbuild
+
+@rem Generate the VS project.
+if exist build\gyp goto have_gyp
+echo git clone https://chromium.googlesource.com/external/gyp build/gyp
+git clone https://chromium.googlesource.com/external/gyp build/gyp
+if errorlevel 1 goto gyp_install_failed
+goto have_gyp
+
+:gyp_install_failed
+echo Failed to download gyp. Make sure you have git installed, or
+echo manually install gyp into %~dp0build\gyp.
+exit /b 1
+
+:have_gyp
+if not defined PYTHON set PYTHON=python
+"%PYTHON%" gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
+if errorlevel 1 goto create-msvs-files-failed
+if not exist uv.sln goto create-msvs-files-failed
+echo Project files generated.
+
+:msbuild
+@rem Skip project generation if requested.
+if defined nobuild goto run
+
+@rem Check if VS build env is available
+if defined VCINSTALLDIR goto msbuild-found
+if defined WindowsSDKDir goto msbuild-found
+echo Build skipped. To build, this file needs to run from VS cmd prompt.
+goto run
+
+@rem Build the sln with msbuild.
+:msbuild-found
+msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo
+if errorlevel 1 exit /b 1
+
+:run
+@rem Run tests if requested.
+if "%run%"=="" goto exit
+if not exist %config%\%run% goto exit
+echo running '%config%\%run%'
+%config%\%run%
+goto exit
+
+:create-msvs-files-failed
+echo Failed to create vc project files.
+exit /b 1
+
+:help
+echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [x86/x64] [static/shared]
+echo Examples:
+echo vcbuild.bat : builds debug build
+echo vcbuild.bat test : builds debug build and runs tests
+echo vcbuild.bat release bench: builds release build and runs benchmarks
+goto exit
+
+:exit