From 14b4e3473c11b0c6d1d50411e0d423ea67fc2758 Mon Sep 17 00:00:00 2001 From: thinking Date: Fri, 16 Mar 2018 20:48:56 +0800 Subject: [PATCH 01/11] add libuv --- 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md | 10 + 3rd/libuv-1.19.2/.gitignore | 79 + 3rd/libuv-1.19.2/.mailmap | 46 + 3rd/libuv-1.19.2/AUTHORS | 332 ++ 3rd/libuv-1.19.2/CONTRIBUTING.md | 169 + 3rd/libuv-1.19.2/ChangeLog | 3531 ++++++++++++ 3rd/libuv-1.19.2/LICENSE | 70 + 3rd/libuv-1.19.2/LICENSE-docs | 396 ++ 3rd/libuv-1.19.2/MAINTAINERS.md | 43 + 3rd/libuv-1.19.2/Makefile.am | 468 ++ 3rd/libuv-1.19.2/Makefile.mingw | 86 + 3rd/libuv-1.19.2/README.md | 332 ++ 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md | 73 + 3rd/libuv-1.19.2/android-configure | 23 + 3rd/libuv-1.19.2/appveyor.yml | 32 + 3rd/libuv-1.19.2/autogen.sh | 46 + 3rd/libuv-1.19.2/checksparse.sh | 253 + 3rd/libuv-1.19.2/common.gypi | 208 + 3rd/libuv-1.19.2/configure.ac | 72 + 3rd/libuv-1.19.2/docs/code/cgi/main.c | 81 + 3rd/libuv-1.19.2/docs/code/cgi/tick.c | 13 + 3rd/libuv-1.19.2/docs/code/detach/main.c | 31 + 3rd/libuv-1.19.2/docs/code/dns/main.c | 80 + 3rd/libuv-1.19.2/docs/code/helloworld/main.c | 15 + 3rd/libuv-1.19.2/docs/code/idle-basic/main.c | 24 + .../docs/code/idle-compute/main.c | 43 + 3rd/libuv-1.19.2/docs/code/interfaces/main.c | 33 + 3rd/libuv-1.19.2/docs/code/locks/main.c | 57 + .../docs/code/multi-echo-server/hammer.js | 20 + .../docs/code/multi-echo-server/main.c | 114 + .../docs/code/multi-echo-server/worker.c | 88 + 3rd/libuv-1.19.2/docs/code/onchange/main.c | 44 + .../docs/code/pipe-echo-server/main.c | 94 + 3rd/libuv-1.19.2/docs/code/plugin/hello.c | 5 + 3rd/libuv-1.19.2/docs/code/plugin/main.c | 39 + 3rd/libuv-1.19.2/docs/code/plugin/plugin.h | 7 + .../docs/code/proc-streams/main.c | 49 + .../docs/code/proc-streams/test.c | 8 + 3rd/libuv-1.19.2/docs/code/progress/main.c | 47 + .../docs/code/queue-cancel/main.c | 59 + 3rd/libuv-1.19.2/docs/code/queue-work/main.c | 44 + 3rd/libuv-1.19.2/docs/code/ref-timer/main.c | 29 + 3rd/libuv-1.19.2/docs/code/signal/main.c | 66 + 3rd/libuv-1.19.2/docs/code/spawn/main.c | 36 + .../docs/code/tcp-echo-server/main.c | 87 + .../docs/code/thread-create/main.c | 36 + 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c | 48 + 3rd/libuv-1.19.2/docs/code/tty/main.c | 29 + 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c | 127 + 3rd/libuv-1.19.2/docs/code/uvcat/main.c | 63 + 3rd/libuv-1.19.2/docs/code/uvstop/main.c | 33 + 3rd/libuv-1.19.2/docs/code/uvtee/main.c | 80 + 3rd/libuv-1.19.2/docs/code/uvwget/main.c | 166 + 3rd/libuv-1.19.2/docs/make.bat | 243 + 3rd/libuv-1.19.2/docs/src/api.rst | 35 + 3rd/libuv-1.19.2/docs/src/async.rst | 61 + 3rd/libuv-1.19.2/docs/src/check.rst | 46 + 3rd/libuv-1.19.2/docs/src/conf.py | 348 ++ 3rd/libuv-1.19.2/docs/src/design.rst | 138 + 3rd/libuv-1.19.2/docs/src/dll.rst | 44 + 3rd/libuv-1.19.2/docs/src/dns.rst | 108 + 3rd/libuv-1.19.2/docs/src/errors.rst | 344 ++ 3rd/libuv-1.19.2/docs/src/fs.rst | 538 ++ 3rd/libuv-1.19.2/docs/src/fs_event.rst | 132 + 3rd/libuv-1.19.2/docs/src/fs_poll.rst | 77 + 3rd/libuv-1.19.2/docs/src/guide.rst | 22 + 3rd/libuv-1.19.2/docs/src/guide/about.rst | 22 + 3rd/libuv-1.19.2/docs/src/guide/basics.rst | 188 + .../docs/src/guide/eventloops.rst | 48 + .../docs/src/guide/filesystem.rst | 287 + .../docs/src/guide/introduction.rst | 75 + .../docs/src/guide/networking.rst | 249 + 3rd/libuv-1.19.2/docs/src/guide/processes.rst | 389 ++ 3rd/libuv-1.19.2/docs/src/guide/threads.rst | 381 ++ 3rd/libuv-1.19.2/docs/src/guide/utilities.rst | 433 ++ 3rd/libuv-1.19.2/docs/src/handle.rst | 264 + 3rd/libuv-1.19.2/docs/src/idle.rst | 54 + 3rd/libuv-1.19.2/docs/src/index.rst | 62 + 3rd/libuv-1.19.2/docs/src/loop.rst | 236 + .../docs/src/migration_010_100.rst | 244 + 3rd/libuv-1.19.2/docs/src/misc.rst | 519 ++ 3rd/libuv-1.19.2/docs/src/pipe.rst | 113 + 3rd/libuv-1.19.2/docs/src/poll.rst | 121 + 3rd/libuv-1.19.2/docs/src/prepare.rst | 46 + 3rd/libuv-1.19.2/docs/src/process.rst | 231 + 3rd/libuv-1.19.2/docs/src/request.rst | 109 + 3rd/libuv-1.19.2/docs/src/signal.rst | 78 + .../docs/src/sphinx-plugins/manpage.py | 46 + .../docs/src/static/architecture.png | Bin 0 -> 206767 bytes .../src/static/diagrams.key/Data/st0-311.jpg | Bin 0 -> 19328 bytes .../src/static/diagrams.key/Data/st1-475.jpg | Bin 0 -> 12655 bytes .../docs/src/static/diagrams.key/Index.zip | Bin 0 -> 71160 bytes .../Metadata/BuildVersionHistory.plist | 8 + .../diagrams.key/Metadata/DocumentIdentifier | 1 + .../diagrams.key/Metadata/Properties.plist | Bin 0 -> 340 bytes .../src/static/diagrams.key/preview-micro.jpg | Bin 0 -> 1425 bytes .../src/static/diagrams.key/preview-web.jpg | Bin 0 -> 8106 bytes .../docs/src/static/diagrams.key/preview.jpg | Bin 0 -> 107456 bytes 3rd/libuv-1.19.2/docs/src/static/favicon.ico | Bin 0 -> 15086 bytes 3rd/libuv-1.19.2/docs/src/static/logo.png | Bin 0 -> 33545 bytes .../docs/src/static/loop_iteration.png | Bin 0 -> 80528 bytes 3rd/libuv-1.19.2/docs/src/stream.rst | 237 + 3rd/libuv-1.19.2/docs/src/tcp.rst | 115 + 3rd/libuv-1.19.2/docs/src/threading.rst | 168 + 3rd/libuv-1.19.2/docs/src/threadpool.rst | 67 + 3rd/libuv-1.19.2/docs/src/timer.rst | 81 + 3rd/libuv-1.19.2/docs/src/tty.rst | 101 + 3rd/libuv-1.19.2/docs/src/udp.rst | 314 ++ 3rd/libuv-1.19.2/docs/src/upgrading.rst | 11 + 3rd/libuv-1.19.2/docs/src/version.rst | 60 + 3rd/libuv-1.19.2/gyp_uv.py | 73 + 3rd/libuv-1.19.2/img/banner.png | Bin 0 -> 44102 bytes 3rd/libuv-1.19.2/img/logos.svg | 152 + 3rd/libuv-1.19.2/include/android-ifaddrs.h | 54 + 3rd/libuv-1.19.2/include/pthread-barrier.h | 69 + 3rd/libuv-1.19.2/include/stdint-msvc2008.h | 247 + 3rd/libuv-1.19.2/include/tree.h | 768 +++ 3rd/libuv-1.19.2/include/uv-aix.h | 32 + 3rd/libuv-1.19.2/include/uv-bsd.h | 34 + 3rd/libuv-1.19.2/include/uv-darwin.h | 61 + 3rd/libuv-1.19.2/include/uv-errno.h | 437 ++ 3rd/libuv-1.19.2/include/uv-linux.h | 34 + 3rd/libuv-1.19.2/include/uv-os390.h | 33 + 3rd/libuv-1.19.2/include/uv-posix.h | 31 + 3rd/libuv-1.19.2/include/uv-sunos.h | 44 + 3rd/libuv-1.19.2/include/uv-threadpool.h | 37 + 3rd/libuv-1.19.2/include/uv-unix.h | 464 ++ 3rd/libuv-1.19.2/include/uv-version.h | 43 + 3rd/libuv-1.19.2/include/uv-win.h | 676 +++ 3rd/libuv-1.19.2/include/uv.h | 1567 ++++++ 3rd/libuv-1.19.2/libuv.pc.in | 12 + 3rd/libuv-1.19.2/m4/.gitignore | 4 + 3rd/libuv-1.19.2/m4/as_case.m4 | 21 + 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 | 319 ++ 3rd/libuv-1.19.2/samples/.gitignore | 22 + .../samples/socks5-proxy/.gitignore | 21 + 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE | 53 + .../samples/socks5-proxy/build.gyp | 46 + .../samples/socks5-proxy/client.c | 736 +++ 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h | 139 + .../samples/socks5-proxy/getopt.c | 131 + 3rd/libuv-1.19.2/samples/socks5-proxy/main.c | 99 + 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c | 271 + 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h | 94 + .../samples/socks5-proxy/server.c | 241 + 3rd/libuv-1.19.2/samples/socks5-proxy/util.c | 72 + 3rd/libuv-1.19.2/src/fs-poll.c | 256 + 3rd/libuv-1.19.2/src/heap-inl.h | 245 + 3rd/libuv-1.19.2/src/inet.c | 309 ++ 3rd/libuv-1.19.2/src/queue.h | 108 + 3rd/libuv-1.19.2/src/threadpool.c | 318 ++ 3rd/libuv-1.19.2/src/unix/aix-common.c | 292 + 3rd/libuv-1.19.2/src/unix/aix.c | 1041 ++++ 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c | 710 +++ 3rd/libuv-1.19.2/src/unix/async.c | 269 + 3rd/libuv-1.19.2/src/unix/atomic-ops.h | 100 + 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c | 152 + 3rd/libuv-1.19.2/src/unix/core.c | 1355 +++++ 3rd/libuv-1.19.2/src/unix/cygwin.c | 54 + 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c | 209 + 3rd/libuv-1.19.2/src/unix/darwin.c | 231 + 3rd/libuv-1.19.2/src/unix/dl.c | 80 + 3rd/libuv-1.19.2/src/unix/freebsd.c | 375 ++ 3rd/libuv-1.19.2/src/unix/fs.c | 1513 ++++++ 3rd/libuv-1.19.2/src/unix/fsevents.c | 919 ++++ 3rd/libuv-1.19.2/src/unix/getaddrinfo.c | 232 + 3rd/libuv-1.19.2/src/unix/getnameinfo.c | 120 + 3rd/libuv-1.19.2/src/unix/ibmi.c | 112 + 3rd/libuv-1.19.2/src/unix/internal.h | 340 ++ 3rd/libuv-1.19.2/src/unix/kqueue.c | 533 ++ 3rd/libuv-1.19.2/src/unix/linux-core.c | 951 ++++ 3rd/libuv-1.19.2/src/unix/linux-inotify.c | 352 ++ 3rd/libuv-1.19.2/src/unix/linux-syscalls.c | 471 ++ 3rd/libuv-1.19.2/src/unix/linux-syscalls.h | 151 + 3rd/libuv-1.19.2/src/unix/loop-watcher.c | 68 + 3rd/libuv-1.19.2/src/unix/loop.c | 193 + 3rd/libuv-1.19.2/src/unix/netbsd.c | 309 ++ 3rd/libuv-1.19.2/src/unix/no-fsevents.c | 42 + 3rd/libuv-1.19.2/src/unix/no-proctitle.c | 42 + 3rd/libuv-1.19.2/src/unix/openbsd.c | 313 ++ 3rd/libuv-1.19.2/src/unix/os390-syscalls.c | 499 ++ 3rd/libuv-1.19.2/src/unix/os390-syscalls.h | 72 + 3rd/libuv-1.19.2/src/unix/os390.c | 998 ++++ 3rd/libuv-1.19.2/src/unix/pipe.c | 357 ++ 3rd/libuv-1.19.2/src/unix/poll.c | 147 + 3rd/libuv-1.19.2/src/unix/posix-hrtime.c | 35 + 3rd/libuv-1.19.2/src/unix/posix-poll.c | 324 ++ 3rd/libuv-1.19.2/src/unix/process.c | 599 +++ 3rd/libuv-1.19.2/src/unix/procfs-exepath.c | 45 + 3rd/libuv-1.19.2/src/unix/proctitle.c | 132 + 3rd/libuv-1.19.2/src/unix/pthread-fixes.c | 56 + 3rd/libuv-1.19.2/src/unix/signal.c | 564 ++ 3rd/libuv-1.19.2/src/unix/spinlock.h | 53 + 3rd/libuv-1.19.2/src/unix/stream.c | 1696 ++++++ 3rd/libuv-1.19.2/src/unix/sunos.c | 821 +++ 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c | 36 + 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c | 42 + 3rd/libuv-1.19.2/src/unix/tcp.c | 444 ++ 3rd/libuv-1.19.2/src/unix/thread.c | 729 +++ 3rd/libuv-1.19.2/src/unix/timer.c | 172 + 3rd/libuv-1.19.2/src/unix/tty.c | 372 ++ 3rd/libuv-1.19.2/src/unix/udp.c | 902 ++++ 3rd/libuv-1.19.2/src/uv-common.c | 664 +++ 3rd/libuv-1.19.2/src/uv-common.h | 260 + 3rd/libuv-1.19.2/src/uv-data-getter-setters.c | 96 + 3rd/libuv-1.19.2/src/version.c | 45 + 3rd/libuv-1.19.2/src/win/async.c | 98 + 3rd/libuv-1.19.2/src/win/atomicops-inl.h | 57 + 3rd/libuv-1.19.2/src/win/core.c | 605 +++ 3rd/libuv-1.19.2/src/win/detect-wakeup.c | 35 + 3rd/libuv-1.19.2/src/win/dl.c | 133 + 3rd/libuv-1.19.2/src/win/error.c | 171 + 3rd/libuv-1.19.2/src/win/fs-event.c | 561 ++ 3rd/libuv-1.19.2/src/win/fs.c | 2426 +++++++++ 3rd/libuv-1.19.2/src/win/getaddrinfo.c | 453 ++ 3rd/libuv-1.19.2/src/win/getnameinfo.c | 149 + 3rd/libuv-1.19.2/src/win/handle-inl.h | 179 + 3rd/libuv-1.19.2/src/win/handle.c | 159 + 3rd/libuv-1.19.2/src/win/internal.h | 394 ++ 3rd/libuv-1.19.2/src/win/loop-watcher.c | 122 + 3rd/libuv-1.19.2/src/win/pipe.c | 2214 ++++++++ 3rd/libuv-1.19.2/src/win/poll.c | 644 +++ 3rd/libuv-1.19.2/src/win/process-stdio.c | 511 ++ 3rd/libuv-1.19.2/src/win/process.c | 1272 +++++ 3rd/libuv-1.19.2/src/win/req-inl.h | 221 + 3rd/libuv-1.19.2/src/win/req.c | 25 + 3rd/libuv-1.19.2/src/win/signal.c | 277 + 3rd/libuv-1.19.2/src/win/snprintf.c | 42 + 3rd/libuv-1.19.2/src/win/stream-inl.h | 54 + 3rd/libuv-1.19.2/src/win/stream.c | 248 + 3rd/libuv-1.19.2/src/win/tcp.c | 1525 ++++++ 3rd/libuv-1.19.2/src/win/thread.c | 703 +++ 3rd/libuv-1.19.2/src/win/timer.c | 195 + 3rd/libuv-1.19.2/src/win/tty.c | 2328 ++++++++ 3rd/libuv-1.19.2/src/win/udp.c | 965 ++++ 3rd/libuv-1.19.2/src/win/util.c | 1581 ++++++ 3rd/libuv-1.19.2/src/win/winapi.c | 169 + 3rd/libuv-1.19.2/src/win/winapi.h | 4778 +++++++++++++++++ 3rd/libuv-1.19.2/src/win/winsock.c | 591 ++ 3rd/libuv-1.19.2/src/win/winsock.h | 193 + .../test/benchmark-async-pummel.c | 119 + 3rd/libuv-1.19.2/test/benchmark-async.c | 141 + 3rd/libuv-1.19.2/test/benchmark-fs-stat.c | 136 + 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c | 92 + 3rd/libuv-1.19.2/test/benchmark-list.h | 163 + 3rd/libuv-1.19.2/test/benchmark-loop-count.c | 92 + .../test/benchmark-million-async.c | 112 + .../test/benchmark-million-timers.c | 86 + .../test/benchmark-multi-accept.c | 447 ++ 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c | 221 + 3rd/libuv-1.19.2/test/benchmark-pound.c | 351 ++ 3rd/libuv-1.19.2/test/benchmark-pump.c | 476 ++ 3rd/libuv-1.19.2/test/benchmark-sizes.c | 46 + 3rd/libuv-1.19.2/test/benchmark-spawn.c | 164 + .../test/benchmark-tcp-write-batch.c | 144 + 3rd/libuv-1.19.2/test/benchmark-thread.c | 64 + 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c | 243 + 3rd/libuv-1.19.2/test/blackhole-server.c | 121 + 3rd/libuv-1.19.2/test/dns-server.c | 340 ++ 3rd/libuv-1.19.2/test/echo-server.c | 378 ++ 3rd/libuv-1.19.2/test/fixtures/empty_file | 0 .../test/fixtures/load_error.node | 1 + 3rd/libuv-1.19.2/test/run-benchmarks.c | 65 + 3rd/libuv-1.19.2/test/run-tests.c | 204 + 3rd/libuv-1.19.2/test/runner-unix.c | 400 ++ 3rd/libuv-1.19.2/test/runner-unix.h | 36 + 3rd/libuv-1.19.2/test/runner-win.c | 351 ++ 3rd/libuv-1.19.2/test/runner-win.h | 39 + 3rd/libuv-1.19.2/test/runner.c | 434 ++ 3rd/libuv-1.19.2/test/runner.h | 177 + 3rd/libuv-1.19.2/test/task.h | 232 + 3rd/libuv-1.19.2/test/test-active.c | 84 + 3rd/libuv-1.19.2/test/test-async-null-cb.c | 64 + 3rd/libuv-1.19.2/test/test-async.c | 134 + 3rd/libuv-1.19.2/test/test-barrier.c | 106 + 3rd/libuv-1.19.2/test/test-callback-order.c | 77 + 3rd/libuv-1.19.2/test/test-callback-stack.c | 205 + 3rd/libuv-1.19.2/test/test-close-fd.c | 76 + 3rd/libuv-1.19.2/test/test-close-order.c | 80 + 3rd/libuv-1.19.2/test/test-condvar.c | 245 + .../test/test-connect-unspecified.c | 61 + 3rd/libuv-1.19.2/test/test-connection-fail.c | 151 + 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c | 51 + .../test/test-default-loop-close.c | 59 + 3rd/libuv-1.19.2/test/test-delayed-accept.c | 189 + 3rd/libuv-1.19.2/test/test-dlerror.c | 57 + 3rd/libuv-1.19.2/test/test-eintr-handling.c | 94 + 3rd/libuv-1.19.2/test/test-embed.c | 139 + 3rd/libuv-1.19.2/test/test-emfile.c | 117 + 3rd/libuv-1.19.2/test/test-env-vars.c | 90 + 3rd/libuv-1.19.2/test/test-error.c | 73 + 3rd/libuv-1.19.2/test/test-fail-always.c | 29 + 3rd/libuv-1.19.2/test/test-fork.c | 681 +++ 3rd/libuv-1.19.2/test/test-fs-copyfile.c | 173 + 3rd/libuv-1.19.2/test/test-fs-event.c | 1051 ++++ 3rd/libuv-1.19.2/test/test-fs-poll.c | 187 + 3rd/libuv-1.19.2/test/test-fs.c | 3174 +++++++++++ 3rd/libuv-1.19.2/test/test-get-currentexe.c | 86 + 3rd/libuv-1.19.2/test/test-get-loadavg.c | 35 + 3rd/libuv-1.19.2/test/test-get-memory.c | 38 + 3rd/libuv-1.19.2/test/test-get-passwd.c | 86 + 3rd/libuv-1.19.2/test/test-getaddrinfo.c | 191 + 3rd/libuv-1.19.2/test/test-gethostname.c | 62 + 3rd/libuv-1.19.2/test/test-getnameinfo.c | 101 + 3rd/libuv-1.19.2/test/test-getsockname.c | 361 ++ 3rd/libuv-1.19.2/test/test-getters-setters.c | 88 + 3rd/libuv-1.19.2/test/test-handle-fileno.c | 121 + 3rd/libuv-1.19.2/test/test-homedir.c | 72 + 3rd/libuv-1.19.2/test/test-hrtime.c | 54 + 3rd/libuv-1.19.2/test/test-idle.c | 99 + 3rd/libuv-1.19.2/test/test-ip4-addr.c | 46 + 3rd/libuv-1.19.2/test/test-ip6-addr.c | 162 + 3rd/libuv-1.19.2/test/test-ipc-send-recv.c | 428 ++ 3rd/libuv-1.19.2/test/test-ipc.c | 887 +++ 3rd/libuv-1.19.2/test/test-list.h | 905 ++++ 3rd/libuv-1.19.2/test/test-loop-alive.c | 67 + 3rd/libuv-1.19.2/test/test-loop-close.c | 75 + 3rd/libuv-1.19.2/test/test-loop-configure.c | 38 + 3rd/libuv-1.19.2/test/test-loop-handles.c | 337 ++ 3rd/libuv-1.19.2/test/test-loop-stop.c | 71 + 3rd/libuv-1.19.2/test/test-loop-time.c | 63 + 3rd/libuv-1.19.2/test/test-multiple-listen.c | 109 + 3rd/libuv-1.19.2/test/test-mutexes.c | 182 + 3rd/libuv-1.19.2/test/test-osx-select.c | 140 + 3rd/libuv-1.19.2/test/test-pass-always.c | 28 + 3rd/libuv-1.19.2/test/test-ping-pong.c | 274 + 3rd/libuv-1.19.2/test/test-pipe-bind-error.c | 139 + .../test/test-pipe-close-stdout-read-stdin.c | 107 + .../test/test-pipe-connect-error.c | 95 + .../test/test-pipe-connect-multiple.c | 107 + .../test/test-pipe-connect-prepare.c | 83 + 3rd/libuv-1.19.2/test/test-pipe-getsockname.c | 266 + .../test/test-pipe-pending-instances.c | 59 + 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c | 172 + .../test/test-pipe-server-close.c | 94 + 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c | 66 + .../test/test-pipe-set-non-blocking.c | 99 + 3rd/libuv-1.19.2/test/test-platform-output.c | 157 + .../test-poll-close-doesnt-corrupt-stack.c | 116 + 3rd/libuv-1.19.2/test/test-poll-close.c | 73 + 3rd/libuv-1.19.2/test/test-poll-closesocket.c | 93 + 3rd/libuv-1.19.2/test/test-poll-oob.c | 205 + 3rd/libuv-1.19.2/test/test-poll.c | 665 +++ .../test/test-process-title-threadsafe.c | 90 + 3rd/libuv-1.19.2/test/test-process-title.c | 75 + .../test/test-queue-foreach-delete.c | 200 + 3rd/libuv-1.19.2/test/test-ref.c | 445 ++ 3rd/libuv-1.19.2/test/test-run-nowait.c | 45 + 3rd/libuv-1.19.2/test/test-run-once.c | 48 + 3rd/libuv-1.19.2/test/test-semaphore.c | 111 + 3rd/libuv-1.19.2/test/test-shutdown-close.c | 108 + 3rd/libuv-1.19.2/test/test-shutdown-eof.c | 182 + 3rd/libuv-1.19.2/test/test-shutdown-twice.c | 85 + .../test/test-signal-multiple-loops.c | 298 + 3rd/libuv-1.19.2/test/test-signal.c | 325 ++ .../test/test-socket-buffer-size.c | 77 + 3rd/libuv-1.19.2/test/test-spawn.c | 1875 +++++++ 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c | 255 + .../test/test-tcp-alloc-cb-fail.c | 123 + 3rd/libuv-1.19.2/test/test-tcp-bind-error.c | 216 + 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c | 176 + 3rd/libuv-1.19.2/test/test-tcp-close-accept.c | 194 + .../test/test-tcp-close-while-connecting.c | 97 + 3rd/libuv-1.19.2/test/test-tcp-close.c | 136 + .../test/test-tcp-connect-error-after-write.c | 98 + .../test/test-tcp-connect-error.c | 73 + .../test/test-tcp-connect-timeout.c | 91 + .../test/test-tcp-connect6-error.c | 71 + .../test/test-tcp-create-socket-early.c | 209 + 3rd/libuv-1.19.2/test/test-tcp-flags.c | 52 + 3rd/libuv-1.19.2/test/test-tcp-oob.c | 141 + 3rd/libuv-1.19.2/test/test-tcp-open.c | 277 + 3rd/libuv-1.19.2/test/test-tcp-read-stop.c | 76 + .../test/test-tcp-shutdown-after-write.c | 138 + 3rd/libuv-1.19.2/test/test-tcp-try-write.c | 135 + .../test/test-tcp-unexpected-read.c | 117 + .../test/test-tcp-write-after-connect.c | 68 + 3rd/libuv-1.19.2/test/test-tcp-write-fail.c | 115 + .../test/test-tcp-write-queue-order.c | 139 + .../test-tcp-write-to-half-open-connection.c | 141 + 3rd/libuv-1.19.2/test/test-tcp-writealot.c | 180 + 3rd/libuv-1.19.2/test/test-thread-equal.c | 45 + 3rd/libuv-1.19.2/test/test-thread.c | 232 + .../test/test-threadpool-cancel.c | 308 ++ 3rd/libuv-1.19.2/test/test-threadpool.c | 76 + 3rd/libuv-1.19.2/test/test-timer-again.c | 141 + 3rd/libuv-1.19.2/test/test-timer-from-check.c | 80 + 3rd/libuv-1.19.2/test/test-timer.c | 330 ++ 3rd/libuv-1.19.2/test/test-tmpdir.c | 71 + 3rd/libuv-1.19.2/test/test-tty.c | 390 ++ .../test/test-udp-alloc-cb-fail.c | 197 + 3rd/libuv-1.19.2/test/test-udp-bind.c | 93 + .../test/test-udp-create-socket-early.c | 135 + .../test/test-udp-dgram-too-big.c | 91 + 3rd/libuv-1.19.2/test/test-udp-ipv6.c | 198 + .../test/test-udp-multicast-interface.c | 99 + .../test/test-udp-multicast-interface6.c | 103 + .../test/test-udp-multicast-join.c | 150 + .../test/test-udp-multicast-join6.c | 165 + .../test/test-udp-multicast-ttl.c | 94 + 3rd/libuv-1.19.2/test/test-udp-open.c | 204 + 3rd/libuv-1.19.2/test/test-udp-options.c | 137 + .../test/test-udp-send-and-recv.c | 214 + .../test/test-udp-send-hang-loop.c | 99 + .../test/test-udp-send-immediate.c | 149 + .../test/test-udp-send-unreachable.c | 150 + 3rd/libuv-1.19.2/test/test-udp-try-send.c | 121 + 3rd/libuv-1.19.2/test/test-walk-handles.c | 77 + .../test/test-watcher-cross-stop.c | 111 + 3rd/libuv-1.19.2/test/test.gyp | 279 + 3rd/libuv-1.19.2/tools/make_dist_html.py | 124 + 3rd/libuv-1.19.2/uv.gyp | 355 ++ 3rd/libuv-1.19.2/vcbuild.bat | 184 + 413 files changed, 103306 insertions(+) create mode 100644 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md create mode 100644 3rd/libuv-1.19.2/.gitignore create mode 100644 3rd/libuv-1.19.2/.mailmap create mode 100644 3rd/libuv-1.19.2/AUTHORS create mode 100644 3rd/libuv-1.19.2/CONTRIBUTING.md create mode 100644 3rd/libuv-1.19.2/ChangeLog create mode 100644 3rd/libuv-1.19.2/LICENSE create mode 100644 3rd/libuv-1.19.2/LICENSE-docs create mode 100644 3rd/libuv-1.19.2/MAINTAINERS.md create mode 100644 3rd/libuv-1.19.2/Makefile.am create mode 100644 3rd/libuv-1.19.2/Makefile.mingw create mode 100644 3rd/libuv-1.19.2/README.md create mode 100644 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md create mode 100644 3rd/libuv-1.19.2/android-configure create mode 100644 3rd/libuv-1.19.2/appveyor.yml create mode 100644 3rd/libuv-1.19.2/autogen.sh create mode 100644 3rd/libuv-1.19.2/checksparse.sh create mode 100644 3rd/libuv-1.19.2/common.gypi create mode 100644 3rd/libuv-1.19.2/configure.ac create mode 100644 3rd/libuv-1.19.2/docs/code/cgi/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/cgi/tick.c create mode 100644 3rd/libuv-1.19.2/docs/code/detach/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/dns/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/helloworld/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/idle-basic/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/idle-compute/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/interfaces/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/locks/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c create mode 100644 3rd/libuv-1.19.2/docs/code/onchange/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/hello.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/plugin.h create mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/test.c create mode 100644 3rd/libuv-1.19.2/docs/code/progress/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/queue-cancel/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/queue-work/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/ref-timer/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/signal/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/spawn/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/thread-create/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tty/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvcat/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvstop/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvtee/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvwget/main.c create mode 100644 3rd/libuv-1.19.2/docs/make.bat create mode 100644 3rd/libuv-1.19.2/docs/src/api.rst create mode 100644 3rd/libuv-1.19.2/docs/src/async.rst create mode 100644 3rd/libuv-1.19.2/docs/src/check.rst create mode 100644 3rd/libuv-1.19.2/docs/src/conf.py create mode 100644 3rd/libuv-1.19.2/docs/src/design.rst create mode 100644 3rd/libuv-1.19.2/docs/src/dll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/dns.rst create mode 100644 3rd/libuv-1.19.2/docs/src/errors.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs_event.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs_poll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/about.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/basics.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/eventloops.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/filesystem.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/introduction.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/networking.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/processes.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/threads.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/utilities.rst create mode 100644 3rd/libuv-1.19.2/docs/src/handle.rst create mode 100644 3rd/libuv-1.19.2/docs/src/idle.rst create mode 100644 3rd/libuv-1.19.2/docs/src/index.rst create mode 100644 3rd/libuv-1.19.2/docs/src/loop.rst create mode 100644 3rd/libuv-1.19.2/docs/src/migration_010_100.rst create mode 100644 3rd/libuv-1.19.2/docs/src/misc.rst create mode 100644 3rd/libuv-1.19.2/docs/src/pipe.rst create mode 100644 3rd/libuv-1.19.2/docs/src/poll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/prepare.rst create mode 100644 3rd/libuv-1.19.2/docs/src/process.rst create mode 100644 3rd/libuv-1.19.2/docs/src/request.rst create mode 100644 3rd/libuv-1.19.2/docs/src/signal.rst create mode 100644 3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py create mode 100644 3rd/libuv-1.19.2/docs/src/static/architecture.png create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-micro.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-web.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/favicon.ico create mode 100644 3rd/libuv-1.19.2/docs/src/static/logo.png create mode 100644 3rd/libuv-1.19.2/docs/src/static/loop_iteration.png create mode 100644 3rd/libuv-1.19.2/docs/src/stream.rst create mode 100644 3rd/libuv-1.19.2/docs/src/tcp.rst create mode 100644 3rd/libuv-1.19.2/docs/src/threading.rst create mode 100644 3rd/libuv-1.19.2/docs/src/threadpool.rst create mode 100644 3rd/libuv-1.19.2/docs/src/timer.rst create mode 100644 3rd/libuv-1.19.2/docs/src/tty.rst create mode 100644 3rd/libuv-1.19.2/docs/src/udp.rst create mode 100644 3rd/libuv-1.19.2/docs/src/upgrading.rst create mode 100644 3rd/libuv-1.19.2/docs/src/version.rst create mode 100644 3rd/libuv-1.19.2/gyp_uv.py create mode 100644 3rd/libuv-1.19.2/img/banner.png create mode 100644 3rd/libuv-1.19.2/img/logos.svg create mode 100644 3rd/libuv-1.19.2/include/android-ifaddrs.h create mode 100644 3rd/libuv-1.19.2/include/pthread-barrier.h create mode 100644 3rd/libuv-1.19.2/include/stdint-msvc2008.h create mode 100644 3rd/libuv-1.19.2/include/tree.h create mode 100644 3rd/libuv-1.19.2/include/uv-aix.h create mode 100644 3rd/libuv-1.19.2/include/uv-bsd.h create mode 100644 3rd/libuv-1.19.2/include/uv-darwin.h create mode 100644 3rd/libuv-1.19.2/include/uv-errno.h create mode 100644 3rd/libuv-1.19.2/include/uv-linux.h create mode 100644 3rd/libuv-1.19.2/include/uv-os390.h create mode 100644 3rd/libuv-1.19.2/include/uv-posix.h create mode 100644 3rd/libuv-1.19.2/include/uv-sunos.h create mode 100644 3rd/libuv-1.19.2/include/uv-threadpool.h create mode 100644 3rd/libuv-1.19.2/include/uv-unix.h create mode 100644 3rd/libuv-1.19.2/include/uv-version.h create mode 100644 3rd/libuv-1.19.2/include/uv-win.h create mode 100644 3rd/libuv-1.19.2/include/uv.h create mode 100644 3rd/libuv-1.19.2/libuv.pc.in create mode 100644 3rd/libuv-1.19.2/m4/.gitignore create mode 100644 3rd/libuv-1.19.2/m4/as_case.m4 create mode 100644 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 create mode 100644 3rd/libuv-1.19.2/samples/.gitignore create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/client.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/main.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/server.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/util.c create mode 100644 3rd/libuv-1.19.2/src/fs-poll.c create mode 100644 3rd/libuv-1.19.2/src/heap-inl.h create mode 100644 3rd/libuv-1.19.2/src/inet.c create mode 100644 3rd/libuv-1.19.2/src/queue.h create mode 100644 3rd/libuv-1.19.2/src/threadpool.c create mode 100644 3rd/libuv-1.19.2/src/unix/aix-common.c create mode 100644 3rd/libuv-1.19.2/src/unix/aix.c create mode 100644 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c create mode 100644 3rd/libuv-1.19.2/src/unix/async.c create mode 100644 3rd/libuv-1.19.2/src/unix/atomic-ops.h create mode 100644 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c create mode 100644 3rd/libuv-1.19.2/src/unix/core.c create mode 100644 3rd/libuv-1.19.2/src/unix/cygwin.c create mode 100644 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/darwin.c create mode 100644 3rd/libuv-1.19.2/src/unix/dl.c create mode 100644 3rd/libuv-1.19.2/src/unix/freebsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/fs.c create mode 100644 3rd/libuv-1.19.2/src/unix/fsevents.c create mode 100644 3rd/libuv-1.19.2/src/unix/getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/src/unix/getnameinfo.c create mode 100644 3rd/libuv-1.19.2/src/unix/ibmi.c create mode 100644 3rd/libuv-1.19.2/src/unix/internal.h create mode 100644 3rd/libuv-1.19.2/src/unix/kqueue.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-core.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-inotify.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.h create mode 100644 3rd/libuv-1.19.2/src/unix/loop-watcher.c create mode 100644 3rd/libuv-1.19.2/src/unix/loop.c create mode 100644 3rd/libuv-1.19.2/src/unix/netbsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/no-fsevents.c create mode 100644 3rd/libuv-1.19.2/src/unix/no-proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/openbsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.c create mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.h create mode 100644 3rd/libuv-1.19.2/src/unix/os390.c create mode 100644 3rd/libuv-1.19.2/src/unix/pipe.c create mode 100644 3rd/libuv-1.19.2/src/unix/poll.c create mode 100644 3rd/libuv-1.19.2/src/unix/posix-hrtime.c create mode 100644 3rd/libuv-1.19.2/src/unix/posix-poll.c create mode 100644 3rd/libuv-1.19.2/src/unix/process.c create mode 100644 3rd/libuv-1.19.2/src/unix/procfs-exepath.c create mode 100644 3rd/libuv-1.19.2/src/unix/proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/pthread-fixes.c create mode 100644 3rd/libuv-1.19.2/src/unix/signal.c create mode 100644 3rd/libuv-1.19.2/src/unix/spinlock.h create mode 100644 3rd/libuv-1.19.2/src/unix/stream.c create mode 100644 3rd/libuv-1.19.2/src/unix/sunos.c create mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c create mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c create mode 100644 3rd/libuv-1.19.2/src/unix/tcp.c create mode 100644 3rd/libuv-1.19.2/src/unix/thread.c create mode 100644 3rd/libuv-1.19.2/src/unix/timer.c create mode 100644 3rd/libuv-1.19.2/src/unix/tty.c create mode 100644 3rd/libuv-1.19.2/src/unix/udp.c create mode 100644 3rd/libuv-1.19.2/src/uv-common.c create mode 100644 3rd/libuv-1.19.2/src/uv-common.h create mode 100644 3rd/libuv-1.19.2/src/uv-data-getter-setters.c create mode 100644 3rd/libuv-1.19.2/src/version.c create mode 100644 3rd/libuv-1.19.2/src/win/async.c create mode 100644 3rd/libuv-1.19.2/src/win/atomicops-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/core.c create mode 100644 3rd/libuv-1.19.2/src/win/detect-wakeup.c create mode 100644 3rd/libuv-1.19.2/src/win/dl.c create mode 100644 3rd/libuv-1.19.2/src/win/error.c create mode 100644 3rd/libuv-1.19.2/src/win/fs-event.c create mode 100644 3rd/libuv-1.19.2/src/win/fs.c create mode 100644 3rd/libuv-1.19.2/src/win/getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/src/win/getnameinfo.c create mode 100644 3rd/libuv-1.19.2/src/win/handle-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/handle.c create mode 100644 3rd/libuv-1.19.2/src/win/internal.h create mode 100644 3rd/libuv-1.19.2/src/win/loop-watcher.c create mode 100644 3rd/libuv-1.19.2/src/win/pipe.c create mode 100644 3rd/libuv-1.19.2/src/win/poll.c create mode 100644 3rd/libuv-1.19.2/src/win/process-stdio.c create mode 100644 3rd/libuv-1.19.2/src/win/process.c create mode 100644 3rd/libuv-1.19.2/src/win/req-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/req.c create mode 100644 3rd/libuv-1.19.2/src/win/signal.c create mode 100644 3rd/libuv-1.19.2/src/win/snprintf.c create mode 100644 3rd/libuv-1.19.2/src/win/stream-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/stream.c create mode 100644 3rd/libuv-1.19.2/src/win/tcp.c create mode 100644 3rd/libuv-1.19.2/src/win/thread.c create mode 100644 3rd/libuv-1.19.2/src/win/timer.c create mode 100644 3rd/libuv-1.19.2/src/win/tty.c create mode 100644 3rd/libuv-1.19.2/src/win/udp.c create mode 100644 3rd/libuv-1.19.2/src/win/util.c create mode 100644 3rd/libuv-1.19.2/src/win/winapi.c create mode 100644 3rd/libuv-1.19.2/src/win/winapi.h create mode 100644 3rd/libuv-1.19.2/src/win/winsock.c create mode 100644 3rd/libuv-1.19.2/src/win/winsock.h create mode 100644 3rd/libuv-1.19.2/test/benchmark-async-pummel.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-async.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-fs-stat.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-list.h create mode 100644 3rd/libuv-1.19.2/test/benchmark-loop-count.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-million-async.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-million-timers.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-multi-accept.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-pound.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-pump.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-sizes.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-spawn.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-thread.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c create mode 100644 3rd/libuv-1.19.2/test/blackhole-server.c create mode 100644 3rd/libuv-1.19.2/test/dns-server.c create mode 100644 3rd/libuv-1.19.2/test/echo-server.c create mode 100644 3rd/libuv-1.19.2/test/fixtures/empty_file create mode 100644 3rd/libuv-1.19.2/test/fixtures/load_error.node create mode 100644 3rd/libuv-1.19.2/test/run-benchmarks.c create mode 100644 3rd/libuv-1.19.2/test/run-tests.c create mode 100644 3rd/libuv-1.19.2/test/runner-unix.c create mode 100644 3rd/libuv-1.19.2/test/runner-unix.h create mode 100644 3rd/libuv-1.19.2/test/runner-win.c create mode 100644 3rd/libuv-1.19.2/test/runner-win.h create mode 100644 3rd/libuv-1.19.2/test/runner.c create mode 100644 3rd/libuv-1.19.2/test/runner.h create mode 100644 3rd/libuv-1.19.2/test/task.h create mode 100644 3rd/libuv-1.19.2/test/test-active.c create mode 100644 3rd/libuv-1.19.2/test/test-async-null-cb.c create mode 100644 3rd/libuv-1.19.2/test/test-async.c create mode 100644 3rd/libuv-1.19.2/test/test-barrier.c create mode 100644 3rd/libuv-1.19.2/test/test-callback-order.c create mode 100644 3rd/libuv-1.19.2/test/test-callback-stack.c create mode 100644 3rd/libuv-1.19.2/test/test-close-fd.c create mode 100644 3rd/libuv-1.19.2/test/test-close-order.c create mode 100644 3rd/libuv-1.19.2/test/test-condvar.c create mode 100644 3rd/libuv-1.19.2/test/test-connect-unspecified.c create mode 100644 3rd/libuv-1.19.2/test/test-connection-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c create mode 100644 3rd/libuv-1.19.2/test/test-default-loop-close.c create mode 100644 3rd/libuv-1.19.2/test/test-delayed-accept.c create mode 100644 3rd/libuv-1.19.2/test/test-dlerror.c create mode 100644 3rd/libuv-1.19.2/test/test-eintr-handling.c create mode 100644 3rd/libuv-1.19.2/test/test-embed.c create mode 100644 3rd/libuv-1.19.2/test/test-emfile.c create mode 100644 3rd/libuv-1.19.2/test/test-env-vars.c create mode 100644 3rd/libuv-1.19.2/test/test-error.c create mode 100644 3rd/libuv-1.19.2/test/test-fail-always.c create mode 100644 3rd/libuv-1.19.2/test/test-fork.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-copyfile.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-event.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-poll.c create mode 100644 3rd/libuv-1.19.2/test/test-fs.c create mode 100644 3rd/libuv-1.19.2/test/test-get-currentexe.c create mode 100644 3rd/libuv-1.19.2/test/test-get-loadavg.c create mode 100644 3rd/libuv-1.19.2/test/test-get-memory.c create mode 100644 3rd/libuv-1.19.2/test/test-get-passwd.c create mode 100644 3rd/libuv-1.19.2/test/test-getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/test/test-gethostname.c create mode 100644 3rd/libuv-1.19.2/test/test-getnameinfo.c create mode 100644 3rd/libuv-1.19.2/test/test-getsockname.c create mode 100644 3rd/libuv-1.19.2/test/test-getters-setters.c create mode 100644 3rd/libuv-1.19.2/test/test-handle-fileno.c create mode 100644 3rd/libuv-1.19.2/test/test-homedir.c create mode 100644 3rd/libuv-1.19.2/test/test-hrtime.c create mode 100644 3rd/libuv-1.19.2/test/test-idle.c create mode 100644 3rd/libuv-1.19.2/test/test-ip4-addr.c create mode 100644 3rd/libuv-1.19.2/test/test-ip6-addr.c create mode 100644 3rd/libuv-1.19.2/test/test-ipc-send-recv.c create mode 100644 3rd/libuv-1.19.2/test/test-ipc.c create mode 100644 3rd/libuv-1.19.2/test/test-list.h create mode 100644 3rd/libuv-1.19.2/test/test-loop-alive.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-close.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-configure.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-handles.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-stop.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-time.c create mode 100644 3rd/libuv-1.19.2/test/test-multiple-listen.c create mode 100644 3rd/libuv-1.19.2/test/test-mutexes.c create mode 100644 3rd/libuv-1.19.2/test/test-osx-select.c create mode 100644 3rd/libuv-1.19.2/test/test-pass-always.c create mode 100644 3rd/libuv-1.19.2/test/test-ping-pong.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-bind-error.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-error.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-getsockname.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-pending-instances.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-server-close.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c create mode 100644 3rd/libuv-1.19.2/test/test-platform-output.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-close.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-closesocket.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-oob.c create mode 100644 3rd/libuv-1.19.2/test/test-poll.c create mode 100644 3rd/libuv-1.19.2/test/test-process-title-threadsafe.c create mode 100644 3rd/libuv-1.19.2/test/test-process-title.c create mode 100644 3rd/libuv-1.19.2/test/test-queue-foreach-delete.c create mode 100644 3rd/libuv-1.19.2/test/test-ref.c create mode 100644 3rd/libuv-1.19.2/test/test-run-nowait.c create mode 100644 3rd/libuv-1.19.2/test/test-run-once.c create mode 100644 3rd/libuv-1.19.2/test/test-semaphore.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-close.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-eof.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-twice.c create mode 100644 3rd/libuv-1.19.2/test/test-signal-multiple-loops.c create mode 100644 3rd/libuv-1.19.2/test/test-signal.c create mode 100644 3rd/libuv-1.19.2/test/test-socket-buffer-size.c create mode 100644 3rd/libuv-1.19.2/test/test-spawn.c create mode 100644 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-accept.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect6-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-flags.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-oob.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-open.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-read-stop.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-try-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-writealot.c create mode 100644 3rd/libuv-1.19.2/test/test-thread-equal.c create mode 100644 3rd/libuv-1.19.2/test/test-thread.c create mode 100644 3rd/libuv-1.19.2/test/test-threadpool-cancel.c create mode 100644 3rd/libuv-1.19.2/test/test-threadpool.c create mode 100644 3rd/libuv-1.19.2/test/test-timer-again.c create mode 100644 3rd/libuv-1.19.2/test/test-timer-from-check.c create mode 100644 3rd/libuv-1.19.2/test/test-timer.c create mode 100644 3rd/libuv-1.19.2/test/test-tmpdir.c create mode 100644 3rd/libuv-1.19.2/test/test-tty.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-bind.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-create-socket-early.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-ipv6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-open.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-options.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-and-recv.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-immediate.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-unreachable.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-try-send.c create mode 100644 3rd/libuv-1.19.2/test/test-walk-handles.c create mode 100644 3rd/libuv-1.19.2/test/test-watcher-cross-stop.c create mode 100644 3rd/libuv-1.19.2/test/test.gyp create mode 100644 3rd/libuv-1.19.2/tools/make_dist_html.py create mode 100644 3rd/libuv-1.19.2/uv.gyp create mode 100644 3rd/libuv-1.19.2/vcbuild.bat diff --git a/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md b/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..543dc9fd --- /dev/null +++ b/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,10 @@ + +* **Version**: +* **Platform**: diff --git a/3rd/libuv-1.19.2/.gitignore b/3rd/libuv-1.19.2/.gitignore new file mode 100644 index 00000000..7536abd5 --- /dev/null +++ b/3rd/libuv-1.19.2/.gitignore @@ -0,0 +1,79 @@ +*.swp +*.[oa] +*.l[oa] +*.opensdf +*.orig +*.pyc +*.sdf +*.suo +.vs/ +*.VC.db +*.VC.opendb +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 +/android-toolchain + +/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/3rd/libuv-1.19.2/.mailmap b/3rd/libuv-1.19.2/.mailmap new file mode 100644 index 00000000..da421436 --- /dev/null +++ b/3rd/libuv-1.19.2/.mailmap @@ -0,0 +1,46 @@ +A. Hauptmann +Aaron Bieber +Alan Gutierrez +Andrius Bentkus +Bert Belder +Bert Belder +Bert Belder +Brandon Philips +Brian White +Brian White +Caleb James DeLisle +Christoph Iserlohn +Devchandra Meetei Leishangthem +Fedor Indutny +Frank Denis +Imran Iqbal +Isaac Z. Schlueter +Jason Williams +Justin Venus +Keno Fischer +Keno Fischer +Leith Bade +Leonard Hecker +Maciej Małecki +Marc Schlaich +Michael +Michael Neumann +Nicholas Vavilov +Nick Logan +Rasmus Christian Pedersen +Rasmus Christian Pedersen +Robert Mustacchi +Ryan Dahl +Ryan Emery +Sakthipriyan Vairamani +Sam Roberts +San-Tai Hsu +Santiago Gimeno +Saúl Ibarra Corretgé +Shigeki Ohtsu +Timothy J. Fontaine +Yasuhiro Matsumoto +Yazhong Liu +Yuki Okumura +jBarz +jBarz diff --git a/3rd/libuv-1.19.2/AUTHORS b/3rd/libuv-1.19.2/AUTHORS new file mode 100644 index 00000000..fcb0aac3 --- /dev/null +++ b/3rd/libuv-1.19.2/AUTHORS @@ -0,0 +1,332 @@ +# Authors ordered by first contribution. +Ryan Dahl +Bert Belder +Josh Roesslein +Alan Gutierrez +Joshua Peek +Igor Zinkovsky +San-Tai Hsu +Ben Noordhuis +Henry Rawas +Robert Mustacchi +Matt Stevens +Paul Querna +Shigeki Ohtsu +Tom Hughes +Peter Bright +Jeroen Janssen +Andrea Lattuada +Augusto Henrique Hentz +Clifford Heath +Jorge Chamorro Bieling +Luis Lavena +Matthew Sporleder +Erick Tryzelaar +Isaac Z. Schlueter +Pieter Noordhuis +Marek Jelen +Fedor Indutny +Saúl Ibarra Corretgé +Felix Geisendörfer +Yuki Okumura +Roman Shtylman +Frank Denis +Carter Allen +Tj Holowaychuk +Shimon Doodkin +Ryan Emery +Bruce Mitchener +Maciej Małecki +Yasuhiro Matsumoto +Daisuke Murase +Paddy Byers +Dan VerWeire +Brandon Benvie +Brandon Philips +Nathan Rajlich +Charlie McConnell +Vladimir Dronnikov +Aaron Bieber +Bulat Shakirzyanov +Brian White +Erik Dubbelboer +Keno Fischer +Ira Cooper +Andrius Bentkus +Iñaki Baz Castillo +Mark Cavage +George Yohng +Xidorn Quan +Roman Neuhauser +Shuhei Tanuma +Bryan Cantrill +Trond Norbye +Tim Holy +Prancesco Pertugio +Leonard Hecker +Andrew Paprocki +Luigi Grilli +Shannen Saez +Artur Adib +Hiroaki Nakamura +Ting-Yu Lin +Stephen Gallagher +Shane Holloway +Andrew Shaffer +Vlad Tudose +Ben Leslie +Tim Bradshaw +Timothy J. Fontaine +Marc Schlaich +Brian Mazza +Elliot Saba +Ben Kelly +Nils Maier +Nicholas Vavilov +Miroslav Bajtoš +Sean Silva +Wynn Wilkes +Andrei Sedoi +Alex Crichton +Brent Cook +Brian Kaisner +Luca Bruno +Reini Urban +Maks Naumov +Sean Farrell +Chris Bank +Geert Jansen +Christoph Iserlohn +Steven Kabbes +Alex Gaynor +huxingyi +Tenor Biel +Andrej Manduch +Joshua Neuheisel +Alexis Campailla +Yazhong Liu +Sam Roberts +River Tarnell +Nathan Sweet +Trevor Norris +Oguz Bastemur +Dylan Cali +Austin Foxley +Benjamin Saunders +Geoffry Song +Rasmus Christian Pedersen +William Light +Oleg Efimov +Lars Gierth +Rasmus Christian Pedersen +Justin Venus +Kristian Evensen +Linus Mårtensson +Navaneeth Kedaram Nambiathan +Yorkie +StarWing +thierry-FreeBSD +Isaiah Norton +Raul Martins +David Capello +Paul Tan +Javier Hernández +Tonis Tiigi +Norio Kobota +李港平 +Chernyshev Viacheslav +Stephen von Takach +JD Ballard +Luka Perkov +Ryan Cole +HungMingWu +Jay Satiro +Leith Bade +Peter Atashian +Tim Cooper +Caleb James DeLisle +Jameson Nash +Graham Lee +Andrew Low +Pavel Platto +Tony Kelman +John Firebaugh +lilohuang +Paul Goldsmith +Julien Gilli +Michael Hudson-Doyle +Recep ASLANTAS +Rob Adams +Zachary Newman +Robin Hahling +Jeff Widman +cjihrig +Tomasz Kołodziejski +Unknown W. Brackets +Emmanuel Odeke +Mikhail Mukovnikov +Thorsten Lorenz +Yuri D'Elia +Manos Nikolaidis +Elijah Andrews +Michael Ira Krufky +Helge Deller +Joey Geralnik +Tim Caswell +Logan Rosen +Kenneth Perry +John Marino +Alexey Melnichuk +Johan Bergström +Alex Mo +Luis Martinez de Bartolome +Michael Penick +Michael +Massimiliano Torromeo +TomCrypto +Brett Vickers +Ole André Vadla Ravnås +Kazuho Oku +Ryan Phillips +Brian Green +Devchandra Meetei Leishangthem +Corey Farrell +Per Nilsson +Alan Rogers +Daryl Haresign +Rui Abreu Ferreira +João Reis +farblue68 +Jason Williams +Igor Soarez +Miodrag Milanovic +Cheng Zhao +Michael Neumann +Stefano Cristiano +heshamsafi +A. Hauptmann +John McNamee +Yosuke Furukawa +Santiago Gimeno +guworks +RossBencina +Roger A. Light +chenttuuvv +Richard Lau +ronkorving +Corbin Simpson +Zachary Hamm +Karl Skomski +Jeremy Whitlock +Willem Thiart +Ben Trask +Jianghua Yang +Colin Snover +Sakthipriyan Vairamani +Eli Skeggs +nmushell +Gireesh Punathil +Ryan Johnston +Adam Stylinski +Nathan Corvino +Wink Saville +Angel Leon +Louis DeJardin +Imran Iqbal +Petka Antonov +Ian Kronquist +kkdaemon +Yuval Brik +Joran Dirk Greef +Andrey Mazo +sztomi +Martin Bark +Dave +Alexis Murzeau +Didiet +Nan Xiang <514580344@qq.com> +Samuel Lorétan +Nándor István Krácser +Katsutoshi Horie +Lukasz Jagiello +Robert Chiras +Kári Tristan Helgason +Krishnaraj Bhat +Enno Boland +Michael Fero +Robert Jefe Lindstaedt +Myles Borins +Tony Theodore +Jason Ginchereau +Nicolas Cavallari +Pierre-Marie de Rodat +Brian Maher +neevek +John Barboza +liuxiaobo +Michele Caini +Bartosz Sosnowski +Matej Knopp +sunjin.lee +Matt Clarkson +Jeffrey Clark +Bart Robinson +Vit Gottwald +Vladimír Čunát +Alex Hultman +Brad King +Philippe Laferriere +Will Speak +Hitesh Kanwathirtha +Eric Sciple +jBarz +muflub +Daniel Bevenius +Howard Hellyer +Chris Araman +Vladimir Matveev +Jason Madden +Jamie Davis +Daniel Kahn Gillmor +Keane +James McCoy +Bernardo Ramos +Juan Cruz Viotti +Gemini Wen +Sebastian Wiedenroth +Sai Ke WANG +Barnabas Gema +Romain Caire +Robert Ayrapetyan +Refael Ackermann +André Klitzing +Matthew Taylor +CurlyMoo +XadillaX +Anticrisis +Jacob Segal +Maciej Szeptuch (Neverous) +Joel Winarske +Gergely Nagy +Kamil Rytarowski +tux.uudiin <77389867@qq.com> +Nick Logan +darobs +Zheng, Lei +Carlo Marcelo Arenas Belón +Scott Parker +Wade Brainerd +rayrase +Pekka Nikander +Ed Schouten +Xu Meng +Matt Harrison +Anna Henningsen +Jérémy Lal +Ben Wijen +elephantp +Felix Yan +Mason X +Jesse Gorzinski +Ryuichi KAWAMATA +Joyee Cheung diff --git a/3rd/libuv-1.19.2/CONTRIBUTING.md b/3rd/libuv-1.19.2/CONTRIBUTING.md new file mode 100644 index 00000000..d9bf0472 --- /dev/null +++ b/3rd/libuv-1.19.2/CONTRIBUTING.md @@ -0,0 +1,169 @@ +# 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][] 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. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. +- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. + +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.freenode.net/?channels=libuv +[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html +[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/3rd/libuv-1.19.2/ChangeLog b/3rd/libuv-1.19.2/ChangeLog new file mode 100644 index 00000000..53ebd01d --- /dev/null +++ b/3rd/libuv-1.19.2/ChangeLog @@ -0,0 +1,3531 @@ +2018.02.22, Version 1.19.2 (Stable) + +Changes since version 1.19.1: + +* test: fix incorrect asserts (cjihrig) + +* test: fix a typo in test-fork.c (Felix Yan) + +* build: remove long-obsolete gyp workarounds (Ben Noordhuis) + +* build: split off tests into separate gyp file (Ben Noordhuis) + +* test: check uv_cond_timedwait more carefully (Jamie Davis) + +* include,src: introduce UV__ERR() macro (Mason X) + +* build: add url field to libuv.pc (Ben Noordhuis) + +* doc: mark IBM i as Tier 3 support (Jesse Gorzinski) + +* win,build: correct C2059 errors (Michael Fero) + +* zos: fix timeout for condition variable (jBarz) + +* win: CREATE_NO_WINDOW when stdio is not inherited (Nick Logan) + +* build: fix commmon.gypi comment (Ryuichi KAWAMATA) + +* doc: document uv_timer_start() on an active timer (Vladimír Čunát) + +* doc: add note about handle movability (Bartosz Sosnowski) + +* doc: fix syntax error in loop documentation (Bartosz Sosnowski) + +* osx,stream: retry sending handle on EMSGSIZE error (Santiago Gimeno) + +* unix: delay fs req register until after validation (cjihrig) + +* test: add tests for bad inputs (Joyee Cheung) + +* unix,win: ensure req->bufs is freed (cjihrig) + +* test: add additional fs memory management checks (cjihrig) + + +2018.01.20, Version 1.19.1 (Stable), 8202d1751196c2374ad370f7f3779daef89befae + +Changes since version 1.19.0: + +* Revert "unix,tcp: avoid marking server sockets connected" (Ben Noordhuis) + +* Revert "unix,fs: fix for potential partial reads/writes" (Ben Noordhuis) + +* Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" (Ben Noordhuis) + +* cygwin: fix compilation of ifaddrs impl (Brad King) + + +2018.01.18, Version 1.19.0 (Stable), effbb7c9d29090b2e085a40867f8cdfa916a66df + +Changes since version 1.18.0: + +* core: add getter/setter functions for easier ABI compat (Anna Henningsen) + +* unix: make get(set)_process_title MT-safe (Matt Harrison) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* win, process: uv_kill improvements (Bartosz Sosnowski) + +* win: set _WIN32_WINNT to 0x0600 (cjihrig) + +* zos: implement uv_fs_event* functions (jBarz) + +* unix,tcp: avoid marking server sockets connected (Jameson Nash) + +* doc: mark Windows 7 as Tier 1 support (Bartosz Sosnowski) + +* win: map 0.0.0.0 and :: addresses to localhost (Bartosz Sosnowski) + +* build: install libuv.pc unconditionally (Ben Noordhuis) + +* test: remove custom timeout for thread test on ppc (Ben Noordhuis) + +* test: allow multicast not permitted status (Jérémy Lal) + +* test: allow net unreachable status in udp test (Ben Noordhuis) + +* unix: use SA_RESTART when setting our sighandler (Brad King) + +* unix,fs: fix for potential partial reads/writes (Ben Wijen) + +* win,build: do not build executable installer for dll (Bert Belder) + +* win: allow directory symlinks to be created in a non-elevated context (Bert + Belder) + +* zos,test: accept SIGKILL for flaky test (jBarz) + +* win: use RemoveDirectoryW() instead of _wmrmdir() (Ben Noordhuis) + +* unix: fix uv_cpu_info() error on FreeBSD (elephantp) + +* zos,test: decrease pings to avoid timeout (jBarz) + + +2017.12.02, Version 1.18.0 (Stable), 1489c98b7fc17f1702821a269eb0c5e730c5c813 + +Changes since version 1.17.0: + +* aix: fix -Wmaybe-uninitialized warning (cjihrig) + +* doc: remove note about SIGWINCH on Windows (Bartosz Sosnowski) + +* Revert "unix,win: wait for threads to start" (Ben Noordhuis) + +* unix,win: add uv_os_getpid() (Bartosz Sosnowski) + +* unix: remove incorrect assertion in uv_shutdown() (Jameson Nash) + +* doc: fix IRC URL in CONTRIBUTING.md (Matt Harrison) + + +2017.11.25, Version 1.17.0 (Stable), 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 + +Changes since version 1.16.1: + +* unix: avoid malloc() call in uv_spawn() (Ben Noordhuis) + +* doc: clarify the description of uv_loop_alive() (Ed Schouten) + +* win: map UV_FS_O_EXLOCK to a share mode of 0 (Joran Dirk Greef) + +* win: fix build on case-sensitive file systems (Ben Noordhuis) + +* win: fix test runner build with mingw64 (Ben Noordhuis) + +* win: remove unused variable in test/test-fs.c (Ben Noordhuis) + +* zos: add strnlen() implementation (jBarz) + +* unix: keep track of bound sockets sent via spawn (jBarz) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* test: avoid malloc() in threadpool test (Ben Noordhuis) + +* test: lower number of tasks in threadpool test (Ben Noordhuis) + +* win: issue memory barrier in uv_thread_join() (Ben Noordhuis) + +* ibmi: add support for new platform (Xu Meng) + +* test: fix test-spawn compilation (Bartosz Sosnowski) + + +2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 + +Changes since version 1.16.0: + +* unix: move net/if.h include (cjihrig) + +* win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) + + +2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb + +Changes since version 1.15.0: + +* win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) + +* unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) + +* win, fs: fix non-symlink reparse points (Wade Brainerd) + +* test: fix -Wstrict-prototypes warnings (Ben Noordhuis) + +* unix, windows: map ENOTTY errno (Ben Noordhuis) + +* unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) + +* unix: do not close invalid kqueue fd after fork (jBarz) + +* zos: reset epoll data after fork (jBarz) + +* zos: skip fork_threadpool_queue_work_simple (jBarz) + +* test: keep platform_output as first test (Bartosz Sosnowski) + +* win: fix non-English dlopen error message (Bartosz Sosnowski) + +* unix,win: add uv_os_getppid() (cjihrig) + +* test: fix const qualification compiler warning (Ben Noordhuis) + +* doc: mark uv_default_loop() as not thread safe (rayrase) + +* win, pipe: null-initialize stream->shutdown_req (Jameson Nash) + +* tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) + +* test: no extra new line in skipped test output (Bartosz Sosnowski) + +* pipe: allow access from other users (Bartosz Sosnowski) + +* unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) + + +2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 + +Changes since version 1.14.1: + +* unix: limit uv__has_forked_with_cfrunloop to macOS (Kamil Rytarowski) + +* win: fix buffer size in uv__getpwuid_r() (tux.uudiin) + +* win,tty: improve SIGWINCH support (Bartosz Sosnowski) + +* unix: use fchmod() in uv_fs_copyfile() (cjihrig) + +* unix: support copying empty files (cjihrig) + +* unix: truncate destination in uv_fs_copyfile() (Nick Logan) + +* win,build: keep cwd when setting build environment (darobs) + +* test: add NetBSD support to test-udp-ipv6.c (Kamil Rytarowski) + +* unix: add NetBSD support in core.c (Kamil Rytarowski) + +* linux: increase thread stack size with musl libc (Ben Noordhuis) + +* netbsd: correct uv_exepath() on NetBSD (Kamil Rytarowski) + +* test: clean up semaphore after use (jBarz) + +* win,build: bump vswhere_usability_wrapper to 2.0.0 (Refael Ackermann) + +* win: let UV_PROCESS_WINDOWS_HIDE hide consoles (cjihrig) + +* zos: lock protect global epoll list in epoll_ctl (jBarz) + +* zos: change platform name to match python (jBarz) + +* android: fix getifaddrs() (Zheng, Lei) + +* netbsd: implement uv__tty_is_slave() (Kamil Rytarowski) + +* zos: fix readlink for mounts with system variables (jBarz) + +* test: sort the tests alphabetically (Sakthipriyan Vairamani) + +* windows: fix compilation warnings (Carlo Marcelo Arenas Belón) + +* build: avoid -fstrict-aliasing compile option (jBarz) + +* win: remove unused variables (Carlo Marcelo Arenas Belón) + +* unix: remove unused variables (Sakthipriyan Vairamani) + +* netbsd: disable poll_bad_fdtype on NetBSD (Kamil Rytarowski) + +* netbsd: use uv__cloexec and uv__nonblock (Kamil Rytarowski) + +* test: fix udp_multicast_join6 on NetBSD (Kamil Rytarowski) + +* unix,win: add uv_mutex_init_recursive() (Scott Parker) + +* netbsd: do not exclude IPv6 functionality (Kamil Rytarowski) + +* fsevents: watch files with fsevents on macos 10.7+ (Ben Noordhuis) + +* unix: retry on ENOBUFS in sendmsg(2) (Kamil Rytarowski) + + +2017.09.07, Version 1.14.1 (Stable), b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 + +Changes since version 1.14.0: + +* fs, win: add support for user symlinks (Bartosz Sosnowski) + +* cygwin: include uv-posix.h header (Joel Winarske) + +* zos: fix semaphore initialization (jBarz) + +* zos: improve loop_count benchmark performance (jBarz) + +* zos, test: flush out the oob data in callback (jBarz) + +* unix,win: check for bad flags in uv_fs_copyfile() (cjihrig) + +* unix: modify argv[0] when process title is set (Matthew Taylor) + +* unix: don't use req->loop in uv__fs_copyfile() (cjihrig) + +* doc: fix a trivial typo (Vladimír Čunát) + +* android: fix uv_cond_timedwait on API level < 21 (Gergely Nagy) + +* win: add uv__once_init() calls (Bartosz Sosnowski) + +* unix,windows: init all requests in fs calls (cjihrig) + +* unix,windows: return UV_EINVAL on NULL fs reqs (cjihrig) + +* windows: add POST macro to fs functions (cjihrig) + +* unix: handle partial sends in uv_fs_copyfile() (A. Hauptmann) + +* Revert "win, test: fix double close in test runner" (Bartosz Sosnowski) + +* win, test: remove surplus CloseHandle (Bartosz Sosnowski) + + +2017.08.17, Version 1.14.0 (Stable), e0d31e9e21870f88277746b6d59cf07b977cdfea + +Changes since version 1.13.1: + +* unix: check for NULL in uv_os_unsetenv for parameter name (André Klitzing) + +* doc: add thread safety warning for process title (Matthew Taylor) + +* unix: always copy process title into local buffer (Matthew Taylor) + +* poll: add support for OOB TCP and GPIO interrupts (CurlyMoo) + +* win,build: fix appveyor properly (Refael Ackermann) + +* win: include filename in dlopen error message (Ben Noordhuis) + +* aix: add netmask, mac address into net interfaces (Gireesh Punathil) + +* unix, windows: map EREMOTEIO errno (Ben Noordhuis) + +* unix: fix wrong MAC of uv_interface_address (XadillaX) + +* win,build: fix building from Windows SDK or VS console (Saúl Ibarra Corretgé) + +* github: fix link to help repo in issue template (Ben Noordhuis) + +* zos: remove nonexistent include from autotools build (Saúl Ibarra Corretgé) + +* misc: remove reference to pthread-fixes.h from LICENSE (Saúl Ibarra Corretgé) + +* docs: fix guide source code example paths (Anticrisis) + +* android: fix compilation with new NDK versions (Saúl Ibarra Corretgé) + +* misc: add android-toolchain to .gitignore (Saúl Ibarra Corretgé) + +* win, fs: support unusual reparse points (Bartosz Sosnowski) + +* android: fix detection of pthread_condattr_setclock (Saúl Ibarra Corretgé) + +* android: remove no longer needed check (Saúl Ibarra Corretgé) + +* doc: update instructions for building on Android (Saúl Ibarra Corretgé) + +* win, process: support semicolons in PATH variable (Bartosz Sosnowski) + +* doc: document uv_async_(init|send) return values (Ben Noordhuis) + +* doc: add Android as a tier 3 supported platform (Saúl Ibarra Corretgé) + +* unix: add missing semicolon (jBarz) + +* win, test: fix double close in test runner (Bartosz Sosnowski) + +* doc: update supported windows version baseline (Ben Noordhuis) + +* test,zos: skip chown root test (jBarz) + +* test,zos: use gid=-1 to test spawn_setgid_fails (jBarz) + +* zos: fix hr timer resolution (jBarz) + +* android: fix blocking recvmsg due to netlink bug (Jacob Segal) + +* zos: read more accurate rss info from RSM (jBarz) + +* win: allow bound/connected socket in uv_tcp_open() (Maciej Szeptuch + (Neverous)) + +* doc: differentiate SmartOS and SunOS support (cjihrig) + +* unix: make uv_poll_stop() remove fd from pollset (Ben Noordhuis) + +* unix, windows: add basic uv_fs_copyfile() (cjihrig) + + +2017.07.07, Version 1.13.1 (Stable), 2bb4b68758f07cd8617838e68c44c125bc567ba6 + +Changes since version 1.13.0: + +* Now working on version 1.13.1 (cjihrig) + +* build: workaround AppVeyor quirk (Refael Ackermann) + + +2017.07.06, Version 1.13.0 (Stable), 8342fcaab815f33b988c1910ea988f28dfe27edb + +Changes since version 1.12.0: + +* Now working on version 1.12.1 (cjihrig) + +* unix: avoid segfault in uv_get_process_title (Michele Caini) + +* build: add a comma to uv.gyp (Gemini Wen) + +* win: restore file pos after positional read/write (Bartosz Sosnowski) + +* unix,stream: return error on closed handle passing (Santiago Gimeno) + +* unix,benchmark: use fd instead of FILE* after fork (jBarz) + +* zos: avoid compiler warnings (jBarz) + +* win,pipe: race condition canceling readfile thread (Jameson Nash) + +* sunos: filter out non-IPv4/IPv6 interfaces (Sebastian Wiedenroth) + +* sunos: fix cmpxchgi and cmpxchgl type error (Sai Ke WANG) + +* unix: reset signal disposition before execve() (Ben Noordhuis) + +* unix: reset signal mask before execve() (Ben Noordhuis) + +* unix: fix POLLIN assertion on server read (jBarz) + +* zos: use stckf builtin for high-res timer (jBarz) + +* win,udp: implements uv_udp_try_send (Barnabas Gema) + +* win,udp: return UV_EINVAL instead of aborting (Romain Caire) + +* freebsd: replace kvm with sysctl (Robert Ayrapetyan) + +* aix: fix un-initialized pointer field in fs handle (Gireesh Punathil) + +* win,build: support building with VS2017 (Refael Ackermann) + +* doc: add instructions for building on Windows (Refael Ackermann) + +* doc: format README (Refael Ackermann) + + +2017.05.31, Version 1.12.0 (Stable), d6ac141ac674657049598c36604f26e031fae917 + +Changes since version 1.11.0: + +* Now working on version 1.11.1 (cjihrig) + +* test: fix tests on OpenBSD (Santiago Gimeno) + +* test: fix -Wformat warning (Santiago Gimeno) + +* win,fs: avoid double freeing uv_fs_event_t.dirw (Vladimir Matveev) + +* unix: remove unused code in `uv__io_start` (Fedor Indutny) + +* signal: add uv_signal_start_oneshot method (Santiago Gimeno) + +* unix: factor out reusable POSIX hrtime impl (Brad King) + +* unix,win: add uv_os_{get,set,unset}env() (cjihrig) + +* win: add uv__convert_utf8_to_utf16() (cjihrig) + +* docs: improve UV_ENOBUFS scenario documentation (cjihrig) + +* unix: return UV_EINVAL for NULL env name (jBarz) + +* unix: filter getifaddrs results consistently (Brad King) + +* unix: factor out getifaddrs result filter (Brad King) + +* unix: factor out reusable BSD ifaddrs impl (Brad King) + +* unix: use union to follow strict aliasing rules (jBarz) + +* unix: simplify async watcher dispatch logic (Ben Noordhuis) + +* samples: update timer callback prototype (Ben Noordhuis) + +* unix: make loops and watchers usable after fork() (Jason Madden) + +* win: free uv__loops once empty (cjihrig) + +* tools: add make_dist_html.py script (Ben Noordhuis) + +* win,sunos: stop handle on uv_fs_event_start() err (cjihrig) + +* unix,windows: refactor request init logic (Ben Noordhuis) + +* win: fix memory leak inside uv__pipe_getname (A. Hauptmann) + +* fsevent: support for files without short name (Bartosz Sosnowski) + +* doc: fix multiple doc typos (Jamie Davis) + +* test,osx: fix flaky kill test (Santiago Gimeno) + +* unix: inline uv_pipe_bind() err_bind goto target (cjihrig) + +* unix,test: deadstore fixes (Rasmus Christian Pedersen) + +* win: fix memory leak inside uv_fs_access() (A. Hauptmann) + +* doc: fix docs/src/fs.rst build warning (Daniel Bevenius) + +* doc: minor grammar fix in Installation section (Daniel Bevenius) + +* doc: suggestions for design page (Daniel Bevenius) + +* doc: libuv does not touch uv_loop_t.data (Ben Noordhuis) + +* github: add ISSUE_TEMPLATE.md (Ben Noordhuis) + +* doc: add link to libuv/help to README (Ben Noordhuis) + +* udp: fix fast path in uv_udp_send() on unix (Fedor Indutny) + +* test: add test for uv_udp_send() fix (Trevor Norris) + +* doc: fix documentation for uv_handle_t.type (Daniel Kahn Gillmor) + +* zos: use proper prototype for epoll_init() (Ben Noordhuis) + +* doc: rename docs to "libuv documentation" (Saúl Ibarra Corretgé) + +* doc: update copyright years (Saúl Ibarra Corretgé) + +* doc: move TOC to a dedicated document (Saúl Ibarra Corretgé) + +* doc: move documentation section up (Saúl Ibarra Corretgé) + +* doc: move "upgrading" to a standalone document (Saúl Ibarra Corretgé) + +* doc: add initial version of the User Guide (Saúl Ibarra Corretgé) + +* doc: removed unused file (Saúl Ibarra Corretgé) + +* doc: update guide/about and mention new maintainership (Saúl Ibarra Corretgé) + +* doc: remove licensing note from guide/about (Saúl Ibarra Corretgé) + +* doc: add warning note to user guide (Saúl Ibarra Corretgé) + +* doc: change license to CC BY 4.0 (Saúl Ibarra Corretgé) + +* doc: remove ubvook reference from README (Saúl Ibarra Corretgé) + +* doc: add code samples from uvbook (unadapted) (Saúl Ibarra Corretgé) + +* doc: update supported linux/glibc baseline (Ben Noordhuis) + +* win: avoid leaking pipe handles to child processes (Jameson Nash) + +* win,test: support stdout output larger than 1kb (Bartosz Sosnowski) + +* win: remove __declspec(inline) from atomic op (Keane) + +* test: fix VC++ compilation warning (Rasmus Christian Pedersen) + +* build: add -Wstrict-prototypes (Jameson Nash) + +* zos: implement uv__io_fork, skip fs event tests (jBarz) + +* unix: do not close udp sockets on bind error (Marc Schlaich) + +* unix: remove FSEventStreamFlushSync() call (cjihrig) + +* build,openbsd: remove kvm-related code (James McCoy) + +* test: fix flaky tcp-write-queue-order (Santiago Gimeno) + +* unix,win: add uv_os_gethostname() (cjihrig) + +* zos: increase timeout for tcp_writealot (jBarz) + +* zos: do not inline OOB data by default (jBarz) + +* test: fix -Wstrict-prototypes compiler warnings (Ben Noordhuis) + +* unix: factor out reusable no-proctitle impl (Brad King) + +* test: factor out fsevents skip explanation (Brad King) + +* test: skip fork fsevent cases when lacking support (Brad King) + +* unix: factor out reusable no-fsevents impl (Brad King) + +* unix: factor out reusable sysinfo memory lookup (Brad King) + +* unix: factor out reusable sysinfo loadavg impl (Brad King) + +* unix: factor out reusable procfs exepath impl (Brad King) + +* unix: add a uv__io_poll impl using POSIX poll(2) (Brad King) + +* cygwin: implement support for cygwin and msys2 (Brad King) + +* cygwin: recognize EOF on named pipe closure (Brad King) + +* cygwin: fix uv_pipe_connect report of ENOTSOCK (Brad King) + +* cygwin: disable non-functional ipc handle send (Brad King) + +* test: skip self-connecting tests on cygwin (Brad King) + +* doc: mark uv_loop_fork() as experimental (cjihrig) + +* doc: add bzoz to maintainers (Bartosz Sosnowski) + +* doc: fix memory leak in tcp-echo-server example (Bernardo Ramos) + +* win: make uv__get_osfhandle() public (Juan Cruz Viotti) + +* doc: use valid pipe name in pipe-echo-server (Bernardo Ramos) + + +2017.02.02, Version 1.11.0 (Stable), 7452ef4e06a4f99ee26b694c65476401534f2725 + +Changes since version 1.10.2: + +* Now working on version 1.10.3 (cjihrig) + +* win: added fcntl.h to uv-win.h (Michele Caini) + +* unix: move function call out of assert (jBarz) + +* fs: cleanup uv__fs_scandir (Santiago Gimeno) + +* fs: fix crash in uv_fs_scandir_next (muflub) + +* win,signal: fix potential deadlock (Bartosz Sosnowski) + +* unix: use async-signal safe functions between fork and exec (jBarz) + +* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) + +* zos: make platform functional (John Barboza) + +* doc: add repitition qualifier to version regexs (Daniel Bevenius) + +* zos: use gyp OS label "os390" on z/OS (John Barboza) + +* aix: enable uv_get/set_process_title (Howard Hellyer) + +* zos: use built-in proctitle implementation (John Barboza) + +* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) + +* win,test: don't write uninitialized buffer to tty (Bert Belder) + +* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) + +* aix: re-enable fs watch facility (Gireesh Punathil) + + +2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 + +Changes since version 1.10.1: + +* Now working on version 1.10.2 (cjihrig) + +* darwin: fix fsync and fdatasync (Joran Dirk Greef) + +* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" + (Santiago Gimeno) + +* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) + +* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) + +* win: fix comment in quote_cmd_arg (Eric Sciple) + +* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) + +* win, tty: fix crash on restarting with pending data (Nicholas Vavilov) + +* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) + +* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) + +* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) + + +2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 + +Changes since version 1.10.0: + +* Now working on version 1.10.1 (cjihrig) + +* win: fix anonymous union syntax (Brad King) + +* unix: use uv__is_closing everywhere (Santiago Gimeno) + +* win: add missing break statement (cjihrig) + +* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) + +* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) + +* doc: add cjihrig alternative GPG ID (cjihrig) + +* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) + + +2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 + +Changes since version 1.9.1: + +* Now working on version 1.9.2 (Saúl Ibarra Corretgé) + +* doc: add cjihrig GPG ID (cjihrig) + +* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) + +* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra + Corretgé) + +* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) + +* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) + +* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) + +* license: libuv is no longer a Node project (Saúl Ibarra Corretgé) + +* license: add license text we've been using for a while (Saúl Ibarra Corretgé) + +* doc: add licensing information to README (Saúl Ibarra Corretgé) + +* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) + +* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) + +* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) + +* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) + +* doc: update docs with AIX related information (Imran Iqbal) + +* test: silence build warnings (Kári Tristan Helgason) + +* doc: add iWuzHere GPG ID (Imran Iqbal) + +* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) + +* build: fix build on DragonFly (Michael Neumann) + +* unix: correctly detect named pipes on DragonFly (Michael Neumann) + +* test: make tap output the default (Ben Noordhuis) + +* test: don't dump output for skipped tests (Ben Noordhuis) + +* test: improve formatting of diagnostic messages (Ben Noordhuis) + +* test: remove unused RETURN_TODO macro (Ben Noordhuis) + +* doc: fix stream typos (Pierre-Marie de Rodat) + +* doc: update coding style link (Imran Iqbal) + +* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) + +* build: check for warnings for -fvisibility=hidden (Imran Iqbal) + +* unix: remove unneeded TODO note (Saúl Ibarra Corretgé) + +* test: skip tty_pty test if pty is not available (Luca Bruno) + +* sunos: set phys_addr of interface_address using ARP (Brian Maher) + +* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) + +* unix: don't convert stat buffer when syscall fails (Ben Noordhuis) + +* win: compare entire filename in watch events (cjihrig) + +* doc: add a note on safe reuse of uv_write_t (neevek) + +* linux: fix potential event loop stall (Ben Noordhuis) + +* unix,win: make uv_get_process_title() stricter (cjihrig) + +* test: close server before initiating new connection (John Barboza) + +* test: account for multiple handles in one ipc read (John Barboza) + +* unix: fix errno and retval conflict (liuxiaobo) + +* doc: add missing entry in uv_fs_type enum (Michele Caini) + +* unix: preserve loop->data across loop init/done (Ben Noordhuis) + +* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) + +* win: simplify memory copy logic in fs.c (Ben Noordhuis) + +* win: fix compilation on mingw (Bartosz Sosnowski) + +* win: ensure 32-bit printf precision (Matej Knopp) + +* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) + +* test: fix OOB buffer access (Saúl Ibarra Corretgé) + +* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) + +* test: fix android build error. (sunjin.lee) + +* win: evaluate timers when system wakes up (Bartosz Sosnowski) + +* doc: add supported platforms description (Saúl Ibarra Corretgé) + +* win: fix lstat reparse point without link data (Jason Ginchereau) + +* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) + +* zos: add support for new platform (John Barboza) + +* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) + +* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) + +* build: GNU/kFreeBSD support (Jeffrey Clark) + +* zos: use PLO instruction for atomic operations (John Barboza) + +* zos: use pthread helper functions (John Barboza) + +* zos: implement uv__fs_futime (John Barboza) + +* unix: expand range of values for usleep (John Barboza) + +* zos: track unbound handles and bind before listen (John Barboza) + +* test: improve tap output on test failures (Santiago Gimeno) + +* test: refactor fs_event_close_in_callback (Julien Gilli) + +* zos: implement uv__io_check_fd (John Barboza) + +* unix: unneccessary use const qualifier in container_of (John Barboza) + +* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) + +* doc: add santigimeno to maintainers (Santiago Gimeno) + +* win: fix typo in type name (Saúl Ibarra Corretgé) + +* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) + +* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) + +* win: add disk read/write count to uv_getrusage (Imran Iqbal) + +* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) + +* test: improve spawn_setuid_setgid test (Santiago Gimeno) + +* test: fix building pty test on Android (Saúl Ibarra Corretgé) + +* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) + +* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) + +* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) + +* doc: update supported fields for uv_rusage_t (Imran Iqbal) + +* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) + +* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) + +* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) + +* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) + +* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) + +* doc: add ABI tracker link to README (Saúl Ibarra Corretgé) + +* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) + +* test: fix fs_fstat on Android (Vit Gottwald) + +* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) + +* doc: add description of uv_handle_type (Vit Gottwald) + +* build: use -pthreads for tests with autotools (Julien Gilli) + +* win: fix leaky fs request buffer (Jason Ginchereau) + +* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) + +* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) + +* win: fix winapi function pointer typedef syntax (Brad King) + +* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) + +* test: make threadpool_cancel_single deterministic (Ben Noordhuis) + +* test: make threadpool saturation reliable (Ben Noordhuis) + +* unix: don't malloc in uv_thread_create() (Ben Noordhuis) + +* unix: don't include CoreServices globally on macOS (Brad King) + +* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) + +* win: remove unused static variables (Ben Noordhuis) + +* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) + +* signal: replace pthread_once with uv_once (Santiago Gimeno) + +* test: fix sign-compare warning (Will Speak) + +* common: fix unused variable warning (Brad King) + + +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c + +Changes since version 1.9.0: + +* test: handle root home directories (cjihrig) + +* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) + +* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) + +* win: fix var declaration to be C89 compliant (Michael Fero) + +* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) + +* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) + +* Revert "win,build: remove unused build defines" (cjihrig) + +* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) + +* linux: don't abort on malformed /proc/stat (Ben Noordhuis) + +* linux: fix long lines in linux-core.c (Ben Noordhuis) + +* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) + +* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) + +* unix: delay signal handling until after normal i/o (Ben Noordhuis) + +* android: pthread_sigmask() does not set errno (Oguz Bastemur) + +* win: work around sharepoint scandir bug (Ben Noordhuis) + +* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) + +* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) + +* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) + +* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) + +* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) + +* unix: error on realpath if PATH_MAX is undefined (Myles Borins) + +* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) + +* build: bump android ndk version (Kári Tristan Helgason) + +* build: always compile with -fvisibility=hidden (Ben Noordhuis) + +* test: fix -Wformat warnings in platform test (Ben Noordhuis) + +* win: clarify fsevents handling code (Saúl Ibarra Corretgé) + +* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) + +* build, mingw: set LIBS in configure.ac (Tony Theodore) + +* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) + +* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* darwin: work around condition variable kernel bug (Ben Noordhuis) + +* darwin: make thread stack multiple of page size (Ben Noordhuis) + +* build,win: rename platform to msbuild_platform (João Reis) + +* gitignore: ignore VS temporary database files (João Reis) + +* test: skip emfile on AIX (Imran Iqbal) + +* unix: use system allocator for scandir() (cjihrig) + +* common: release uv_fs_scandir() array (cjihrig) + +* win: call uv__fs_scandir_cleanup() (cjihrig) + +* win,tty: fix read stop in line mode (João Reis) + +* win,tty: don't duplicate handle for line reads (João Reis) + +* win,tty: restore cursor after canceling line read (Alexis Campailla) + + +2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 + +Changes since version 1.8.0: + +* win: wait for full timeout duration (João Reis) + +* unix: fix support for uClibc-ng (Martin Bark) + +* doc: indicate where new test files need to be added (Dave) + +* test,unix: fix logic error in test runner (Ben Noordhuis) + +* fs: don't nullify req->bufs on EINTR (Dave) + +* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) + +* build: invoke libtoolize with --copy (Ben Noordhuis) + +* test: fixup eintr_handling (Saúl Ibarra Corretgé) + +* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) + +* test,win: fix compilation with shared lib (Alexis Murzeau) + +* test: fix race condition in pipe-close-stdout (Imran Iqbal) + +* unix,win: add uv_os_tmpdir() (cjihrig) + +* ios: fix undefined PTHREAD_STACK_MIN (Didiet) + +* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) + +* unix: report errors for unpollable fds (Ben Noordhuis) + +* win: fix watching root files (Nicholas Vavilov) + +* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) + +* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) + +* test,win: fix compilation warning (Saúl Ibarra Corretgé) + +* test: use uv_loop_close and assert its result (Nan Xiang) + +* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) + +* osx: protected use of potentially undefined macro (Samuel Lorétan) + +* linux: fix compilation with musl (Saúl Ibarra Corretgé) + +* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) + +* doc: add missing link in README (Saúl Ibarra Corretgé) + +* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) + +* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) + +* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) + +* doc: add missing write callback to example (Nándor István Krácser) + +* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) + +* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) + +* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) + +* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) + +* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) + +* linux: fix cpu count (Lukasz Jagiello) + +* unix: fix uv__handle_type for AIX (Imran Iqbal) + +* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* unix: fix compile error in Android using bionic (Robert Chiras) + +* linux: add braces to multi-statement if (Kári Tristan Helgason) + +* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) + +* unix: add fork-safe open file function (Kári Tristan Helgason) + +* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) + +* linux: remove redundant call to rewind() (Krishnaraj Bhat) + +* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) + +* test: fix poll_bad_fdtype for AIX (Imran Iqbal) + +* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) + +* poll: add UV_DISCONNECT event (Santiago Gimeno) + +* fs: realpath: fix string size before converting (Yuval Brik) + +* win: use native APIs for UTF conversions (cjihrig) + +* doc: clarify uv_loop_close() (Ben Noordhuis) + +* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) + +* win,build: remove unused build defines (Saúl Ibarra Corretgé) + +* win: fix buffer overflow in fs events (Joran Dirk Greef) + +* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) + +* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) + +* test: add missing copyright header (cjihrig) + +* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) + +* unix,win: add uv_get_passwd() (cjihrig) + +* process: fix uv_spawn edge-case (Santiago Gimeno) + +* test: use %ld for printing uid/gid (Ben Noordhuis) + +* aix: fix ahafs implementation (Imran Iqbal) + +* aix: do not store absolute path to ahafs (Imran Iqbal) + +* process: close process pipes safely (Santiago Gimeno) + +* unix: open ttyname instead of /dev/tty (Enno Boland) + +* unix: remove outdated comment (Kári Tristan Helgason) + + +2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 + +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/3rd/libuv-1.19.2/LICENSE b/3rd/libuv-1.19.2/LICENSE new file mode 100644 index 00000000..28f17339 --- /dev/null +++ b/3rd/libuv-1.19.2/LICENSE @@ -0,0 +1,70 @@ +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +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 parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +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.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/3rd/libuv-1.19.2/LICENSE-docs b/3rd/libuv-1.19.2/LICENSE-docs new file mode 100644 index 00000000..53883b1c --- /dev/null +++ b/3rd/libuv-1.19.2/LICENSE-docs @@ -0,0 +1,396 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/3rd/libuv-1.19.2/MAINTAINERS.md b/3rd/libuv-1.19.2/MAINTAINERS.md new file mode 100644 index 00000000..d85deb00 --- /dev/null +++ b/3rd/libuv-1.19.2/MAINTAINERS.md @@ -0,0 +1,43 @@ + +# Project Maintainers + +libuv is currently managed by the following individuals: + +* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) +* **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)) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) +* **Fedor Indutny** ([@indutny](https://github.com/indutny)) + - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) +* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) + - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) +* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) + - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) +* **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/3rd/libuv-1.19.2/Makefile.am b/3rd/libuv-1.19.2/Makefile.am new file mode 100644 index 00000000..ae9d96bc --- /dev/null +++ b/3rd/libuv-1.19.2/Makefile.am @@ -0,0 +1,468 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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-data-getter-setters.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 += -pthreads +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 +libuv_la_SOURCES += src/win/async.c \ + src/win/atomicops-inl.h \ + src/win/core.c \ + src/win/detect-wakeup.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 +if OS390 +test_run_tests_CFLAGS = +else +test_run_tests_CFLAGS = -Wno-long-long +endif + +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. +test_run_tests_CFLAGS += -pthreads +endif + +test_run_tests_LDFLAGS = +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-connect-unspecified.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-eintr-handling.c \ + test/test-embed.c \ + test/test-emfile.c \ + test/test-env-vars.c \ + test/test-error.c \ + test/test-fail-always.c \ + test/test-fs-copyfile.c \ + test/test-fs-event.c \ + test/test-fs-poll.c \ + test/test-fs.c \ + test/test-fork.c \ + test/test-getters-setters.c \ + test/test-get-currentexe.c \ + test/test-get-loadavg.c \ + test/test-get-memory.c \ + test/test-get-passwd.c \ + test/test-getaddrinfo.c \ + test/test-gethostname.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-pipe-set-fchmod.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-poll-oob.c \ + test/test-process-title.c \ + test/test-process-title-threadsafe.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-alloc-cb-fail.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-tmpdir.c \ + test/test-tty.c \ + test/test-udp-alloc-cb-fail.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-hang-loop.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 LINUX +test_run_tests_CFLAGS += -D_GNU_SOURCE +endif + +if SUNOS +test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +endif + +if OS390 +test_run_tests_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_FILE_EXT \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +endif + +if AIX +libuv_la_CFLAGS += -D_ALL_SOURCE \ + -D_XOPEN_SOURCE=500 \ + -D_LINUX_SOURCE_COMPAT \ + -D_THREAD_SAFE \ + -DHAVE_SYS_AHAFS_EVPRODS_H +include_HEADERS += include/uv-aix.h +libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c +endif + +if ANDROID +include_HEADERS += include/android-ifaddrs.h \ + include/pthread-barrier.h +libuv_la_SOURCES += src/unix/android-ifaddrs.c \ + src/unix/pthread-fixes.c +endif + +if CYGWIN +include_HEADERS += include/uv-posix.h +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_SOURCES += src/unix/cygwin.c \ + src/unix/bsd-ifaddrs.c \ + src/unix/no-fsevents.c \ + src/unix/no-proctitle.c \ + src/unix/posix-hrtime.c \ + src/unix/posix-poll.c \ + src/unix/procfs-exepath.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +endif + +if DARWIN +include_HEADERS += include/uv-darwin.h \ + include/pthread-barrier.h +libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 +libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/darwin.c \ + src/unix/darwin-proctitle.c \ + src/unix/fsevents.c \ + src/unix/kqueue.c \ + src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil +endif + +if DRAGONFLY +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if FREEBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +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/procfs-exepath.c \ + src/unix/proctitle.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +test_run_tests_LDFLAGS += -lutil +endif + +if MSYS +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_SOURCES += src/unix/cygwin.c \ + src/unix/bsd-ifaddrs.c \ + src/unix/no-fsevents.c \ + src/unix/no-proctitle.c \ + src/unix/posix-hrtime.c \ + src/unix/posix-poll.c \ + src/unix/procfs-exepath.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +endif + +if NETBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ + src/unix/netbsd.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if OPENBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ + src/unix/openbsd.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if SUNOS +include_HEADERS += include/uv-sunos.h +libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +libuv_la_SOURCES += src/unix/no-proctitle.c \ + src/unix/sunos.c +endif + +if OS390 +include_HEADERS += include/pthread-barrier.h +libuv_la_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_SYS_FILE_EXT \ + -DUV_PLATFORM_SEM_T=int \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +libuv_la_LDFLAGS += -qXPLINK +libuv_la_SOURCES += src/unix/pthread-fixes.c \ + src/unix/os390.c \ + src/unix/os390-syscalls.c \ + src/unix/proctitle.c +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/3rd/libuv-1.19.2/Makefile.mingw b/3rd/libuv-1.19.2/Makefile.mingw new file mode 100644 index 00000000..3acf9e14 --- /dev/null +++ b/3rd/libuv-1.19.2/Makefile.mingw @@ -0,0 +1,86 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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 \ + -Wstrict-prototypes \ + -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/detect-wakeup.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/3rd/libuv-1.19.2/README.md b/3rd/libuv-1.19.2/README.md new file mode 100644 index 00000000..733171be --- /dev/null +++ b/3rd/libuv-1.19.2/README.md @@ -0,0 +1,332 @@ +![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][], 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. + +The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/). + +## Licensing + +libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). +The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-docs file](LICENSE-docs). + +## Community + + * [Support](https://github.com/libuv/help) + * [Mailing list](http://groups.google.com/group/libuv) + * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) + +## Documentation + +### Official 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: + +```bash +$ make help +``` + +Build documentation as HTML: + +```bash +$ make html +``` + +Build documentation as HTML and live reload it when it changes (this requires +sphinx-autobuild to be installed and is only supported on Unix): + +```bash +$ make livehtml +``` + +Build documentation as man pages: + +```bash +$ make man +``` + +Build documentation as ePub: + +```bash +$ 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 + + * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) + — High-level introductory talk about libuv. + * [libuv-dox](https://github.com/thlorenz/libuv-dox) + — Documenting types and methods of libuv, mostly by reading uv.h. + * [learnuv](https://github.com/thlorenz/learnuv) + — 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: + +```bash +$ gpg --keyserver pool.sks-keyservers.net --recv-keys AE9BC059 +``` + +Importing a key from a git blob object: + +```bash +$ git show pubkey-saghul | gpg --import +``` + +### Verifying releases + +Git tags are signed with the developer's key, they can be verified as follows: + +```bash +$ 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: + +```bash +$ 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: + +```bash +$ sh autogen.sh +$ ./configure +$ make +$ make check +$ make install +``` + +### Windows + +Prerequisites: + +* [Python 2.6 or 2.7][] 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` +* One of: + * [Visual C++ Build Tools][] + * [Visual Studio 2015 Update 3][], all editions + including the Community edition (remember to select + "Common Tools for Visual C++ 2015" feature during installation). + * [Visual Studio 2017][], any edition (including the Build Tools SKU). + **Required Components:** "MSbuild", "VC++ 2017 v141 toolset" and one of the + Windows SDKs (10 or 8.1). +* Basic Unix tools required for some tests, + [Git for Windows][] includes Git Bash + and tools which can be included in the global `PATH`. + +To build, launch a git shell (e.g. Cmd or PowerShell), run `vcbuild.bat` +(to build with VS2017 you need to explicitly add a `vs2017` argument), +which will checkout the GYP code into `build/gyp`, generate `uv.sln` +as well as the necesery related project files, and start building. + +```console +> vcbuild +``` + +Or: + +```console +> vcbuild vs2017 +``` + +To run the tests: + +```console +> vcbuild test +``` + +To see all the options that could passed to `vcbuild`: + +```console +> vcbuild help +vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] +Examples: + vcbuild.bat : builds debug build + vcbuild.bat test : builds debug build and runs tests + vcbuild.bat release bench: builds release build and runs benchmarks +``` + + +### Unix + +For Debug builds (recommended) run: + +```bash +$ ./gyp_uv.py -f make +$ make -C out +``` + +For Release builds run: + +```bash +$ ./gyp_uv.py -f make +$ BUILDTYPE=Release make -C out +``` + +Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. + +### OS X + +Run: + +```bash +$ ./gyp_uv.py -f xcode +$ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ + -configuration Release -target All +``` + +Using Homebrew: + +```bash +$ 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: + +```bash +$ source ./android-configure NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +The default API level is 24, but a different one can be selected as follows: + +```bash +$ source ./android-configure ~/android-ndk-r15b gyp 21 +$ 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: + +```bash +$ ./gyp_uv.py -f ninja +$ ninja -C out/Debug #for debug build OR +$ ninja -C out/Release +``` + + +### Running tests + +Run: + +```bash +$ ./gyp_uv.py -f make +$ make -C out +$ ./out/Debug/run-tests +``` + +## Supported Platforms + +Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). + +### 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/ +[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md +[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png +[x32]: https://en.wikipedia.org/wiki/X32_ABI +[Python 2.6 or 2.7]: https://www.python.org/downloads/ +[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools +[Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ +[Visual Studio 2017]: https://www.visualstudio.com/downloads/ +[Git for Windows]: http://git-scm.com/download/win diff --git a/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md b/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md new file mode 100644 index 00000000..07719108 --- /dev/null +++ b/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md @@ -0,0 +1,73 @@ +# Supported platforms + +| System | Support type | Supported versions | Notes | +|---|---|---|---| +| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | +| macOS | Tier 1 | macOS >= 10.7 | | +| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported | +| FreeBSD | Tier 1 | >= 9 (see note) | | +| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | +| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | +| Linux with musl | Tier 2 | musl >= 1.0 | | +| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | +| Android | Tier 3 | NDK >= r15b | | +| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | +| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| SunOS | Tier 3 | Solaris 121 and later | | +| Other | Tier 3 | N/A | | + +#### Note on FreeBSD 9 + +While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until +it reaches end of life, in December 2016. + +## Support types + +* **Tier 1**: Officially supported and tested with CI. Any contributed patch + MUST NOT break such systems. These are supported by @libuv/collaborators. + +* **Tier 2**: Officially supported, but not necessarily tested with CI. These + systems are maintained to the best of @libuv/collaborators ability, + without being a top priority. + +* **Tier 3**: Community maintained. These systems may inadvertently break and the + community and interested parties are expected to help with the maintenance. + +## Adding support for a new platform + +**IMPORTANT**: Before attempting to add support for a new platform please open +an issue about it for discussion. + +### Unix + +I/O handling is abstracted by an internal `uv__io_t` handle. The new platform +will need to implement some of the functions, the prototypes are in +``src/unix/internal.h``. + +If the new platform requires extra fields for any handle structure, create a +new include file in ``include/`` with the name ``uv-theplatform.h`` and add +the appropriate defines there. + +All functionality related to the new platform must be implemented in its own +file inside ``src/unix/`` unless it's already done in a common file, in which +case adding an `ifdef` is fine. + +Two build systems are supported: autotools and GYP. Ideally both need to be +supported, but if GYP does not support the new platform it can be left out. + +### Windows + +Windows is treated as a single platform, so adding support for a new platform +would mean adding support for a new version. + +Compilation and runtime must succeed for the minimum supported version. If a +new API is to be used, it must be done optionally, only in supported versions. + +### Common + +Some common notes when adding support for new platforms: + +* Generally libuv tries to avoid compile time checks. Do not add any to the + autotools based build system or use version checking macros. + Dynamically load functions and symbols if they are not supported by the + minimum supported version. diff --git a/3rd/libuv-1.19.2/android-configure b/3rd/libuv-1.19.2/android-configure new file mode 100644 index 00000000..b5c11cd4 --- /dev/null +++ b/3rd/libuv-1.19.2/android-configure @@ -0,0 +1,23 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain +mkdir -p $TOOLCHAIN +API=${3:-24} +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=arm-linux-androideabi-4.9 \ + --arch=arm \ + --install-dir=$TOOLCHAIN \ + --platform=android-$API \ + --force +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 +export CFLAGS="-D__ANDROID_API__=$API" + +if [[ $2 == 'gyp' ]] + then + ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android +fi diff --git a/3rd/libuv-1.19.2/appveyor.yml b/3rd/libuv-1.19.2/appveyor.yml new file mode 100644 index 00000000..1b018a59 --- /dev/null +++ b/3rd/libuv-1.19.2/appveyor.yml @@ -0,0 +1,32 @@ +version: v1.18.0.build{build} + +init: + - git config --global core.autocrlf true + +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 + +cache: + - C:\projects\libuv\build\gyp diff --git a/3rd/libuv-1.19.2/autogen.sh b/3rd/libuv-1.19.2/autogen.sh new file mode 100644 index 00000000..271c2ee8 --- /dev/null +++ b/3rd/libuv-1.19.2/autogen.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# 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" --copy +"$ACLOCAL" -I m4 +"$AUTOCONF" +"$AUTOMAKE" --add-missing --copy diff --git a/3rd/libuv-1.19.2/checksparse.sh b/3rd/libuv-1.19.2/checksparse.sh new file mode 100644 index 00000000..27eb529b --- /dev/null +++ b/3rd/libuv-1.19.2/checksparse.sh @@ -0,0 +1,253 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# 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 +src/uv-data-getter-setters.c +" + +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-env-vars.c +test/test-error.c +test/test-fail-always.c +test/test-fs-copyfile.c +test/test-fs-event.c +test/test-fs-poll.c +test/test-fs.c +test/test-getters-setters.c +test/test-get-currentexe.c +test/test-get-loadavg.c +test/test-get-memory.c +test/test-get-passwd.c +test/test-getaddrinfo.c +test/test-gethostname.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-process-title-threadsafe.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-tmpdir.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-udp-send-hang-loop.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-common.c + src/unix/aix.c" + ;; +OS400) + SPARSE_FLAGS="$SPARSE_FLAGS -D_PASE=1" + SOURCES="$SOURCES + src/unix/aix-common.c + src/unix/ibmi.c + src/unix/posix-poll.c + src/unix/no-fsevents.c + src/unix/no-proctitle.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/3rd/libuv-1.19.2/common.gypi b/3rd/libuv-1.19.2/common.gypi new file mode 100644 index 00000000..572a1633 --- /dev/null +++ b/3rd/libuv-1.19.2/common.gypi @@ -0,0 +1,208 @@ +{ + 'variables': { + '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' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['uv_library=="static_library"', { + 'RuntimeLibrary': 1, # /MTd static debug + }, { + 'RuntimeLibrary': 3, # /MDd 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', + }, + 'conditions': [ + ['OS != "zos"', { + 'cflags': [ '-O0', '-fwrapv' ] + }], + ['OS == "android"', { + 'cflags': [ '-fPIE' ], + 'ldflags': [ '-fPIE', '-pie' ] + }] + ] + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'cflags': [ + '-O3', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['uv_library=="static_library"', { + 'RuntimeLibrary': 0, # /MT static release + }, { + 'RuntimeLibrary': 2, # /MD DLL 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 + }, + }, + 'conditions': [ + ['OS != "zos"', { + 'cflags': [ + '-fomit-frame-pointer', + '-fdata-sections', + '-ffunction-sections', + ], + }], + ] + } + }, + '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 zos"', { + 'cflags': [ '-pthread' ], + 'ldflags': [ '-pthread' ], + }], + ], + }], + ['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_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'PREBINDING': 'NO', # No -Wl,-prebind + 'USE_HEADERMAP': 'NO', + 'WARNING_CFLAGS': [ + '-Wall', + '-Wendif-labels', + '-W', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + }, + '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/3rd/libuv-1.19.2/configure.ac b/3rd/libuv-1.19.2/configure.ac new file mode 100644 index 00000000..4074e778 --- /dev/null +++ b/3rd/libuv-1.19.2/configure.ac @@ -0,0 +1,72 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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.19.2], [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 +AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) +]) +CC_FLAG_VISIBILITY #[-fvisibility=hidden] +CC_CHECK_CFLAGS_APPEND([-g]) +CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-Wall]) +CC_CHECK_CFLAGS_APPEND([-Wextra]) +CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) +CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) +# 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([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([CYGWIN], [AS_CASE([$host_os],[cygwin*], [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([MSYS], [AS_CASE([$host_os],[msys*], [true], [false])]) +AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) +AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) +AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])]) +AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) +AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) +AS_CASE([$host_os],[mingw*], [ + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" +]) +AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) +AC_CHECK_HEADERS([sys/ahafs_evProds.h]) +AC_CONFIG_FILES([Makefile libuv.pc]) +AC_OUTPUT diff --git a/3rd/libuv-1.19.2/docs/code/cgi/main.c b/3rd/libuv-1.19.2/docs/code/cgi/main.c new file mode 100644 index 00000000..d2e34265 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/cgi/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req->data, NULL); + uv_close((uv_handle_t*) req, NULL); +} + +void invoke_cgi_script(uv_tcp_t *client) { + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("cgi")), "tick"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... finding the executable path and setting up arguments ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_INHERIT_STREAM; + child_stdio[1].data.stream = (uv_stream_t*) client; + child_stdio[2].flags = UV_IGNORE; + options.stdio = child_stdio; + + options.exit_cb = cleanup_handles; + options.file = args[0]; + options.args = args; + + // Set this so we can close the socket after the child process exits. + child_req.data = (void*) client; + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return; + } +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + invoke_cgi_script(client); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/cgi/tick.c b/3rd/libuv-1.19.2/docs/code/cgi/tick.c new file mode 100644 index 00000000..0b498edf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/cgi/tick.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + int i; + for (i = 0; i < 10; i++) { + printf("tick\n"); + fflush(stdout); + sleep(1); + } + printf("BOOM!\n"); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/detach/main.c b/3rd/libuv-1.19.2/docs/code/detach/main.c new file mode 100644 index 00000000..3c88fff4 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/detach/main.c @@ -0,0 +1,31 @@ +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "sleep"; + args[1] = "100"; + args[2] = NULL; + + options.exit_cb = NULL; + options.file = "sleep"; + options.args = args; + options.flags = UV_PROCESS_DETACHED; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid); + uv_unref((uv_handle_t*) &child_req); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/dns/main.c b/3rd/libuv-1.19.2/docs/code/dns/main.c new file mode 100644 index 00000000..77a7005f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/dns/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +uv_loop_t *loop; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + free(buf->base); + free(client); + return; + } + + char *data = (char*) malloc(sizeof(char) * (nread+1)); + data[nread] = '\0'; + strncpy(data, buf->base, nread); + + fprintf(stderr, "%s", data); + free(data); + free(buf->base); +} + +void on_connect(uv_connect_t *req, int status) { + if (status < 0) { + fprintf(stderr, "connect failed error %s\n", uv_err_name(status)); + free(req); + return; + } + + uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read); + free(req); +} + +void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { + if (status < 0) { + fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status)); + return; + } + + char addr[17] = {'\0'}; + uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16); + fprintf(stderr, "%s\n", addr); + + uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); + uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect); + + uv_freeaddrinfo(res); +} + +int main() { + loop = uv_default_loop(); + + struct addrinfo hints; + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = 0; + + uv_getaddrinfo_t resolver; + fprintf(stderr, "irc.freenode.net is... "); + int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints); + + if (r) { + fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/helloworld/main.c b/3rd/libuv-1.19.2/docs/code/helloworld/main.c new file mode 100644 index 00000000..a31bf88a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/helloworld/main.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int main() { + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + uv_loop_init(loop); + + printf("Now quitting.\n"); + uv_run(loop, UV_RUN_DEFAULT); + + uv_loop_close(loop); + free(loop); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/idle-basic/main.c b/3rd/libuv-1.19.2/docs/code/idle-basic/main.c new file mode 100644 index 00000000..77ba31cf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/idle-basic/main.c @@ -0,0 +1,24 @@ +#include +#include + +int64_t counter = 0; + +void wait_for_a_while(uv_idle_t* handle) { + counter++; + + if (counter >= 10e6) + uv_idle_stop(handle); +} + +int main() { + uv_idle_t idler; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, wait_for_a_while); + + printf("Idling...\n"); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_loop_close(uv_default_loop()); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/idle-compute/main.c b/3rd/libuv-1.19.2/docs/code/idle-compute/main.c new file mode 100644 index 00000000..ff44b694 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/idle-compute/main.c @@ -0,0 +1,43 @@ +#include + +#include + +uv_loop_t *loop; +uv_fs_t stdin_watcher; +uv_idle_t idler; +char buffer[1024]; + +void crunch_away(uv_idle_t* handle) { + // Compute extra-terrestrial life + // fold proteins + // computer another digit of PI + // or similar + fprintf(stderr, "Computing PI...\n"); + // just to avoid overwhelming your terminal emulator + uv_idle_stop(handle); +} + +void on_type(uv_fs_t *req) { + if (stdin_watcher.result > 0) { + buffer[stdin_watcher.result] = '\0'; + printf("Typed %s\n", buffer); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + } + else if (stdin_watcher.result < 0) { + fprintf(stderr, "error opening file: %s\n", uv_strerror(req->result)); + } +} + +int main() { + loop = uv_default_loop(); + + uv_idle_init(loop, &idler); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/interfaces/main.c b/3rd/libuv-1.19.2/docs/code/interfaces/main.c new file mode 100644 index 00000000..cac12c26 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/interfaces/main.c @@ -0,0 +1,33 @@ +#include +#include + +int main() { + char buf[512]; + uv_interface_address_t *info; + int count, i; + + uv_interface_addresses(&info, &count); + i = count; + + printf("Number of interfaces: %d\n", count); + while (i--) { + uv_interface_address_t interface = info[i]; + + printf("Name: %s\n", interface.name); + printf("Internal? %s\n", interface.is_internal ? "Yes" : "No"); + + if (interface.address.address4.sin_family == AF_INET) { + uv_ip4_name(&interface.address.address4, buf, sizeof(buf)); + printf("IPv4 address: %s\n", buf); + } + else if (interface.address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interface.address.address6, buf, sizeof(buf)); + printf("IPv6 address: %s\n", buf); + } + + printf("\n"); + } + + uv_free_interface_addresses(info, count); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/locks/main.c b/3rd/libuv-1.19.2/docs/code/locks/main.c new file mode 100644 index 00000000..2b1f8ca7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/locks/main.c @@ -0,0 +1,57 @@ +#include +#include + +uv_barrier_t blocker; +uv_rwlock_t numlock; +int shared_num; + +void reader(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_rdlock(&numlock); + printf("Reader %d: acquired lock\n", num); + printf("Reader %d: shared num = %d\n", num, shared_num); + uv_rwlock_rdunlock(&numlock); + printf("Reader %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +void writer(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_wrlock(&numlock); + printf("Writer %d: acquired lock\n", num); + shared_num++; + printf("Writer %d: incremented shared num = %d\n", num, shared_num); + uv_rwlock_wrunlock(&numlock); + printf("Writer %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +int main() +{ + uv_barrier_init(&blocker, 4); + + shared_num = 0; + uv_rwlock_init(&numlock); + + uv_thread_t threads[3]; + + int thread_nums[] = {1, 2, 1}; + uv_thread_create(&threads[0], reader, &thread_nums[0]); + uv_thread_create(&threads[1], reader, &thread_nums[1]); + + uv_thread_create(&threads[2], writer, &thread_nums[2]); + + uv_barrier_wait(&blocker); + uv_barrier_destroy(&blocker); + + uv_rwlock_destroy(&numlock); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js b/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js new file mode 100644 index 00000000..5df345b7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js @@ -0,0 +1,20 @@ +var net = require('net'); + +var PHRASE = "hello world"; +var write = function(socket) { + socket.write(PHRASE, 'utf8'); +} + +for (var i = 0; i < 1000; i++) { +(function() { + var socket = net.connect(7000, 'localhost', function() { + socket.on('data', function(reply) { + if (reply.toString().indexOf(PHRASE) != 0) + console.error("Problem! '" + reply + "'" + " '" + PHRASE + "'"); + else + write(socket); + }); + write(socket); + }); +})(); +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c new file mode 100644 index 00000000..25f49612 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; + +struct child_worker { + uv_process_t req; + uv_process_options_t options; + uv_pipe_t pipe; +} *workers; + +int round_robin_counter; +int child_worker_count; + +uv_buf_t dummy_buf; +char worker_path[500]; + +void close_process_handle(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_write_t *write_req = (uv_write_t*) malloc(sizeof(uv_write_t)); + dummy_buf = uv_buf_init("a", 1); + struct child_worker *worker = &workers[round_robin_counter]; + uv_write2(write_req, (uv_stream_t*) &worker->pipe, &dummy_buf, 1, (uv_stream_t*) client, NULL); + round_robin_counter = (round_robin_counter + 1) % child_worker_count; + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void setup_workers() { + size_t path_size = 500; + uv_exepath(worker_path, &path_size); + strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker"); + fprintf(stderr, "Worker path: %s\n", worker_path); + + char* args[2]; + args[0] = worker_path; + args[1] = NULL; + + round_robin_counter = 0; + + // ... + + // launch same number of workers as number of CPUs + uv_cpu_info_t *info; + int cpu_count; + uv_cpu_info(&info, &cpu_count); + uv_free_cpu_info(info, cpu_count); + + child_worker_count = cpu_count; + + workers = calloc(sizeof(struct child_worker), cpu_count); + while (cpu_count--) { + struct child_worker *worker = &workers[cpu_count]; + uv_pipe_init(loop, &worker->pipe, 1); + + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + + worker->options.stdio = child_stdio; + worker->options.stdio_count = 3; + + worker->options.exit_cb = close_process_handle; + worker->options.file = args[0]; + worker->options.args = args; + + uv_spawn(loop, &worker->req, &worker->options); + fprintf(stderr, "Started worker %d\n", worker->req.pid); + } +} + +int main() { + loop = uv_default_loop(); + + setup_workers(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r; + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c new file mode 100644 index 00000000..1c465759 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_pipe_t queue; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) q, NULL); + return; + } + + uv_pipe_t *pipe = (uv_pipe_t*) q; + if (!uv_pipe_pending_count(pipe)) { + fprintf(stderr, "No pending count\n"); + return; + } + + uv_handle_type pending = uv_pipe_pending_type(pipe); + assert(pending == UV_TCP); + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(q, (uv_stream_t*) client) == 0) { + uv_os_fd_t fd; + uv_fileno((const uv_handle_t*) client, &fd); + fprintf(stderr, "Worker %d: Accepted fd %d\n", getpid(), fd); + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_init(loop, &queue, 1 /* ipc */); + uv_pipe_open(&queue, 0); + uv_read_start((uv_stream_t*)&queue, alloc_buffer, on_new_connection); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/onchange/main.c b/3rd/libuv-1.19.2/docs/code/onchange/main.c new file mode 100644 index 00000000..40bdaa52 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/onchange/main.c @@ -0,0 +1,44 @@ +#include +#include + +#include + +uv_loop_t *loop; +const char *command; + +void run_command(uv_fs_event_t *handle, const char *filename, int events, int status) { + char path[1024]; + size_t size = 1023; + // Does not handle error if path is longer than 1023. + uv_fs_event_getpath(handle, path, &size); + path[size] = '\0'; + + fprintf(stderr, "Change detected in %s: ", path); + if (events & UV_RENAME) + fprintf(stderr, "renamed"); + if (events & UV_CHANGE) + fprintf(stderr, "changed"); + + fprintf(stderr, " %s\n", filename ? filename : ""); + system(command); +} + +int main(int argc, char **argv) { + if (argc <= 2) { + fprintf(stderr, "Usage: %s [file2 ...]\n", argv[0]); + return 1; + } + + loop = uv_default_loop(); + command = argv[1]; + + while (argc-- > 2) { + fprintf(stderr, "Adding watch on %s\n", argv[argc]); + uv_fs_event_t *fs_event_req = malloc(sizeof(uv_fs_event_t)); + uv_fs_event_init(loop, fs_event_req); + // The recursive flag watches subdirectories too. + uv_fs_event_start(fs_event_req, run_command, argv[argc], UV_FS_EVENT_RECURSIVE); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c new file mode 100644 index 00000000..4f28fd03 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#define PIPENAME "\\\\?\\pipe\\echo.sock" +#else +#define PIPENAME "/tmp/echo.sock" +#endif + +uv_loop_t *loop; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status < 0) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t)); + uv_pipe_init(loop, client, 0); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void remove_sock(int sig) { + uv_fs_t req; + uv_fs_unlink(loop, &req, PIPENAME, NULL); + exit(0); +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_t server; + uv_pipe_init(loop, &server, 0); + + signal(SIGINT, remove_sock); + + int r; + if ((r = uv_pipe_bind(&server, PIPENAME))) { + fprintf(stderr, "Bind error %s\n", uv_err_name(r)); + return 1; + } + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/hello.c b/3rd/libuv-1.19.2/docs/code/plugin/hello.c new file mode 100644 index 00000000..7b2861d7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/hello.c @@ -0,0 +1,5 @@ +#include "plugin.h" + +void initialize() { + mfp_register("Hello World!"); +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/main.c b/3rd/libuv-1.19.2/docs/code/plugin/main.c new file mode 100644 index 00000000..06e581e6 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/main.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include + +#include "plugin.h" + +typedef void (*init_plugin_function)(); + +void mfp_register(const char *name) { + fprintf(stderr, "Registered plugin \"%s\"\n", name); +} + +int main(int argc, char **argv) { + if (argc == 1) { + fprintf(stderr, "Usage: %s [plugin1] [plugin2] ...\n", argv[0]); + return 0; + } + + uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t)); + while (--argc) { + fprintf(stderr, "Loading %s\n", argv[argc]); + if (uv_dlopen(argv[argc], lib)) { + fprintf(stderr, "Error: %s\n", uv_dlerror(lib)); + continue; + } + + init_plugin_function init_plugin; + if (uv_dlsym(lib, "initialize", (void **) &init_plugin)) { + fprintf(stderr, "dlsym error: %s\n", uv_dlerror(lib)); + continue; + } + + init_plugin(); + } + + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/plugin.h b/3rd/libuv-1.19.2/docs/code/plugin/plugin.h new file mode 100644 index 00000000..21f194e6 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/plugin.h @@ -0,0 +1,7 @@ +#ifndef UVBOOK_PLUGIN_SYSTEM +#define UVBOOK_PLUGIN_SYSTEM + +// Plugin authors should use this to register their plugins with mfp. +void mfp_register(const char *name); + +#endif diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/main.c b/3rd/libuv-1.19.2/docs/code/proc-streams/main.c new file mode 100644 index 00000000..b8a65212 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/proc-streams/main.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("proc-streams")), "test"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + options.stdio = child_stdio; + + options.exit_cb = on_exit; + options.file = args[0]; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/test.c b/3rd/libuv-1.19.2/docs/code/proc-streams/test.c new file mode 100644 index 00000000..7c45c1fd --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/proc-streams/test.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + fprintf(stderr, "This is stderr\n"); + printf("This is stdout\n"); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/progress/main.c b/3rd/libuv-1.19.2/docs/code/progress/main.c new file mode 100644 index 00000000..5af01f14 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/progress/main.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_async_t async; + +double percentage; + +void fake_download(uv_work_t *req) { + int size = *((int*) req->data); + int downloaded = 0; + while (downloaded < size) { + percentage = downloaded*100.0/size; + async.data = (void*) &percentage; + uv_async_send(&async); + + sleep(1); + downloaded += (200+random())%1000; // can only download max 1000bytes/sec, + // but at least a 200; + } +} + +void after(uv_work_t *req, int status) { + fprintf(stderr, "Download complete\n"); + uv_close((uv_handle_t*) &async, NULL); +} + +void print_progress(uv_async_t *handle) { + double percentage = *((double*) handle->data); + fprintf(stderr, "Downloaded %.2f%%\n", percentage); +} + +int main() { + loop = uv_default_loop(); + + uv_work_t req; + int size = 10240; + req.data = (void*) &size; + + uv_async_init(loop, &async, print_progress); + uv_queue_work(loop, &req, fake_download, after); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c b/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c new file mode 100644 index 00000000..3f7836cb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; +uv_work_t fib_reqs[FIB_UNTIL]; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + if (status == UV_ECANCELED) + fprintf(stderr, "Calculation of %d cancelled.\n", *(int *) req->data); +} + +void signal_handler(uv_signal_t *req, int signum) +{ + printf("Signal received!\n"); + int i; + for (i = 0; i < FIB_UNTIL; i++) { + uv_cancel((uv_req_t*) &fib_reqs[i]); + } + uv_signal_stop(req); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + fib_reqs[i].data = (void *) &data[i]; + uv_queue_work(loop, &fib_reqs[i], fib, after_fib); + } + + uv_signal_t sig; + uv_signal_init(loop, &sig); + uv_signal_start(&sig, signal_handler, SIGINT); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/queue-work/main.c b/3rd/libuv-1.19.2/docs/code/queue-work/main.c new file mode 100644 index 00000000..55675ea0 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/queue-work/main.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + fprintf(stderr, "Done calculating %dth fibonacci\n", *(int *) req->data); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + uv_work_t req[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + req[i].data = (void *) &data[i]; + uv_queue_work(loop, &req[i], fib, after_fib); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/ref-timer/main.c b/3rd/libuv-1.19.2/docs/code/ref-timer/main.c new file mode 100644 index 00000000..ad7c8295 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/ref-timer/main.c @@ -0,0 +1,29 @@ +#include + +#include + +uv_loop_t *loop; +uv_timer_t gc_req; +uv_timer_t fake_job_req; + +void gc(uv_timer_t *handle) { + fprintf(stderr, "Freeing unused objects\n"); +} + +void fake_job(uv_timer_t *handle) { + fprintf(stdout, "Fake job done\n"); +} + +int main() { + loop = uv_default_loop(); + + uv_timer_init(loop, &gc_req); + uv_unref((uv_handle_t*) &gc_req); + + uv_timer_start(&gc_req, gc, 0, 2000); + + // could actually be a TCP download or something + uv_timer_init(loop, &fake_job_req); + uv_timer_start(&fake_job_req, fake_job, 9000, 0); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/signal/main.c b/3rd/libuv-1.19.2/docs/code/signal/main.c new file mode 100644 index 00000000..1b982c5a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/signal/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +uv_loop_t* create_loop() +{ + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + if (loop) { + uv_loop_init(loop); + } + return loop; +} + +void signal_handler(uv_signal_t *handle, int signum) +{ + printf("Signal received: %d\n", signum); + uv_signal_stop(handle); +} + +// two signal handlers in one loop +void thread1_worker(void *userp) +{ + uv_loop_t *loop1 = create_loop(); + + uv_signal_t sig1a, sig1b; + uv_signal_init(loop1, &sig1a); + uv_signal_start(&sig1a, signal_handler, SIGUSR1); + + uv_signal_init(loop1, &sig1b); + uv_signal_start(&sig1b, signal_handler, SIGUSR1); + + uv_run(loop1, UV_RUN_DEFAULT); +} + +// two signal handlers, each in its own loop +void thread2_worker(void *userp) +{ + uv_loop_t *loop2 = create_loop(); + uv_loop_t *loop3 = create_loop(); + + uv_signal_t sig2; + uv_signal_init(loop2, &sig2); + uv_signal_start(&sig2, signal_handler, SIGUSR1); + + uv_signal_t sig3; + uv_signal_init(loop3, &sig3); + uv_signal_start(&sig3, signal_handler, SIGUSR1); + + while (uv_run(loop2, UV_RUN_NOWAIT) || uv_run(loop3, UV_RUN_NOWAIT)) { + } +} + +int main() +{ + printf("PID %d\n", getpid()); + + uv_thread_t thread1, thread2; + + uv_thread_create(&thread1, thread1_worker, 0); + uv_thread_create(&thread2, thread2_worker, 0); + + uv_thread_join(&thread1); + uv_thread_join(&thread2); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/spawn/main.c b/3rd/libuv-1.19.2/docs/code/spawn/main.c new file mode 100644 index 00000000..dedfe00c --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/spawn/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "mkdir"; + args[1] = "test-dir"; + args[2] = NULL; + + options.exit_cb = on_exit; + options.file = "mkdir"; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } else { + fprintf(stderr, "Launched process with ID %d\n", child_req.pid); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c new file mode 100644 index 00000000..5d7b4993 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#define DEFAULT_PORT 7000 +#define DEFAULT_BACKLOG 128 + +uv_loop_t *loop; +struct sockaddr_in addr; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = (char*) malloc(suggested_size); + buf->len = suggested_size; +} + +void on_close(uv_handle_t* handle) { + free(handle); +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_strerror(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, on_close); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status < 0) { + fprintf(stderr, "New connection error %s\n", uv_strerror(status)); + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, on_close); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr); + + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_strerror(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/thread-create/main.c b/3rd/libuv-1.19.2/docs/code/thread-create/main.c new file mode 100644 index 00000000..70224c1e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/thread-create/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +void hare(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + sleep(1); + fprintf(stderr, "Hare ran another step\n"); + } + fprintf(stderr, "Hare done running!\n"); +} + +void tortoise(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + fprintf(stderr, "Tortoise ran another step\n"); + sleep(3); + } + fprintf(stderr, "Tortoise done running!\n"); +} + +int main() { + int tracklen = 10; + uv_thread_t hare_id; + uv_thread_t tortoise_id; + uv_thread_create(&hare_id, hare, &tracklen); + uv_thread_create(&tortoise_id, tortoise, &tracklen); + + uv_thread_join(&hare_id); + uv_thread_join(&tortoise_id); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c b/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c new file mode 100644 index 00000000..053e7e59 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +uv_timer_t tick; +uv_write_t write_req; +int width, height; +int pos = 0; +char *message = " Hello TTY "; + +void update(uv_timer_t *req) { + char data[500]; + + uv_buf_t buf; + buf.base = data; + buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%luC\033[42;37m%s", + pos, + (unsigned long) (width-strlen(message))/2, + message); + uv_write(&write_req, (uv_stream_t*) &tty, &buf, 1, NULL); + + pos++; + if (pos > height) { + uv_tty_reset_mode(); + uv_timer_stop(&tick); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 0); + uv_tty_set_mode(&tty, 0); + + if (uv_tty_get_winsize(&tty, &width, &height)) { + fprintf(stderr, "Could not get TTY information\n"); + uv_tty_reset_mode(); + return 1; + } + + fprintf(stderr, "Width %d, height %d\n", width, height); + uv_timer_init(loop, &tick); + uv_timer_start(&tick, update, 200, 200); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/tty/main.c b/3rd/libuv-1.19.2/docs/code/tty/main.c new file mode 100644 index 00000000..03b26fbc --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tty/main.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 0); + uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL); + + if (uv_guess_handle(1) == UV_TTY) { + uv_write_t req; + uv_buf_t buf; + buf.base = "\033[41;37m"; + buf.len = strlen(buf.base); + uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + } + + uv_write_t req; + uv_buf_t buf; + buf.base = "Hello TTY\n"; + buf.len = strlen(buf.base); + uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + uv_tty_reset_mode(); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c b/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c new file mode 100644 index 00000000..fc2ca0c8 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_udp_t send_socket; +uv_udp_t recv_socket; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { + if (nread < 0) { + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) req, NULL); + free(buf->base); + return; + } + + char sender[17] = { 0 }; + uv_ip4_name((const struct sockaddr_in*) addr, sender, 16); + fprintf(stderr, "Recv from %s\n", sender); + + // ... DHCP specific code + unsigned int *as_integer = (unsigned int*)buf->base; + unsigned int ipbin = ntohl(as_integer[4]); + unsigned char ip[4] = {0}; + int i; + for (i = 0; i < 4; i++) + ip[i] = (ipbin >> i*8) & 0xff; + fprintf(stderr, "Offered IP %d.%d.%d.%d\n", ip[3], ip[2], ip[1], ip[0]); + + free(buf->base); + uv_udp_recv_stop(req); +} + +uv_buf_t make_discover_msg() { + uv_buf_t buffer; + alloc_buffer(NULL, 256, &buffer); + memset(buffer.base, 0, buffer.len); + + // BOOTREQUEST + buffer.base[0] = 0x1; + // HTYPE ethernet + buffer.base[1] = 0x1; + // HLEN + buffer.base[2] = 0x6; + // HOPS + buffer.base[3] = 0x0; + // XID 4 bytes + buffer.base[4] = (unsigned int) random(); + // SECS + buffer.base[8] = 0x0; + // FLAGS + buffer.base[10] = 0x80; + // CIADDR 12-15 is all zeros + // YIADDR 16-19 is all zeros + // SIADDR 20-23 is all zeros + // GIADDR 24-27 is all zeros + // CHADDR 28-43 is the MAC address, use your own + buffer.base[28] = 0xe4; + buffer.base[29] = 0xce; + buffer.base[30] = 0x8f; + buffer.base[31] = 0x13; + buffer.base[32] = 0xf6; + buffer.base[33] = 0xd4; + // SNAME 64 bytes zero + // FILE 128 bytes zero + // OPTIONS + // - magic cookie + buffer.base[236] = 99; + buffer.base[237] = 130; + buffer.base[238] = 83; + buffer.base[239] = 99; + + // DHCP Message type + buffer.base[240] = 53; + buffer.base[241] = 1; + buffer.base[242] = 1; // DHCPDISCOVER + + // DHCP Parameter request list + buffer.base[243] = 55; + buffer.base[244] = 4; + buffer.base[245] = 1; + buffer.base[246] = 3; + buffer.base[247] = 15; + buffer.base[248] = 6; + + return buffer; +} + +void on_send(uv_udp_send_t *req, int status) { + if (status) { + fprintf(stderr, "Send error %s\n", uv_strerror(status)); + return; + } +} + +int main() { + loop = uv_default_loop(); + + uv_udp_init(loop, &recv_socket); + struct sockaddr_in recv_addr; + uv_ip4_addr("0.0.0.0", 68, &recv_addr); + uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); + uv_udp_recv_start(&recv_socket, alloc_buffer, on_read); + + uv_udp_init(loop, &send_socket); + struct sockaddr_in broadcast_addr; + uv_ip4_addr("0.0.0.0", 0, &broadcast_addr); + uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0); + uv_udp_set_broadcast(&send_socket, 1); + + uv_udp_send_t send_req; + uv_buf_t discover_msg = make_discover_msg(); + + struct sockaddr_in send_addr; + uv_ip4_addr("255.255.255.255", 67, &send_addr); + uv_udp_send(&send_req, &send_socket, &discover_msg, 1, (const struct sockaddr *)&send_addr, on_send); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/uvcat/main.c b/3rd/libuv-1.19.2/docs/code/uvcat/main.c new file mode 100644 index 00000000..b03b0944 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvcat/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +void on_read(uv_fs_t *req); + +uv_fs_t open_req; +uv_fs_t read_req; +uv_fs_t write_req; + +static char buffer[1024]; + +static uv_buf_t iov; + +void on_write(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Write error: %s\n", uv_strerror((int)req->result)); + } + else { + uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1, on_read); + } +} + +void on_read(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Read error: %s\n", uv_strerror(req->result)); + } + else if (req->result == 0) { + uv_fs_t close_req; + // synchronous + uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); + } + else if (req->result > 0) { + iov.len = req->result; + uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write); + } +} + +void on_open(uv_fs_t *req) { + // The request passed to the callback is the same as the one the call setup + // function was passed. + assert(req == &open_req); + if (req->result >= 0) { + iov = uv_buf_init(buffer, sizeof(buffer)); + uv_fs_read(uv_default_loop(), &read_req, req->result, + &iov, 1, -1, on_read); + } + else { + fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result)); + } +} + +int main(int argc, char **argv) { + uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_fs_req_cleanup(&open_req); + uv_fs_req_cleanup(&read_req); + uv_fs_req_cleanup(&write_req); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvstop/main.c b/3rd/libuv-1.19.2/docs/code/uvstop/main.c new file mode 100644 index 00000000..7aa53b76 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvstop/main.c @@ -0,0 +1,33 @@ +#include +#include + +int64_t counter = 0; + +void idle_cb(uv_idle_t *handle) { + printf("Idle callback\n"); + counter++; + + if (counter >= 5) { + uv_stop(uv_default_loop()); + printf("uv_stop() called\n"); + } +} + +void prep_cb(uv_prepare_t *handle) { + printf("Prep callback\n"); +} + +int main() { + uv_idle_t idler; + uv_prepare_t prep; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, idle_cb); + + uv_prepare_init(uv_default_loop(), &prep); + uv_prepare_start(&prep, prep_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvtee/main.c b/3rd/libuv-1.19.2/docs/code/uvtee/main.c new file mode 100644 index 00000000..6216c2eb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvtee/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +#include + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +uv_loop_t *loop; +uv_pipe_t stdin_pipe; +uv_pipe_t stdout_pipe; +uv_pipe_t file_pipe; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + *buf = uv_buf_init((char*) malloc(suggested_size), suggested_size); +} + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void on_stdout_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void on_file_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void write_data(uv_stream_t *dest, size_t size, uv_buf_t buf, uv_write_cb cb) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init((char*) malloc(size), size); + memcpy(req->buf.base, buf.base, size); + uv_write((uv_write_t*) req, (uv_stream_t*)dest, &req->buf, 1, cb); +} + +void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0){ + if (nread == UV_EOF){ + // end of file + uv_close((uv_handle_t *)&stdin_pipe, NULL); + uv_close((uv_handle_t *)&stdout_pipe, NULL); + uv_close((uv_handle_t *)&file_pipe, NULL); + } + } else if (nread > 0) { + write_data((uv_stream_t *)&stdout_pipe, nread, *buf, on_stdout_write); + write_data((uv_stream_t *)&file_pipe, nread, *buf, on_file_write); + } + + // OK to free buffer as write_data copies it. + if (buf->base) + free(buf->base); +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + uv_pipe_init(loop, &stdin_pipe, 0); + uv_pipe_open(&stdin_pipe, 0); + + uv_pipe_init(loop, &stdout_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + uv_fs_t file_req; + int fd = uv_fs_open(loop, &file_req, argv[1], O_CREAT | O_RDWR, 0644, NULL); + uv_pipe_init(loop, &file_pipe, 0); + uv_pipe_open(&file_pipe, fd); + + uv_read_start((uv_stream_t*)&stdin_pipe, alloc_buffer, read_stdin); + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvwget/main.c b/3rd/libuv-1.19.2/docs/code/uvwget/main.c new file mode 100644 index 00000000..40186241 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvwget/main.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +CURLM *curl_handle; +uv_timer_t timeout; + +typedef struct curl_context_s { + uv_poll_t poll_handle; + curl_socket_t sockfd; +} curl_context_t; + +curl_context_t *create_curl_context(curl_socket_t sockfd) { + curl_context_t *context; + + context = (curl_context_t*) malloc(sizeof *context); + + context->sockfd = sockfd; + + int r = uv_poll_init_socket(loop, &context->poll_handle, sockfd); + assert(r == 0); + context->poll_handle.data = context; + + return context; +} + +void curl_close_cb(uv_handle_t *handle) { + curl_context_t *context = (curl_context_t*) handle->data; + free(context); +} + +void destroy_curl_context(curl_context_t *context) { + uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb); +} + + +void add_download(const char *url, int num) { + char filename[50]; + sprintf(filename, "%d.download", num); + FILE *file; + + file = fopen(filename, "w"); + if (file == NULL) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + CURL *handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +void check_multi_info(void) { + char *done_url; + CURLMsg *message; + int pending; + + while ((message = curl_multi_info_read(curl_handle, &pending))) { + switch (message->msg) { + case CURLMSG_DONE: + curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, + &done_url); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, message->easy_handle); + curl_easy_cleanup(message->easy_handle); + break; + + default: + fprintf(stderr, "CURLMSG default\n"); + abort(); + } + } +} + +void curl_perform(uv_poll_t *req, int status, int events) { + uv_timer_stop(&timeout); + int running_handles; + int flags = 0; + if (status < 0) flags = CURL_CSELECT_ERR; + if (!status && events & UV_READABLE) flags |= CURL_CSELECT_IN; + if (!status && events & UV_WRITABLE) flags |= CURL_CSELECT_OUT; + + curl_context_t *context; + + context = (curl_context_t*)req; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, &running_handles); + check_multi_info(); +} + +void on_timeout(uv_timer_t *req) { + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, &running_handles); + check_multi_info(); +} + +void start_timeout(CURLM *multi, long timeout_ms, void *userp) { + if (timeout_ms <= 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */ + uv_timer_start(&timeout, on_timeout, timeout_ms, 0); +} + +int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, void *socketp) { + curl_context_t *curl_context; + if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { + if (socketp) { + curl_context = (curl_context_t*) socketp; + } + else { + curl_context = create_curl_context(s); + curl_multi_assign(curl_handle, s, (void *) curl_context); + } + } + + switch (action) { + case CURL_POLL_IN: + uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform); + break; + case CURL_POLL_OUT: + uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform); + break; + case CURL_POLL_REMOVE: + if (socketp) { + uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + if (argc <= 1) + return 0; + + if (curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init cURL\n"); + return 1; + } + + uv_timer_init(loop, &timeout); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while (argc-- > 1) { + add_download(argv[argc], argc); + } + + uv_run(loop, UV_RUN_DEFAULT); + curl_multi_cleanup(curl_handle); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/make.bat b/3rd/libuv-1.19.2/docs/make.bat new file mode 100644 index 00000000..10eb94b0 --- /dev/null +++ b/3rd/libuv-1.19.2/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 ^` where ^ 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/3rd/libuv-1.19.2/docs/src/api.rst b/3rd/libuv-1.19.2/docs/src/api.rst new file mode 100644 index 00000000..22f0640f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/api.rst @@ -0,0 +1,35 @@ +.. _api: + +API documentation +================= + +.. toctree:: + :maxdepth: 1 + + 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/3rd/libuv-1.19.2/docs/src/async.rst b/3rd/libuv-1.19.2/docs/src/async.rst new file mode 100644 index 00000000..02e6a58e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/async.rst @@ -0,0 +1,61 @@ + +.. _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. + + :returns: 0 on success, or an error code < 0 on failure. + + .. note:: + Unlike other handle initialization functions, it immediately starts the handle. + +.. c:function:: int uv_async_send(uv_async_t* async) + + Wake up the event loop and call the async handle's callback. + + :returns: 0 on success, or an error code < 0 on failure. + + .. 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/3rd/libuv-1.19.2/docs/src/check.rst b/3rd/libuv-1.19.2/docs/src/check.rst new file mode 100644 index 00000000..36c93cf0 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/conf.py b/3rd/libuv-1.19.2/docs/src/conf.py new file mode 100644 index 00000000..c9b4ea38 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/conf.py @@ -0,0 +1,348 @@ +# -*- coding: utf-8 -*- +# +# libuv 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'2014-present, 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 +# " v documentation". +html_title = 'libuv documentation' + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = 'libuv %s 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 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 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 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 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 documentation' +epub_author = u'libuv contributors' +epub_publisher = u'libuv contributors' +epub_copyright = u'2014-present, 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/3rd/libuv-1.19.2/docs/src/design.rst b/3rd/libuv-1.19.2/docs/src/design.rst new file mode 100644 index 00000000..487d08ba --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/design.rst @@ -0,0 +1,138 @@ + +.. _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 a simple 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. +- A TCP server handle that gets 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 matches, 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 duration calculated + in 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 ends 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 `_. + +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: + + * File system 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/3rd/libuv-1.19.2/docs/src/dll.rst b/3rd/libuv-1.19.2/docs/src/dll.rst new file mode 100644 index 00000000..fb13f908 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/dns.rst b/3rd/libuv-1.19.2/docs/src/dns.rst new file mode 100644 index 00000000..1d881580 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/errors.rst b/3rd/libuv-1.19.2/docs/src/errors.rst new file mode 100644 index 00000000..4e30447b --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/errors.rst @@ -0,0 +1,344 @@ + +.. _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. + +When a function which takes a callback returns an error, the callback will never +be called. + +.. 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. + +.. c:function:: int uv_translate_sys_error(int sys_errno) + + Returns the libuv error code equivalent to the given platform dependent error + code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error + codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`). + + If `sys_errno` is already a libuv error, it is simply returned. + + .. versionchanged:: 1.10.0 function declared public. diff --git a/3rd/libuv-1.19.2/docs/src/fs.rst b/3rd/libuv-1.19.2/docs/src/fs.rst new file mode 100644 index 00000000..87af828a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs.rst @@ -0,0 +1,538 @@ + +.. _fs: + +File system operations +====================== + +libuv provides a wide variety of cross-platform sync and async file system +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 + + File system 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 + + File system 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_REALPATH, + UV_FS_COPYFILE + } 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 file systems (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:`lstat(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_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) + + Copies a file from `path` to `new_path`. Supported `flags` are described below. + + - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with + `UV_EEXIST` if the destination path already exists. The default behavior + is to overwrite the destination if it exists. + + .. warning:: + If the destination path is created, but an error occurs while copying + the data, then the destination path is removed. There is a brief window + of time between closing and removing the file where another process + could access the file. + + .. versionadded:: 1.14.0 + +.. 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. + + .. note:: + AIX: This function only works for AIX 7.1 and newer. It can still be called on older + versions but will return ``UV_ENOSYS``. + + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows + +.. 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 `_. + + .. warning:: + This function has certain platform-specific caveats that were discovered when used in Node. + + * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are + found while resolving the given path. This limit is hardcoded and cannot be sidestepped. + * Windows: while this function works in the common case, there are a number of corner cases + where it doesn't: + + - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) + cannot be resolved. + - Inconsistent casing when using drive letters. + - Resolved path bypasses subst'd drives. + + While this function can still be used, it's not recommended if scenarios such as the + above need to be supported. + + The background story and some more details on these issues can be checked + `here `_. + + .. 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. + +.. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) + + Returns `req->fs_type`. + + .. versionadded:: 1.19.0 + +.. c:function:: ssize_t uv_fs_get_result(const uv_fs_t* req) + + Returns `req->result`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) + + Returns `req->ptr`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_fs_get_path(const uv_fs_t* req) + + Returns `req->path`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) + + Returns `&req->statbuf`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. + +Helper functions +---------------- + +.. c:function:: uv_os_fd_t uv_get_osfhandle(int fd) + + For a file descriptor in the C runtime, get the OS-dependent handle. + On UNIX, returns the ``fd`` intact. On Windows, this calls `_get_osfhandle `_. + Note that the return value is still owned by the C runtime, + any attempts to close it or to use it after closing the fd may lead to malfunction. + + .. versionadded:: 1.12.0 + +File open constants +------------------- + +.. c:macro:: UV_FS_O_APPEND + + The file is opened in append mode. Before each write, the file offset is + positioned at the end of the file. + +.. c:macro:: UV_FS_O_CREAT + + The file is created if it does not already exist. + +.. c:macro:: UV_FS_O_DIRECT + + File I/O is done directly to and from user-space buffers, which must be + aligned. Buffer size and address should be a multiple of the physical sector + size of the block device. + + .. note:: + `UV_FS_O_DIRECT` is supported on Linux, and on Windows via + `FILE_FLAG_NO_BUFFERING `_. + `UV_FS_O_DIRECT` is not supported on macOS. + +.. c:macro:: UV_FS_O_DIRECTORY + + If the path is not a directory, fail the open. + + .. note:: + `UV_FS_O_DIRECTORY` is not supported on Windows. + +.. c:macro:: UV_FS_O_DSYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and a minimum of metadata are flushed to disk. + + .. note:: + `UV_FS_O_DSYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_EXCL + + If the `O_CREAT` flag is set and the file already exists, fail the open. + + .. note:: + In general, the behavior of `O_EXCL` is undefined if it is used without + `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can + be used without `O_CREAT` if pathname refers to a block device. If the + block device is in use by the system (e.g., mounted), the open will fail + with the error `EBUSY`. + +.. c:macro:: UV_FS_O_EXLOCK + + Atomically obtain an exclusive lock. + + .. note:: + `UV_FS_O_EXLOCK` is only supported on macOS and Windows. + + .. versionchanged:: 1.17.0 support is added for Windows. + +.. c:macro:: UV_FS_O_NOATIME + + Do not update the file access time when the file is read. + + .. note:: + `UV_FS_O_NOATIME` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOCTTY + + If the path identifies a terminal device, opening the path will not cause + that terminal to become the controlling terminal for the process (if the + process does not already have one). + + .. note:: + `UV_FS_O_NOCTTY` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOFOLLOW + + If the path is a symbolic link, fail the open. + + .. note:: + `UV_FS_O_NOFOLLOW` is not supported on Windows. + +.. c:macro:: UV_FS_O_NONBLOCK + + Open the file in nonblocking mode if possible. + + .. note:: + `UV_FS_O_NONBLOCK` is not supported on Windows. + +.. c:macro:: UV_FS_O_RANDOM + + Access is intended to be random. The system can use this as a hint to + optimize file caching. + + .. note:: + `UV_FS_O_RANDOM` is only supported on Windows via + `FILE_FLAG_RANDOM_ACCESS `_. + +.. c:macro:: UV_FS_O_RDONLY + + Open the file for read-only access. + +.. c:macro:: UV_FS_O_RDWR + + Open the file for read-write access. + +.. c:macro:: UV_FS_O_SEQUENTIAL + + Access is intended to be sequential from beginning to end. The system can + use this as a hint to optimize file caching. + + .. note:: + `UV_FS_O_SEQUENTIAL` is only supported on Windows via + `FILE_FLAG_SEQUENTIAL_SCAN `_. + +.. c:macro:: UV_FS_O_SHORT_LIVED + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_SHORT_LIVED` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_SYMLINK + + Open the symbolic link itself rather than the resource it points to. + +.. c:macro:: UV_FS_O_SYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and all metadata are flushed to disk. + + .. note:: + `UV_FS_O_SYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_TEMPORARY + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_TEMPORARY` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_TRUNC + + If the file exists and is a regular file, and the file is opened + successfully for write access, its length shall be truncated to zero. + +.. c:macro:: UV_FS_O_WRONLY + + Open the file for write-only access. diff --git a/3rd/libuv-1.19.2/docs/src/fs_event.rst b/3rd/libuv-1.19.2/docs/src/fs_event.rst new file mode 100644 index 00000000..bd076aae --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs_event.rst @@ -0,0 +1,132 @@ + +.. _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. + +.. note:: + For AIX, the non default IBM bos.ahafs package has to be installed. + The AIX Event Infrastructure file system (ahafs) has some limitations: + + - ahafs tracks monitoring per process and is not thread safe. A separate process + must be spawned for each monitor for the same event. + - Events for file modification (writing to a file) are not received if only the + containing folder is watched. + + See documentation_ for more details. + + The z/OS file system events monitoring infrastructure does not notify of file + creation/deletion within a directory that is being monitored. + See the `IBM Knowledge centre`_ for more details. + + .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ + .. _`IBM Knowledge centre`: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.2.0/com.ibm.zos.v2r1.bpxb100/ioc.htm + + + + +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 file systems 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 its 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 `size` will be set to + the required size, including the null terminator. + + .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte, + and the buffer is not null terminated. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/fs_poll.rst b/3rd/libuv-1.19.2/docs/src/fs_poll.rst new file mode 100644 index 00000000..2912bad9 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs_poll.rst @@ -0,0 +1,77 @@ + +.. _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 `size` 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. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/guide.rst b/3rd/libuv-1.19.2/docs/src/guide.rst new file mode 100644 index 00000000..126e0808 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide.rst @@ -0,0 +1,22 @@ +.. _guide: + +User guide +========== + +.. warning:: + The contents of this guide have been recently incorporated into the libuv documentation + and it hasn't gone through thorough review yet. If you spot a mistake please file an + issue, or better yet, open a pull request! + +.. toctree:: + :maxdepth: 2 + + guide/introduction + guide/basics + guide/filesystem + guide/networking + guide/threads + guide/processes + guide/eventloops + guide/utilities + guide/about diff --git a/3rd/libuv-1.19.2/docs/src/guide/about.rst b/3rd/libuv-1.19.2/docs/src/guide/about.rst new file mode 100644 index 00000000..2de658d5 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/about.rst @@ -0,0 +1,22 @@ +About +===== + +`Nikhil Marathe `_ started writing this book one +afternoon (June 16, 2012) when he didn't feel like programming. He had recently +been stung by the lack of good documentation on libuv while working on +`node-taglib `_. Although reference +documentation was present, there were no comprehensive tutorials. This book is +the output of that need and tries to be accurate. That said, the book may have +mistakes. Pull requests are encouraged. + +Nikhil is indebted to Marc Lehmann's comprehensive `man page +`_ about libev which +describes much of the semantics of the two libraries. + +This book was made using `Sphinx `_ and `vim +`_. + +.. note:: + In 2017 the libuv project incorporated the Nikhil's work into the official + documentation and it's maintained there henceforth. + diff --git a/3rd/libuv-1.19.2/docs/src/guide/basics.rst b/3rd/libuv-1.19.2/docs/src/guide/basics.rst new file mode 100644 index 00000000..91fa6a6d --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/basics.rst @@ -0,0 +1,188 @@ +Basics of libuv +=============== + +libuv enforces an **asynchronous**, **event-driven** style of programming. Its +core job is to provide an event loop and callback based notifications of I/O +and other activities. libuv offers core utilities like timers, non-blocking +networking support, asynchronous file system access, child processes and more. + +Event loops +----------- + +In event-driven programming, an application expresses interest in certain events +and respond to them when they occur. The responsibility of gathering events +from the operating system or monitoring other sources of events is handled by +libuv, and the user can register callbacks to be invoked when an event occurs. +The event-loop usually keeps running *forever*. In pseudocode: + +.. code-block:: python + + while there are still events to process: + e = get the next event + if there is a callback associated with e: + call the callback + +Some examples of events are: + +* File is ready for writing +* A socket has data ready to be read +* A timer has timed out + +This event loop is encapsulated by ``uv_run()`` -- the end-all function when using +libuv. + +The most common activity of systems programs is to deal with input and output, +rather than a lot of number-crunching. The problem with using conventional +input/output functions (``read``, ``fprintf``, etc.) is that they are +**blocking**. The actual write to a hard disk or reading from a network, takes +a disproportionately long time compared to the speed of the processor. The +functions don't return until the task is done, so that your program is doing +nothing. For programs which require high performance this is a major roadblock +as other activities and other I/O operations are kept waiting. + +One of the standard solutions is to use threads. Each blocking I/O operation is +started in a separate thread (or in a thread pool). When the blocking function +gets invoked in the thread, the processor can schedule another thread to run, +which actually needs the CPU. + +The approach followed by libuv uses another style, which is the **asynchronous, +non-blocking** style. Most modern operating systems provide event notification +subsystems. For example, a normal ``read`` call on a socket would block until +the sender actually sent something. Instead, the application can request the +operating system to watch the socket and put an event notification in the +queue. The application can inspect the events at its convenience (perhaps doing +some number crunching before to use the processor to the maximum) and grab the +data. It is **asynchronous** because the application expressed interest at one +point, then used the data at another point (in time and space). It is +**non-blocking** because the application process was free to do other tasks. +This fits in well with libuv's event-loop approach, since the operating system +events can be treated as just another libuv event. The non-blocking ensures +that other events can continue to be handled as fast as they come in [#]_. + +.. NOTE:: + + How the I/O is run in the background is not of our concern, but due to the + way our computer hardware works, with the thread as the basic unit of the + processor, libuv and OSes will usually run background/worker threads and/or + polling to perform tasks in a non-blocking manner. + +Bert Belder, one of the libuv core developers has a small video explaining the +architecture of libuv and its background. If you have no prior experience with +either libuv or libev, it is a quick, useful watch. + +libuv's event loop is explained in more detail in the `documentation +`_. + +.. raw:: html + + + +Hello World +----------- + +With the basics out of the way, lets write our first libuv program. It does +nothing, except start a loop which will exit immediately. + +.. rubric:: helloworld/main.c +.. literalinclude:: ../../code/helloworld/main.c + :linenos: + +This program quits immediately because it has no events to process. A libuv +event loop has to be told to watch out for events using the various API +functions. + +Starting with libuv v1.0, users should allocate the memory for the loops before +initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in +custom memory management. Remember to de-initialize the loop using +``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never +close loops since the program quits after the loop ends and the system will +reclaim memory. Production grade projects, especially long running systems +programs, should take care to release correctly. + +Default loop +++++++++++++ + +A default loop is provided by libuv and can be accessed using +``uv_default_loop()``. You should use this loop if you only want a single +loop. + +.. note:: + + node.js uses the default loop as its main loop. If you are writing bindings + you should be aware of this. + +.. _libuv-error-handling: + +Error handling +-------------- + +Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. + +.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants + +You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions +to get a ``const char *`` describing the error or the error name respectively. + +I/O read callbacks (such as for files and sockets) are passed a parameter ``nread``. If ``nread`` is less than 0, there was an error (UV_EOF is the end of file error, which you may want to handle differently). + +Handles and Requests +-------------------- + +libuv works by the user expressing interest in particular events. This is +usually done by creating a **handle** to an I/O device, timer or process. +Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the +handle is used for. + +.. rubric:: libuv watchers +.. literalinclude:: ../../../include/uv.h + :lines: 197-230 + +Handles represent long-lived objects. Async operations on such handles are +identified using **requests**. A request is short-lived (usually used across +only one callback) and usually indicates one I/O operation on a handle. +Requests are used to preserve context between the initiation and the callback +of individual actions. For example, an UDP socket is represented by +a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t`` +structure that is passed to the callback after the write is done. + +Handles are setup by a corresponding:: + + uv_TYPE_init(uv_loop_t *, uv_TYPE_t *) + +function. + +Callbacks are functions which are called by libuv whenever an event the watcher +is interested in has taken place. Application specific logic will usually be +implemented in the callback. For example, an IO watcher's callback will receive +the data read from a file, a timer callback will be triggered on timeout and so +on. + +Idling +++++++ + +Here is an example of using an idle handle. The callback is called once on +every turn of the event loop. A use case for idle handles is discussed in +:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle +and see how ``uv_run()`` will now block because a watcher is present. The idle +watcher is stopped when the count is reached and ``uv_run()`` exits since no +event watchers are active. + +.. rubric:: idle-basic/main.c +.. literalinclude:: ../../code/idle-basic/main.c + :emphasize-lines: 6,10,14-17 + +Storing context ++++++++++++++++ + +In callback based programming style you'll often want to pass some 'context' -- +application specific information -- between the call site and the callback. All +handles and requests have a ``void* data`` member which you can set to the +context and cast back in the callback. This is a common pattern used throughout +the C library ecosystem. In addition ``uv_loop_t`` also has a similar data +member. + +---- + +.. [#] Depending on the capacity of the hardware of course. diff --git a/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst b/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst new file mode 100644 index 00000000..fd9df5fb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst @@ -0,0 +1,48 @@ +Advanced event loops +==================== + +libuv provides considerable user control over event loops, and you can achieve +interesting results by juggling multiple loops. You can also embed libuv's +event loop into another event loop based library -- imagine a Qt based UI, and +Qt's event loop driving a libuv backend which does intensive system level +tasks. + +Stopping an event loop +~~~~~~~~~~~~~~~~~~~~~~ + +``uv_stop()`` can be used to stop an event loop. The earliest the loop will +stop running is *on the next iteration*, possibly later. This means that events +that are ready to be processed in this iteration of the loop will still be +processed, so ``uv_stop()`` can't be used as a kill switch. When ``uv_stop()`` +is called, the loop **won't** block for i/o on this iteration. The semantics of +these things can be a bit difficult to understand, so let's look at +``uv_run()`` where all the control flow occurs. + +.. rubric:: src/unix/core.c - uv_run +.. literalinclude:: ../../../src/unix/core.c + :linenos: + :lines: 304-324 + :emphasize-lines: 10,19,21 + +``stop_flag`` is set by ``uv_stop()``. Now all libuv callbacks are invoked +within the event loop, which is why invoking ``uv_stop()`` in them will still +lead to this iteration of the loop occurring. First libuv updates timers, then +runs pending timer, idle and prepare callbacks, and invokes any pending I/O +callbacks. If you were to call ``uv_stop()`` in any of them, ``stop_flag`` +would be set. This causes ``uv_backend_timeout()`` to return ``0``, which is +why the loop does not block on I/O. If on the other hand, you called +``uv_stop()`` in one of the check handlers, I/O has already finished and is not +affected. + +``uv_stop()`` is useful to shutdown a loop when a result has been computed or +there is an error, without having to ensure that all handlers are stopped one +by one. + +Here is a simple example that stops the loop and demonstrates how the current +iteration of the loop still takes places. + +.. rubric:: uvstop/main.c +.. literalinclude:: ../../code/uvstop/main.c + :linenos: + :emphasize-lines: 11 + diff --git a/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst b/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst new file mode 100644 index 00000000..6129303e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst @@ -0,0 +1,287 @@ +Filesystem +========== + +Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the +``uv_fs_t`` struct. + +.. note:: + + The libuv filesystem operations are different from :doc:`socket operations + `. Socket operations use the non-blocking operations provided + by the operating system. Filesystem operations use blocking functions + internally, but invoke these functions in a `thread pool`_ and notify + watchers registered with the event loop when application interaction is + required. + +.. _thread pool: http://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling + +All filesystem functions have two forms - *synchronous* and *asynchronous*. + +The *synchronous* forms automatically get called (and **block**) if the +callback is null. The return value of functions is a :ref:`libuv error code +`. This is usually only useful for synchronous calls. +The *asynchronous* form is called when a callback is passed and the return +value is 0. + +Reading/Writing files +--------------------- + +A file descriptor is obtained using + +.. code-block:: c + + int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) + +``flags`` and ``mode`` are standard +`Unix flags `_. +libuv takes care of converting to the appropriate Windows flags. + +File descriptors are closed using + +.. code-block:: c + + int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + +Filesystem operation callbacks have the signature: + +.. code-block:: c + + void callback(uv_fs_t* req); + +Let's see a simple implementation of ``cat``. We start with registering +a callback for when the file is opened: + +.. rubric:: uvcat/main.c - opening a file +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 41-53 + :emphasize-lines: 4, 6-7 + +The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the +``uv_fs_open`` callback. If the file is successfully opened, we start reading it. + +.. rubric:: uvcat/main.c - read callback +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 26-40 + :emphasize-lines: 2,8,12 + +In the case of a read call, you should pass an *initialized* buffer which will +be filled with data before the read callback is triggered. The ``uv_fs_*`` +operations map almost directly to certain POSIX functions, so EOF is indicated +in this case by ``result`` being 0. In the case of streams or pipes, the +``UV_EOF`` constant would have been passed as a status instead. + +Here you see a common pattern when writing asynchronous programs. The +``uv_fs_close()`` call is performed synchronously. *Usually tasks which are +one-off, or are done as part of the startup or shutdown stage are performed +synchronously, since we are interested in fast I/O when the program is going +about its primary task and dealing with multiple I/O sources*. For solo tasks +the performance difference usually is negligible and may lead to simpler code. + +Filesystem writing is similarly simple using ``uv_fs_write()``. *Your callback +will be triggered after the write is complete*. In our case the callback +simply drives the next read. Thus read and write proceed in lockstep via +callbacks. + +.. rubric:: uvcat/main.c - write callback +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 16-24 + :emphasize-lines: 6 + +.. warning:: + + Due to the way filesystems and disk drives are configured for performance, + a write that 'succeeds' may not be committed to disk yet. + +We set the dominos rolling in ``main()``: + +.. rubric:: uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 55- + :emphasize-lines: 2 + +.. warning:: + + The ``uv_fs_req_cleanup()`` function must always be called on filesystem + requests to free internal memory allocations in libuv. + +Filesystem operations +--------------------- + +All the standard filesystem operations like ``unlink``, ``rmdir``, ``stat`` are +supported asynchronously and have intuitive argument order. They follow the +same patterns as the read/write/open calls, returning the result in the +``uv_fs_t.result`` field. The full list: + +.. rubric:: Filesystem operations +.. literalinclude:: ../../../include/uv.h + :lines: 1084-1195 + +.. _buffers-and-streams: + +Buffers and Streams +------------------- + +The basic I/O handle in libuv is the stream (``uv_stream_t``). TCP sockets, UDP +sockets, and pipes for file I/O and IPC are all treated as stream subclasses. + +Streams are initialized using custom functions for each subclass, then operated +upon using + +.. code-block:: c + + int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb); + int uv_read_stop(uv_stream_t*); + int uv_write(uv_write_t* req, uv_stream_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); + +The stream based functions are simpler to use than the filesystem ones and +libuv will automatically keep reading from a stream when ``uv_read_start()`` is +called once, until ``uv_read_stop()`` is called. + +The discrete unit of data is the buffer -- ``uv_buf_t``. This is simply +a collection of a pointer to bytes (``uv_buf_t.base``) and the length +(``uv_buf_t.len``). The ``uv_buf_t`` is lightweight and passed around by value. +What does require management is the actual bytes, which have to be allocated +and freed by the application. + +.. ERROR:: + + THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER** + +To demonstrate streams we will need to use ``uv_pipe_t``. This allows streaming +local files [#]_. Here is a simple tee utility using libuv. Doing all operations +asynchronously shows the power of evented I/O. The two writes won't block each +other, but we have to be careful to copy over the buffer data to ensure we don't +free a buffer until it has been written. + +The program is to be executed as:: + + ./uvtee + +We start off opening pipes on the files we require. libuv pipes to a file are +opened as bidirectional by default. + +.. rubric:: uvtee/main.c - read on pipes +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 61-80 + :emphasize-lines: 4,5,15 + +The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named +pipes. This is covered in :doc:`processes`. The ``uv_pipe_open()`` call +associates the pipe with the file descriptor, in this case ``0`` (standard +input). + +We start monitoring ``stdin``. The ``alloc_buffer`` callback is invoked as new +buffers are required to hold incoming data. ``read_stdin`` will be called with +these buffers. + +.. rubric:: uvtee/main.c - reading buffers +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 19-22,44-60 + +The standard ``malloc`` is sufficient here, but you can use any memory allocation +scheme. For example, node.js uses its own slab allocator which associates +buffers with V8 objects. + +The read callback ``nread`` parameter is less than 0 on any error. This error +might be EOF, in which case we close all the streams, using the generic close +function ``uv_close()`` which deals with the handle based on its internal type. +Otherwise ``nread`` is a non-negative number and we can attempt to write that +many bytes to the output streams. Finally remember that buffer allocation and +deallocation is application responsibility, so we free the data. + +The allocation callback may return a buffer with length zero if it fails to +allocate memory. In this case, the read callback is invoked with error +UV_ENOBUFS. libuv will continue to attempt to read the stream though, so you +must explicitly call ``uv_close()`` if you want to stop when allocation fails. + +The read callback may be called with ``nread = 0``, indicating that at this +point there is nothing to be read. Most applications will just ignore this. + +.. rubric:: uvtee/main.c - Write to pipe +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 9-13,23-42 + +``write_data()`` makes a copy of the buffer obtained from read. This buffer +does not get passed through to the write callback trigged on write completion. To +get around this we wrap a write request and a buffer in ``write_req_t`` and +unwrap it in the callbacks. We make a copy so we can free the two buffers from +the two calls to ``write_data`` independently of each other. While acceptable +for a demo program like this, you'll probably want smarter memory management, +like reference counted buffers or a pool of buffers in any major application. + +.. WARNING:: + + If your program is meant to be used with other programs it may knowingly or + unknowingly be writing to a pipe. This makes it susceptible to `aborting on + receiving a SIGPIPE`_. It is a good idea to insert:: + + signal(SIGPIPE, SIG_IGN) + + in the initialization stages of your application. + +.. _aborting on receiving a SIGPIPE: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_SIGPIPE + +File change events +------------------ + +All modern operating systems provide APIs to put watches on individual files or +directories and be informed when the files are modified. libuv wraps common +file change notification libraries [#fsnotify]_. This is one of the more +inconsistent parts of libuv. File change notification systems are themselves +extremely varied across platforms so getting everything working everywhere is +difficult. To demonstrate, I'm going to build a simple utility which runs +a command whenever any of the watched files change:: + + ./onchange [file2] ... + +The file change notification is started using ``uv_fs_event_init()``: + +.. rubric:: onchange/main.c - The setup +.. literalinclude:: ../../code/onchange/main.c + :linenos: + :lines: 26- + :emphasize-lines: 15 + +The third argument is the actual file or directory to monitor. The last +argument, ``flags``, can be: + +.. literalinclude:: ../../../include/uv.h + :lines: 1299, 1308, 1315 + +``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet). +``UV_FS_EVENT_RECURSIVE`` will start watching subdirectories as well on +supported platforms. + +The callback will receive the following arguments: + + #. ``uv_fs_event_t *handle`` - The handle. The ``path`` field of the handle + is the file on which the watch was set. + #. ``const char *filename`` - If a directory is being monitored, this is the + file which was changed. Only non-``null`` on Linux and Windows. May be ``null`` + even on those platforms. + #. ``int flags`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of + both. + #. ``int status`` - Currently 0. + +In our example we simply print the arguments and run the command using +``system()``. + +.. rubric:: onchange/main.c - file change notification callback +.. literalinclude:: ../../code/onchange/main.c + :linenos: + :lines: 9-24 + +---- + +.. [#fsnotify] inotify on Linux, FSEvents on Darwin, kqueue on BSDs, + ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin +.. [#] see :ref:`pipes` diff --git a/3rd/libuv-1.19.2/docs/src/guide/introduction.rst b/3rd/libuv-1.19.2/docs/src/guide/introduction.rst new file mode 100644 index 00000000..f57cdd9c --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/introduction.rst @@ -0,0 +1,75 @@ +Introduction +============ + +This 'book' is a small set of tutorials about using libuv_ as +a high performance evented I/O library which offers the same API on Windows and Unix. + +It is meant to cover the main areas of libuv, but is not a comprehensive +reference discussing every function and data structure. The `official libuv +documentation`_ may be consulted for full details. + +.. _official libuv documentation: http://docs.libuv.org/en/v1.x/ + +This book is still a work in progress, so sections may be incomplete, but +I hope you will enjoy it as it grows. + +Who this book is for +-------------------- + +If you are reading this book, you are either: + +1) a systems programmer, creating low-level programs such as daemons or network + services and clients. You have found that the event loop approach is well + suited for your application and decided to use libuv. + +2) a node.js module writer, who wants to wrap platform APIs + written in C or C++ with a set of (a)synchronous APIs that are exposed to + JavaScript. You will use libuv purely in the context of node.js. For + this you will require some other resources as the book does not cover parts + specific to v8/node.js. + +This book assumes that you are comfortable with the C programming language. + +Background +---------- + +The node.js_ project began in 2009 as a JavaScript environment decoupled +from the browser. Using Google's V8_ and Marc Lehmann's libev_, node.js +combined a model of I/O -- evented -- with a language that was well suited to +the style of programming; due to the way it had been shaped by browsers. As +node.js grew in popularity, it was important to make it work on Windows, but +libev ran only on Unix. The Windows equivalent of kernel event notification +mechanisms like kqueue or (e)poll is IOCP. libuv was an abstraction around libev +or IOCP depending on the platform, providing users an API based on libev. +In the node-v0.9.0 version of libuv `libev was removed`_. + +Since then libuv has continued to mature and become a high quality standalone +library for system programming. Users outside of node.js include Mozilla's +Rust_ programming language, and a variety_ of language bindings. + +This book and the code is based on libuv version `v1.3.0`_. + +Code +---- + +All the code from this book is included as part of the source of the book on +Github. `Clone`_/`Download`_ the book, then build libuv:: + + cd libuv + ./autogen.sh + ./configure + make + +There is no need to ``make install``. To build the examples run ``make`` in the +``code/`` directory. + +.. _Clone: https://github.com/nikhilm/uvbook +.. _Download: https://github.com/nikhilm/uvbook/downloads +.. _v1.3.0: https://github.com/libuv/libuv/tags +.. _V8: http://code.google.com/p/v8/ +.. _libev: http://software.schmorp.de/pkg/libev.html +.. _libuv: https://github.com/libuv/libuv +.. _node.js: http://www.nodejs.org +.. _libev was removed: https://github.com/joyent/libuv/issues/485 +.. _Rust: http://rust-lang.org +.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv diff --git a/3rd/libuv-1.19.2/docs/src/guide/networking.rst b/3rd/libuv-1.19.2/docs/src/guide/networking.rst new file mode 100644 index 00000000..8d3c87bf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/networking.rst @@ -0,0 +1,249 @@ +Networking +========== + +Networking in libuv is not much different from directly using the BSD socket +interface, some things are easier, all are non-blocking, but the concepts stay +the same. In addition libuv offers utility functions to abstract the annoying, +repetitive and low-level tasks like setting up sockets using the BSD socket +structures, DNS lookup, and tweaking various socket parameters. + +The ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O. + +.. NOTE:: + + The code samples in this chapter exist to show certain libuv APIs. They are + not examples of good quality code. They leak memory and don't always close + connections properly. + +TCP +--- + +TCP is a connection oriented, stream protocol and is therefore based on the +libuv streams infrastructure. + +Server +++++++ + +Server sockets proceed by: + +1. ``uv_tcp_init`` the TCP handle. +2. ``uv_tcp_bind`` it. +3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new + connection is established by a client. +4. Use ``uv_accept`` to accept the connection. +5. Use :ref:`stream operations ` to communicate with the + client. + +Here is a simple echo server + +.. rubric:: tcp-echo-server/main.c - The listen socket +.. literalinclude:: ../../code/tcp-echo-server/main.c + :linenos: + :lines: 68- + :emphasize-lines: 4-5,7-10 + +You can see the utility function ``uv_ip4_addr`` being used to convert from +a human readable IP address, port pair to the sockaddr_in structure required by +the BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``. + +.. NOTE:: + + There are ``uv_ip6_*`` analogues for the ip4 functions. + +Most of the setup functions are synchronous since they are CPU-bound. +``uv_listen`` is where we return to libuv's callback style. The second +arguments is the backlog queue -- the maximum length of queued connections. + +When a connection is initiated by clients, the callback is required to set up +a handle for the client socket and associate the handle using ``uv_accept``. +In this case we also establish interest in reading from this stream. + +.. rubric:: tcp-echo-server/main.c - Accepting the client +.. literalinclude:: ../../code/tcp-echo-server/main.c + :linenos: + :lines: 51-66 + :emphasize-lines: 9-10 + +The remaining set of functions is very similar to the streams example and can +be found in the code. Just remember to call ``uv_close`` when the socket isn't +required. This can be done even in the ``uv_listen`` callback if you are not +interested in accepting the connection. + +Client +++++++ + +Where you do bind/listen/accept on the server, on the client side it's simply +a matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style +callback of ``uv_listen`` is used by ``uv_tcp_connect``. Try:: + + uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); + + struct sockaddr_in dest; + uv_ip4_addr("127.0.0.1", 80, &dest); + + uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect); + +where ``on_connect`` will be called after the connection is established. The +callback receives the ``uv_connect_t`` struct, which has a member ``.handle`` +pointing to the socket. + +UDP +--- + +The `User Datagram Protocol`_ offers connectionless, unreliable network +communication. Hence libuv doesn't offer a stream. Instead libuv provides +non-blocking UDP support via the `uv_udp_t` handle (for receiving) and +`uv_udp_send_t` request (for sending) and related functions. That said, the +actual API for reading/writing is very similar to normal stream reads. To look +at how UDP can be used, the example shows the first stage of obtaining an IP +address from a `DHCP`_ server -- DHCP Discover. + +.. note:: + + You will have to run `udp-dhcp` as **root** since it uses well known port + numbers below 1024. + +.. rubric:: udp-dhcp/main.c - Setup and send UDP packets +.. literalinclude:: ../../code/udp-dhcp/main.c + :linenos: + :lines: 7-11,104- + :emphasize-lines: 8,10-11,17-18,21 + +.. note:: + + The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP + address ``255.255.255.255`` is a broadcast address meaning that packets + will be sent to all interfaces on the subnet. port ``0`` means that the OS + randomly assigns a port. + +First we setup the receiving socket to bind on all interfaces on port 68 (DHCP +client) and start a read on it. This will read back responses from any DHCP +server that replies. We use the UV_UDP_REUSEADDR flag to play nice with any +other system DHCP clients that are running on this computer on the same port. +Then we setup a similar send socket and use ``uv_udp_send`` to send +a *broadcast message* on port 67 (DHCP server). + +It is **necessary** to set the broadcast flag, otherwise you will get an +``EACCES`` error [#]_. The exact message being sent is not relevant to this +book and you can study the code if you are interested. As usual the read and +write callbacks will receive a status code of < 0 if something went wrong. + +Since UDP sockets are not connected to a particular peer, the read callback +receives an extra parameter about the sender of the packet. + +``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL, +it indicates there is nothing to read (the callback shouldn't do anything), if +not NULL, it indicates that an empty datagram was received from the host at +``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer +provided by your allocator was not large enough to hold the data. *In this case +the OS will discard the data that could not fit* (That's UDP for you!). + +.. rubric:: udp-dhcp/main.c - Reading packets +.. literalinclude:: ../../code/udp-dhcp/main.c + :linenos: + :lines: 17-40 + :emphasize-lines: 1,23 + +UDP Options ++++++++++++ + +Time-to-live +~~~~~~~~~~~~ + +The TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``. + +IPv6 stack only +~~~~~~~~~~~~~~~ + +IPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to +restrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to +``uv_udp_bind`` [#]_. + +Multicast +~~~~~~~~~ + +A socket can (un)subscribe to a multicast group using: + +.. literalinclude:: ../../../include/uv.h + :lines: 594-597 + +where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. + +The concepts of multicasting are nicely explained in `this guide`_. + +.. _this guide: http://www.tldp.org/HOWTO/Multicast-HOWTO-2.html + +Local loopback of multicast packets is enabled by default [#]_, use +``uv_udp_set_multicast_loop`` to switch it off. + +The packet time-to-live for multicast packets can be changed using +``uv_udp_set_multicast_ttl``. + +Querying DNS +------------ + +libuv provides asynchronous DNS resolution. For this it provides its own +``getaddrinfo`` replacement [#]_. In the callback you can +perform normal socket operations on the retrieved addresses. Let's connect to +Freenode to see an example of DNS resolution. + +.. rubric:: dns/main.c +.. literalinclude:: ../../code/dns/main.c + :linenos: + :lines: 61- + :emphasize-lines: 12 + +If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and +your callback won't be invoked at all. All arguments can be freed immediately +after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` +structures are documented in `the getaddrinfo man page `_. The +callback can be ``NULL`` in which case the function will run synchronously. + +In the resolver callback, you can pick any IP from the linked list of ``struct +addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to +call ``uv_freeaddrinfo`` in the callback. + +.. rubric:: dns/main.c +.. literalinclude:: ../../code/dns/main.c + :linenos: + :lines: 42-60 + :emphasize-lines: 8,16 + +libuv also provides the inverse `uv_getnameinfo`_. + +.. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo + +Network interfaces +------------------ + +Information about the system's network interfaces can be obtained through libuv +using ``uv_interface_addresses``. This simple program just prints out all the +interface details so you get an idea of the fields that are available. This is +useful to allow your service to bind to IP addresses when it starts. + +.. rubric:: interfaces/main.c +.. literalinclude:: ../../code/interfaces/main.c + :linenos: + :emphasize-lines: 9,17 + +``is_internal`` is true for loopback interfaces. Note that if a physical +interface has multiple IPv4/IPv6 addresses, the name will be reported multiple +times, with each address being reported once. + +.. _c-ares: http://c-ares.haxx.se +.. _getaddrinfo: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html + +.. _User Datagram Protocol: http://en.wikipedia.org/wiki/User_Datagram_Protocol +.. _DHCP: http://tools.ietf.org/html/rfc2131 + +---- + +.. [#] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#broadcast +.. [#] on Windows only supported on Windows Vista and later. +.. [#] http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1 +.. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv + v0.8.0 and earlier also included c-ares_ as an alternative, but this has been + removed in v0.9.0. diff --git a/3rd/libuv-1.19.2/docs/src/guide/processes.rst b/3rd/libuv-1.19.2/docs/src/guide/processes.rst new file mode 100644 index 00000000..49df4e93 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/processes.rst @@ -0,0 +1,389 @@ +Processes +========= + +libuv offers considerable child process management, abstracting the platform +differences and allowing communication with the child process using streams or +named pipes. + +A common idiom in Unix is for every process to do one thing and do it well. In +such a case, a process often uses multiple child processes to achieve tasks +(similar to using pipes in shells). A multi-process model with messages +may also be easier to reason about compared to one with threads and shared +memory. + +A common refrain against event-based programs is that they cannot take +advantage of multiple cores in modern computers. In a multi-threaded program +the kernel can perform scheduling and assign different threads to different +cores, improving performance. But an event loop has only one thread. The +workaround can be to launch multiple processes instead, with each process +running an event loop, and each process getting assigned to a separate CPU +core. + +Spawning child processes +------------------------ + +The simplest case is when you simply want to launch a process and know when it +exits. This is achieved using ``uv_spawn``. + +.. rubric:: spawn/main.c +.. literalinclude:: ../../code/spawn/main.c + :linenos: + :lines: 6-8,15- + :emphasize-lines: 11,13-17 + +.. NOTE:: + + ``options`` is implicitly initialized with zeros since it is a global + variable. If you change ``options`` to a local variable, remember to + initialize it to null out all unused fields:: + + uv_process_options_t options = {0}; + +The ``uv_process_t`` struct only acts as the handle, all options are set via +``uv_process_options_t``. To simply launch a process, you need to set only the +``file`` and ``args`` fields. ``file`` is the program to execute. Since +``uv_spawn`` uses execvp_ internally, there is no need to supply the full +path. Finally as per underlying conventions, **the arguments array has to be +one larger than the number of arguments, with the last element being NULL**. + +.. _execvp: http://www.kernel.org/doc/man-pages/online/pages/man3/exec.3.html + +After the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process +ID of the child process. + +The exit callback will be invoked with the *exit status* and the type of *signal* +which caused the exit. + +.. rubric:: spawn/main.c +.. literalinclude:: ../../code/spawn/main.c + :linenos: + :lines: 9-12 + :emphasize-lines: 3 + +It is **required** to close the process watcher after the process exits. + +Changing process parameters +--------------------------- + +Before the child process is launched you can control the execution environment +using fields in ``uv_process_options_t``. + +Change execution directory +++++++++++++++++++++++++++ + +Set ``uv_process_options_t.cwd`` to the corresponding directory. + +Set environment variables ++++++++++++++++++++++++++ + +``uv_process_options_t.env`` is a null-terminated array of strings, each of the +form ``VAR=VALUE`` used to set up the environment variables for the process. Set +this to ``NULL`` to inherit the environment from the parent (this) process. + +Option flags +++++++++++++ + +Setting ``uv_process_options_t.flags`` to a bitwise OR of the following flags, +modifies the child process behaviour: + +* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``. +* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``. + +Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on +Windows with ``UV_ENOTSUP``. + +* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of + ``uv_process_options_t.args`` is done on Windows. Ignored on Unix. +* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which + will keep running after the parent process exits. See example below. + +Detaching processes +------------------- + +Passing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or +child processes which are independent of the parent so that the parent exiting +does not affect it. + +.. rubric:: detach/main.c +.. literalinclude:: ../../code/detach/main.c + :linenos: + :lines: 9-30 + :emphasize-lines: 12,19 + +Just remember that the handle is still monitoring the child, so your program +won't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*. + +Sending signals to processes +---------------------------- + +libuv wraps the standard ``kill(2)`` system call on Unix and implements one +with similar semantics on Windows, with *one caveat*: all of ``SIGTERM``, +``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature +of ``uv_kill`` is:: + + uv_err_t uv_kill(int pid, int signum); + +For processes started using libuv, you may use ``uv_process_kill`` instead, +which accepts the ``uv_process_t`` watcher as the first argument, rather than +the pid. In this case, **remember to call** ``uv_close`` on the watcher. + +Signals +------- + +libuv provides wrappers around Unix signals with `some Windows support +`_ as well. + +Use ``uv_signal_init()`` to initialize +a handle and associate it with a loop. To listen for particular signals on +that handler, use ``uv_signal_start()`` with the handler function. Each handler +can only be associated with one signal number, with subsequent calls to +``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to +stop watching. Here is a small example demonstrating the various possibilities: + +.. rubric:: signal/main.c +.. literalinclude:: ../../code/signal/main.c + :linenos: + :emphasize-lines: 17-18,27-28 + +.. NOTE:: + + ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)`` + in that it will process only one event. UV_RUN_ONCE blocks if there are no + pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT + so that one of the loops isn't starved because the other one has no pending + activity. + +Send ``SIGUSR1`` to the process, and you'll find the handler being invoked +4 times, one for each ``uv_signal_t``. The handler just stops each handle, +so that the program exits. This sort of dispatch to all handlers is very +useful. A server using multiple event loops could ensure that all data was +safely saved before termination, simply by every loop adding a watcher for +``SIGINT``. + +Child Process I/O +----------------- + +A normal, newly spawned process has its own set of file descriptors, with 0, +1 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you +may want to share file descriptors with the child. For example, perhaps your +applications launches a sub-command and you want any errors to go in the log +file, but ignore ``stdout``. For this you'd like to have ``stderr`` of the +child be the same as the stderr of the parent. In this case, libuv supports +*inheriting* file descriptors. In this sample, we invoke the test program, +which is: + +.. rubric:: proc-streams/test.c +.. literalinclude:: ../../code/proc-streams/test.c + +The actual program ``proc-streams`` runs this while sharing only ``stderr``. +The file descriptors of the child process are set using the ``stdio`` field in +``uv_process_options_t``. First set the ``stdio_count`` field to the number of +file descriptors being set. ``uv_process_options_t.stdio`` is an array of +``uv_stdio_container_t``, which is: + +.. literalinclude:: ../../../include/uv.h + :lines: 826-834 + +where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be +used. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll +redirect to ``/dev/null``. + +Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``. +Then we set the ``fd`` to ``stderr``. + +.. rubric:: proc-streams/main.c +.. literalinclude:: ../../code/proc-streams/main.c + :linenos: + :lines: 15-17,27- + :emphasize-lines: 6,10,11,12 + +If you run ``proc-stream`` you'll see that only the line "This is stderr" will +be displayed. Try marking ``stdout`` as being inherited and see the output. + +It is dead simple to apply this redirection to streams. By setting ``flags`` +to ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the +parent process, the child process can treat that stream as standard I/O. This +can be used to implement something like CGI_. + +.. _CGI: http://en.wikipedia.org/wiki/Common_Gateway_Interface + +A sample CGI script/executable is: + +.. rubric:: cgi/tick.c +.. literalinclude:: ../../code/cgi/tick.c + +The CGI server combines the concepts from this chapter and :doc:`networking` so +that every client is sent ten ticks after which that connection is closed. + +.. rubric:: cgi/main.c +.. literalinclude:: ../../code/cgi/main.c + :linenos: + :lines: 49-63 + :emphasize-lines: 10 + +Here we simply accept the TCP connection and pass on the socket (*stream*) to +``invoke_cgi_script``. + +.. rubric:: cgi/main.c +.. literalinclude:: ../../code/cgi/main.c + :linenos: + :lines: 16, 25-45 + :emphasize-lines: 8-9,18,20 + +The ``stdout`` of the CGI script is set to the socket so that whatever our tick +script prints, gets sent to the client. By using processes, we can offload the +read/write buffering to the operating system, so in terms of convenience this +is great. Just be warned that creating processes is a costly task. + +.. _pipes: + +Pipes +----- + +libuv's ``uv_pipe_t`` structure is slightly confusing to Unix programmers, +because it immediately conjures up ``|`` and `pipe(7)`_. But ``uv_pipe_t`` is +not related to anonymous pipes, rather it is an IPC mechanism. ``uv_pipe_t`` +can be backed by a `Unix Domain Socket`_ or `Windows Named Pipe`_ to allow +multiple processes to communicate. This is discussed below. + +.. _pipe(7): http://www.kernel.org/doc/man-pages/online/pages/man7/pipe.7.html +.. _Unix Domain Socket: http://www.kernel.org/doc/man-pages/online/pages/man7/unix.7.html +.. _Windows Named Pipe: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx + +Parent-child IPC +++++++++++++++++ + +A parent and child can have one or two way communication over a pipe created by +settings ``uv_stdio_container_t.flags`` to a bit-wise combination of +``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The +read/write flag is from the perspective of the child process. + +Arbitrary process IPC ++++++++++++++++++++++ + +Since domain sockets [#]_ can have a well known name and a location in the +file-system they can be used for IPC between unrelated processes. The D-BUS_ +system used by open source desktop environments uses domain sockets for event +notification. Various applications can then react when a contact comes online +or new hardware is detected. The MySQL server also runs a domain socket on +which clients can interact with it. + +.. _D-BUS: http://www.freedesktop.org/wiki/Software/dbus + +When using domain sockets, a client-server pattern is usually followed with the +creator/owner of the socket acting as the server. After the initial setup, +messaging is no different from TCP, so we'll re-use the echo server example. + +.. rubric:: pipe-echo-server/main.c +.. literalinclude:: ../../code/pipe-echo-server/main.c + :linenos: + :lines: 70- + :emphasize-lines: 5,10,14 + +We name the socket ``echo.sock`` which means it will be created in the local +directory. This socket now behaves no different from TCP sockets as far as +the stream API is concerned. You can test this server using `socat`_:: + + $ socat - /path/to/socket + +A client which wants to connect to a domain socket will use:: + + void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb); + +where ``name`` will be ``echo.sock`` or similar. + +.. _socat: http://www.dest-unreach.org/socat/ + +Sending file descriptors over pipes ++++++++++++++++++++++++++++++++++++ + +The cool thing about domain sockets is that file descriptors can be exchanged +between processes by sending them over a domain socket. This allows processes +to hand off their I/O to other processes. Applications include load-balancing +servers, worker processes and other ways to make optimum use of CPU. libuv only +supports sending **TCP sockets or other pipes** over pipes for now. + +To demonstrate, we will look at a echo server implementation that hands of +clients to worker processes in a round-robin fashion. This program is a bit +involved, and while only snippets are included in the book, it is recommended +to read the full code to really understand it. + +The worker process is quite simple, since the file-descriptor is handed over to +it by the master. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c + :linenos: + :lines: 7-9,81- + :emphasize-lines: 6-8 + +``queue`` is the pipe connected to the master process on the other end, along +which new file descriptors get sent. It is important to set the ``ipc`` +argument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for +inter-process communication! Since the master will write the file handle to the +standard input of the worker, we connect the pipe to ``stdin`` using +``uv_pipe_open``. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c + :linenos: + :lines: 51-79 + :emphasize-lines: 10,15,20 + +First we call ``uv_pipe_pending_count()`` to ensure that a handle is available +to read out. If your program could deal with different types of handles, +``uv_pipe_pending_type()`` can be used to determine the type. +Although ``accept`` seems odd in this code, it actually makes sense. What +``accept`` traditionally does is get a file descriptor (the client) from +another file descriptor (The listening socket). Which is exactly what we do +here. Fetch the file descriptor (``client``) from ``queue``. From this point +the worker does standard echo server stuff. + +Turning now to the master, let's take a look at how the workers are launched to +allow load balancing. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 9-13 + +The ``child_worker`` structure wraps the process, and the pipe between the +master and the individual process. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 51,61-95 + :emphasize-lines: 17,20-21 + +In setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to +get the number of CPUs so we can launch an equal number of workers. Again it is +important to initialize the pipe acting as the IPC channel with the third +argument as 1. We then indicate that the child process' ``stdin`` is to be +a readable pipe (from the point of view of the child). Everything is +straightforward till here. The workers are launched and waiting for file +descriptors to be written to their standard input. + +It is in ``on_new_connection`` (the TCP infrastructure is initialized in +``main()``), that we accept the client socket and pass it along to the next +worker in the round-robin. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 31-49 + :emphasize-lines: 9,12-13 + +The ``uv_write2`` call handles all the abstraction and it is simply a matter of +passing in the handle (``client``) as the right argument. With this our +multi-process echo server is operational. + +Thanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty +buffer even when sending handles. + +.. _pointing out: https://github.com/nikhilm/uvbook/issues/56 + +---- + +.. [#] In this section domain sockets stands in for named pipes on Windows as + well. diff --git a/3rd/libuv-1.19.2/docs/src/guide/threads.rst b/3rd/libuv-1.19.2/docs/src/guide/threads.rst new file mode 100644 index 00000000..b6a4fd85 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/threads.rst @@ -0,0 +1,381 @@ +Threads +======= + +Wait a minute? Why are we on threads? Aren't event loops supposed to be **the +way** to do *web-scale programming*? Well... no. Threads are still the medium in +which processors do their jobs. Threads are therefore mighty useful sometimes, even +though you might have to wade through various synchronization primitives. + +Threads are used internally to fake the asynchronous nature of all of the system +calls. libuv also uses threads to allow you, the application, to perform a task +asynchronously that is actually blocking, by spawning a thread and collecting +the result when it is done. + +Today there are two predominant thread libraries: the Windows threads +implementation and POSIX's `pthreads`_. libuv's thread API is analogous to +the pthreads API and often has similar semantics. + +A notable aspect of libuv's thread facilities is that it is a self contained +section within libuv. Whereas other features intimately depend on the event +loop and callback principles, threads are complete agnostic, they block as +required, signal errors directly via return values, and, as shown in the +:ref:`first example `, don't even require a running +event loop. + +libuv's thread API is also very limited since the semantics and syntax of +threads are different on all platforms, with different levels of completeness. + +This chapter makes the following assumption: **There is only one event loop, +running in one thread (the main thread)**. No other thread interacts +with the event loop (except using ``uv_async_send``). + +Core thread operations +---------------------- + +There isn't much here, you just start a thread using ``uv_thread_create()`` and +wait for it to close using ``uv_thread_join()``. + +.. _thread-create-example: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c + :linenos: + :lines: 26-36 + :emphasize-lines: 3-7 + +.. tip:: + + ``uv_thread_t`` is just an alias for ``pthread_t`` on Unix, but this is an + implementation detail, avoid depending on it to always be true. + +The second parameter is the function which will serve as the entry point for +the thread, the last parameter is a ``void *`` argument which can be used to pass +custom parameters to the thread. The function ``hare`` will now run in a separate +thread, scheduled pre-emptively by the operating system: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c + :linenos: + :lines: 6-14 + :emphasize-lines: 2 + +Unlike ``pthread_join()`` which allows the target thread to pass back a value to +the calling thread using a second parameter, ``uv_thread_join()`` does not. To +send values use :ref:`inter-thread-communication`. + +Synchronization Primitives +-------------------------- + +This section is purposely spartan. This book is not about threads, so I only +catalogue any surprises in the libuv APIs here. For the rest you can look at +the pthreads `man pages `_. + +Mutexes +~~~~~~~ + +The mutex functions are a **direct** map to the pthread equivalents. + +.. rubric:: libuv mutex functions +.. literalinclude:: ../../../include/uv.h + :lines: 1355-1360 + +The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()`` +functions will return 0 on success, and an error code otherwise. + +If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``, +``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error. +Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other +than* ``EAGAIN`` or ``EBUSY``. + +Recursive mutexes are supported, but you should not rely on them. Also, they +should not be used with ``uv_cond_t`` variables. + +The default BSD mutex implementation will raise an error if a thread which has +locked a mutex attempts to lock it again. For example, a construct like:: + + uv_mutex_init(a_mutex); + uv_mutex_lock(a_mutex); + uv_thread_create(thread_id, entry, (void *)a_mutex); + uv_mutex_lock(a_mutex); + // more things here + +can be used to wait until another thread initializes some stuff and then +unlocks ``a_mutex`` but will lead to your program crashing if in debug mode, or +return an error in the second call to ``uv_mutex_lock()``. + +.. note:: + + Mutexes on Windows are always recursive. + +Locks +~~~~~ + +Read-write locks are a more granular access mechanism. Two readers can access +shared memory at the same time. A writer may not acquire the lock when it is +held by a reader. A reader or writer may not acquire a lock when a writer is +holding it. Read-write locks are frequently used in databases. Here is a toy +example. + +.. rubric:: locks/main.c - simple rwlocks +.. literalinclude:: ../../code/locks/main.c + :linenos: + :emphasize-lines: 13,16,27,31,42,55 + +Run this and observe how the readers will sometimes overlap. In case of +multiple writers, schedulers will usually give them higher priority, so if you +add two writers, you'll see that both writers tend to finish first before the +readers get a chance again. + +We also use barriers in the above example so that the main thread can wait for +all readers and writers to indicate they have ended. + +Others +~~~~~~ + +libuv also supports semaphores_, `condition variables`_ and barriers_ with APIs +very similar to their pthread counterparts. + +.. _semaphores: http://en.wikipedia.org/wiki/Semaphore_(programming) +.. _condition variables: http://en.wikipedia.org/wiki/Condition_variable#Waiting_and_signaling +.. _barriers: http://en.wikipedia.org/wiki/Barrier_(computer_science) + +In addition, libuv provides a convenience function ``uv_once()``. Multiple +threads can attempt to call ``uv_once()`` with a given guard and a function +pointer, **only the first one will win, the function will be called once and +only once**:: + + /* Initialize guard */ + static uv_once_t once_only = UV_ONCE_INIT; + + int i = 0; + + void increment() { + i++; + } + + void thread1() { + /* ... work */ + uv_once(once_only, increment); + } + + void thread2() { + /* ... work */ + uv_once(once_only, increment); + } + + int main() { + /* ... spawn threads */ + } + +After all threads are done, ``i == 1``. + +.. _libuv-work-queue: + +libuv v0.11.11 onwards also added a ``uv_key_t`` struct and api_ for +thread-local storage. + +.. _api: http://docs.libuv.org/en/v1.x/threading.html#thread-local-storage + +libuv work queue +---------------- + +``uv_queue_work()`` is a convenience function that allows an application to run +a task in a separate thread, and have a callback that is triggered when the +task is done. A seemingly simple function, what makes ``uv_queue_work()`` +tempting is that it allows potentially any third-party libraries to be used +with the event-loop paradigm. When you use event loops, it is *imperative to +make sure that no function which runs periodically in the loop thread blocks +when performing I/O or is a serious CPU hog*, because this means that the loop +slows down and events are not being handled at full capacity. + +However, a lot of existing code out there features blocking functions (for example +a routine which performs I/O under the hood) to be used with threads if you +want responsiveness (the classic 'one thread per client' server model), and +getting them to play with an event loop library generally involves rolling your +own system of running the task in a separate thread. libuv just provides +a convenient abstraction for this. + +Here is a simple example inspired by `node.js is cancer`_. We are going to +calculate fibonacci numbers, sleeping a bit along the way, but run it in +a separate thread so that the blocking and CPU bound task does not prevent the +event loop from performing other activities. + +.. rubric:: queue-work/main.c - lazy fibonacci +.. literalinclude:: ../../code/queue-work/main.c + :linenos: + :lines: 17-29 + +The actual task function is simple, nothing to show that it is going to be +run in a separate thread. The ``uv_work_t`` structure is the clue. You can pass +arbitrary data through it using the ``void* data`` field and use it to +communicate to and from the thread. But be sure you are using proper locks if +you are changing things while both threads may be running. + +The trigger is ``uv_queue_work``: + +.. rubric:: queue-work/main.c +.. literalinclude:: ../../code/queue-work/main.c + :linenos: + :lines: 31-44 + :emphasize-lines: 10 + +The thread function will be launched in a separate thread, passed the +``uv_work_t`` structure and once the function returns, the *after* function +will be called on the thread the event loop is running in. It will be passed +the same structure. + +For writing wrappers to blocking libraries, a common :ref:`pattern ` +is to use a baton to exchange data. + +Since libuv version `0.9.4` an additional function, ``uv_cancel()``, is +available. This allows you to cancel tasks on the libuv work queue. Only tasks +that *are yet to be started* can be cancelled. If a task has *already started +executing, or it has finished executing*, ``uv_cancel()`` **will fail**. + +``uv_cancel()`` is useful to cleanup pending tasks if the user requests +termination. For example, a music player may queue up multiple directories to +be scanned for audio files. If the user terminates the program, it should quit +quickly and not wait until all pending requests are run. + +Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set +up a signal handler for termination. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 43- + +When the user triggers the signal by pressing ``Ctrl+C`` we send +``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 33-41 + :emphasize-lines: 6 + +For tasks that do get cancelled successfully, the *after* function is called +with ``status`` set to ``UV_ECANCELED``. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 28-31 + :emphasize-lines: 2 + +``uv_cancel()`` can also be used with ``uv_fs_t`` and ``uv_getaddrinfo_t`` +requests. For the filesystem family of functions, ``uv_fs_t.errorno`` will be +set to ``UV_ECANCELED``. + +.. TIP:: + + A well designed program would have a way to terminate long running workers + that have already started executing. Such a worker could periodically check + for a variable that only the main process sets to signal termination. + +.. _inter-thread-communication: + +Inter-thread communication +-------------------------- + +Sometimes you want various threads to actually send each other messages *while* +they are running. For example you might be running some long duration task in +a separate thread (perhaps using ``uv_queue_work``) but want to notify progress +to the main thread. This is a simple example of having a download manager +informing the user of the status of running downloads. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 7-8,34- + :emphasize-lines: 2,11 + +The async thread communication works *on loops* so although any thread can be +the message sender, only threads with libuv loops can be receivers (or rather +the loop is the receiver). libuv will invoke the callback (``print_progress``) +with the async watcher whenever it receives a message. + +.. warning:: + + It is important to realize that since the message send is *async*, the callback + may be invoked immediately after ``uv_async_send`` is called in another + thread, or it may be invoked after some time. libuv may also combine + multiple calls to ``uv_async_send`` and invoke your callback only once. The + only guarantee that libuv makes is -- The callback function is called *at + least once* after the call to ``uv_async_send``. If you have no pending + calls to ``uv_async_send``, the callback won't be called. If you make two + or more calls, and libuv hasn't had a chance to run the callback yet, it + *may* invoke your callback *only once* for the multiple invocations of + ``uv_async_send``. Your callback will never be called twice for just one + event. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 10-23 + :emphasize-lines: 7-8 + +In the download function, we modify the progress indicator and queue the message +for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also +non-blocking and will return immediately. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 30-33 + +The callback is a standard libuv pattern, extracting the data from the watcher. + +Finally it is important to remember to clean up the watcher. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 25-28 + :emphasize-lines: 3 + +After this example, which showed the abuse of the ``data`` field, bnoordhuis_ +pointed out that using the ``data`` field is not thread safe, and +``uv_async_send()`` is actually only meant to wake up the event loop. Use +a mutex or rwlock to ensure accesses are performed in the right order. + +.. note:: + + mutexes and rwlocks **DO NOT** work inside a signal handler, whereas + ``uv_async_send`` does. + +One use case where ``uv_async_send`` is required is when interoperating with +libraries that require thread affinity for their functionality. For example in +node.js, a v8 engine instance, contexts and its objects are bound to the thread +that the v8 instance was started in. Interacting with v8 data structures from +another thread can lead to undefined results. Now consider some node.js module +which binds a third party library. It may go something like this: + +1. In node, the third party library is set up with a JavaScript callback to be + invoked for more information:: + + var lib = require('lib'); + lib.on_progress(function() { + console.log("Progress"); + }); + + lib.do(); + + // do other stuff + +2. ``lib.do`` is supposed to be non-blocking but the third party lib is + blocking, so the binding uses ``uv_queue_work``. + +3. The actual work being done in a separate thread wants to invoke the progress + callback, but cannot directly call into v8 to interact with JavaScript. So + it uses ``uv_async_send``. + +4. The async callback, invoked in the main loop thread, which is the v8 thread, + then interacts with v8 to invoke the JavaScript callback. + +.. _pthreads: http://man7.org/linux/man-pages/man7/pthreads.7.html + +---- + +.. _node.js is cancer: http://teddziuba.github.io/2011/10/node-js-is-cancer.html +.. _bnoordhuis: https://github.com/bnoordhuis diff --git a/3rd/libuv-1.19.2/docs/src/guide/utilities.rst b/3rd/libuv-1.19.2/docs/src/guide/utilities.rst new file mode 100644 index 00000000..abe6fa8d --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/utilities.rst @@ -0,0 +1,433 @@ +Utilities +========= + +This chapter catalogues tools and techniques which are useful for common tasks. +The `libev man page`_ already covers some patterns which can be adopted to +libuv through simple API changes. It also covers parts of the libuv API that +don't require entire chapters dedicated to them. + +Timers +------ + +Timers invoke the callback after a certain time has elapsed since the timer was +started. libuv timers can also be set to invoke at regular intervals instead of +just once. + +Simple use is to init a watcher and start it with a ``timeout``, and optional ``repeat``. +Timers can be stopped at any time. + +.. code-block:: c + + uv_timer_t timer_req; + + uv_timer_init(loop, &timer_req); + uv_timer_start(&timer_req, callback, 5000, 2000); + +will start a repeating timer, which first starts 5 seconds (the ``timeout``) after the execution +of ``uv_timer_start``, then repeats every 2 seconds (the ``repeat``). Use: + +.. code-block:: c + + uv_timer_stop(&timer_req); + +to stop the timer. This can be used safely from within the callback as well. + +The repeat interval can be modified at any time with:: + + uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat); + +which will take effect **when possible**. If this function is called from +a timer callback, it means: + +* If the timer was non-repeating, the timer has already been stopped. Use + ``uv_timer_start`` again. +* If the timer is repeating, the next timeout has already been scheduled, so + the old repeat interval will be used once more before the timer switches to + the new interval. + +The utility function:: + + int uv_timer_again(uv_timer_t *) + +applies **only to repeating timers** and is equivalent to stopping the timer +and then starting it with both initial ``timeout`` and ``repeat`` set to the +old ``repeat`` value. If the timer hasn't been started it fails (error code +``UV_EINVAL``) and returns -1. + +An actual timer example is in the :ref:`reference count section +`. + +.. _reference-count: + +Event loop reference count +-------------------------- + +The event loop only runs as long as there are active handles. This system +works by having every handle increase the reference count of the event loop +when it is started and decreasing the reference count when stopped. It is also +possible to manually change the reference count of handles using:: + + void uv_ref(uv_handle_t*); + void uv_unref(uv_handle_t*); + +These functions can be used to allow a loop to exit even when a watcher is +active or to use custom objects to keep the loop alive. + +The latter can be used with interval timers. You might have a garbage collector +which runs every X seconds, or your network service might send a heartbeat to +others periodically, but you don't want to have to stop them along all clean +exit paths or error scenarios. Or you want the program to exit when all your +other watchers are done. In that case just unref the timer immediately after +creation so that if it is the only watcher running then ``uv_run`` will still +exit. + +This is also used in node.js where some libuv methods are being bubbled up to +the JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per +JS object and can be ref/unrefed. + +.. rubric:: ref-timer/main.c +.. literalinclude:: ../../code/ref-timer/main.c + :linenos: + :lines: 5-8, 17- + :emphasize-lines: 9 + +We initialize the garbage collector timer, then immediately ``unref`` it. +Observe how after 9 seconds, when the fake job is done, the program +automatically exits, even though the garbage collector is still running. + +Idler pattern +------------- + +The callbacks of idle handles are invoked once per event loop. The idle +callback can be used to perform some very low priority activity. For example, +you could dispatch a summary of the daily application performance to the +developers for analysis during periods of idleness, or use the application's +CPU time to perform SETI calculations :) An idle watcher is also useful in +a GUI application. Say you are using an event loop for a file download. If the +TCP socket is still being established and no other events are present your +event loop will pause (**block**), which means your progress bar will freeze +and the user will face an unresponsive application. In such a case queue up and +idle watcher to keep the UI operational. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c + :linenos: + :lines: 5-9, 34- + :emphasize-lines: 13 + +Here we initialize the idle watcher and queue it up along with the actual +events we are interested in. ``crunch_away`` will now be called repeatedly +until the user types something and presses Return. Then it will be interrupted +for a brief amount as the loop deals with the input data, after which it will +keep calling the idle callback again. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c + :linenos: + :lines: 10-19 + +.. _baton: + +Passing data to worker thread +----------------------------- + +When using ``uv_queue_work`` you'll usually need to pass complex data through +to the worker thread. The solution is to use a ``struct`` and set +``uv_work_t.data`` to point to it. A slight variation is to have the +``uv_work_t`` itself as the first member of this struct (called a baton [#]_). +This allows cleaning up the work request and all the data in one free call. + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + struct ftp_baton { + uv_work_t req; + char *host; + int port; + char *username; + char *password; + } + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton)); + baton->req.data = (void*) baton; + baton->host = strdup("my.webhost.com"); + baton->port = 21; + // ... + + uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup); + +Here we create the baton and queue the task. + +Now the task function can extract the data it needs: + +.. code-block:: c + :linenos: + :emphasize-lines: 2, 12 + + void ftp_session(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + fprintf(stderr, "Connecting to %s\n", baton->host); + } + + void ftp_cleanup(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + free(baton->host); + // ... + free(baton); + } + +We then free the baton which also frees the watcher. + +External I/O with polling +------------------------- + +Usually third-party libraries will handle their own I/O, and keep track of +their sockets and other files internally. In this case it isn't possible to use +the standard stream I/O operations, but the library can still be integrated +into the libuv event loop. All that is required is that the library allow you +to access the underlying file descriptors and provide functions that process +tasks in small increments as decided by your application. Some libraries though +will not allow such access, providing only a standard blocking function which +will perform the entire I/O transaction and only then return. It is unwise to +use these in the event loop thread, use the :ref:`libuv-work-queue` instead. Of +course, this will also mean losing granular control on the library. + +The ``uv_poll`` section of libuv simply watches file descriptors using the +operating system notification mechanism. In some sense, all the I/O operations +that libuv implements itself are also backed by ``uv_poll`` like code. Whenever +the OS notices a change of state in file descriptors being polled, libuv will +invoke the associated callback. + +Here we will walk through a simple download manager that will use libcurl_ to +download files. Rather than give all control to libcurl, we'll instead be +using the libuv event loop, and use the non-blocking, async multi_ interface to +progress with the download whenever libuv notifies of I/O readiness. + +.. _libcurl: http://curl.haxx.se/libcurl/ +.. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html + +.. rubric:: uvwget/main.c - The setup +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 1-9,140- + :emphasize-lines: 7,21,24-25 + +The way each library is integrated with libuv will vary. In the case of +libcurl, we can register two callbacks. The socket callback ``handle_socket`` +is invoked whenever the state of a socket changes and we have to start polling +it. ``start_timeout`` is called by libcurl to notify us of the next timeout +interval, after which we should drive libcurl forward regardless of I/O status. +This is so that libcurl can handle errors or do whatever else is required to +get the download moving. + +Our downloader is to be invoked as:: + + $ ./uvwget [url1] [url2] ... + +So we add each argument as an URL + +.. rubric:: uvwget/main.c - Adding urls +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 39-56 + :emphasize-lines: 13-14 + +We let libcurl directly write the data to a file, but much more is possible if +you so desire. + +``start_timeout`` will be called immediately the first time by libcurl, so +things are set in motion. This simply starts a libuv `timer `_ which +drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it +times out. ``curl_multi_socket_action`` is what drives libcurl, and what we +call whenever sockets change state. But before we go into that, we need to poll +on sockets whenever ``handle_socket`` is called. + +.. rubric:: uvwget/main.c - Setting up polling +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 102-140 + :emphasize-lines: 9,11,15,21,24 + +We are interested in the socket fd ``s``, and the ``action``. For every socket +we create a ``uv_poll_t`` handle if it doesn't exist, and associate it with the +socket using ``curl_multi_assign``. This way ``socketp`` points to it whenever +the callback is invoked. + +In the case that the download is done or fails, libcurl requests removal of the +poll. So we stop and free the poll handle. + +Depending on what events libcurl wishes to watch for, we start polling with +``UV_READABLE`` or ``UV_WRITABLE``. Now libuv will invoke the poll callback +whenever the socket is ready for reading or writing. Calling ``uv_poll_start`` +multiple times on the same handle is acceptable, it will just update the events +mask with the new value. ``curl_perform`` is the crux of this program. + +.. rubric:: uvwget/main.c - Driving libcurl. +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 81-95 + :emphasize-lines: 2,6-7,12 + +The first thing we do is to stop the timer, since there has been some progress +in the interval. Then depending on what event triggered the callback, we set +the correct flags. Then we call ``curl_multi_socket_action`` with the socket +that progressed and the flags informing about what events happened. At this +point libcurl does all of its internal tasks in small increments, and will +attempt to return as fast as possible, which is exactly what an evented program +wants in its main thread. libcurl keeps queueing messages into its own queue +about transfer progress. In our case we are only interested in transfers that +are completed. So we extract these messages, and clean up handles whose +transfers are done. + +.. rubric:: uvwget/main.c - Reading transfer status. +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 58-79 + :emphasize-lines: 6,9-10,13-14 + +Check & Prepare watchers +------------------------ + +TODO + +Loading libraries +----------------- + +libuv provides a cross platform API to dynamically load `shared libraries`_. +This can be used to implement your own plugin/extension/module system and is +used by node.js to implement ``require()`` support for bindings. The usage is +quite simple as long as your library exports the right symbols. Be careful with +sanity and security checks when loading third party code, otherwise your +program will behave unpredictably. This example implements a very simple +plugin system which does nothing except print the name of the plugin. + +Let us first look at the interface provided to plugin authors. + +.. rubric:: plugin/plugin.h +.. literalinclude:: ../../code/plugin/plugin.h + :linenos: + +You can similarly add more functions that plugin authors can use to do useful +things in your application [#]_. A sample plugin using this API is: + +.. rubric:: plugin/hello.c +.. literalinclude:: ../../code/plugin/hello.c + :linenos: + +Our interface defines that all plugins should have an ``initialize`` function +which will be called by the application. This plugin is compiled as a shared +library and can be loaded by running our application:: + + $ ./plugin libhello.dylib + Loading libhello.dylib + Registered plugin "Hello World!" + +.. NOTE:: + + The shared library filename will be different depending on platforms. On + Linux it is ``libhello.so``. + +This is done by using ``uv_dlopen`` to first load the shared library +``libhello.dylib``. Then we get access to the ``initialize`` function using +``uv_dlsym`` and invoke it. + +.. rubric:: plugin/main.c +.. literalinclude:: ../../code/plugin/main.c + :linenos: + :lines: 7- + :emphasize-lines: 15, 18, 24 + +``uv_dlopen`` expects a path to the shared library and sets the opaque +``uv_lib_t`` pointer. It returns 0 on success, -1 on error. Use ``uv_dlerror`` +to get the error message. + +``uv_dlsym`` stores a pointer to the symbol in the second argument in the third +argument. ``init_plugin_function`` is a function pointer to the sort of +function we are looking for in the application's plugins. + +.. _shared libraries: http://en.wikipedia.org/wiki/Shared_library#Shared_libraries + +TTY +--- + +Text terminals have supported basic formatting for a long time, with a `pretty +standardised`_ command set. This formatting is often used by programs to +improve the readability of terminal output. For example ``grep --colour``. +libuv provides the ``uv_tty_t`` abstraction (a stream) and related functions to +implement the ANSI escape codes across all platforms. By this I mean that libuv +converts ANSI codes to the Windows equivalent, and provides functions to get +terminal information. + +.. _pretty standardised: http://en.wikipedia.org/wiki/ANSI_escape_sequences + +The first thing to do is to initialize a ``uv_tty_t`` with the file descriptor +it reads/writes from. This is achieved with:: + + int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable) + +Set ``readable`` to true if you plan to use ``uv_read_start()`` on the stream. + +It is then best to use ``uv_tty_set_mode`` to set the mode to *normal* +which enables most TTY formatting, flow-control and other settings. Other_ modes +are also available. + +.. _Other: http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t + +Remember to call ``uv_tty_reset_mode`` when your program exits to restore the +state of the terminal. Just good manners. Another set of good manners is to be +aware of redirection. If the user redirects the output of your command to +a file, control sequences should not be written as they impede readability and +``grep``. To check if the file descriptor is indeed a TTY, call +``uv_guess_handle`` with the file descriptor and compare the return value with +``UV_TTY``. + +Here is a simple example which prints white text on a red background: + +.. rubric:: tty/main.c +.. literalinclude:: ../../code/tty/main.c + :linenos: + :emphasize-lines: 11-12,14,17,27 + +The final TTY helper is ``uv_tty_get_winsize()`` which is used to get the +width and height of the terminal and returns ``0`` on success. Here is a small +program which does some animation using the function and character position +escape codes. + +.. rubric:: tty-gravity/main.c +.. literalinclude:: ../../code/tty-gravity/main.c + :linenos: + :emphasize-lines: 19,25,38 + +The escape codes are: + +====== ======================= +Code Meaning +====== ======================= +*2* J Clear part of the screen, 2 is entire screen +H Moves cursor to certain position, default top-left +*n* B Moves cursor down by n lines +*n* C Moves cursor right by n columns +m Obeys string of display settings, in this case green background (40+2), white text (30+7) +====== ======================= + +As you can see this is very useful to produce nicely formatted output, or even +console based arcade games if that tickles your fancy. For fancier control you +can try `ncurses`_. + +.. _ncurses: http://www.gnu.org/software/ncurses/ncurses.html + +---- + +.. [#] I was first introduced to the term baton in this context, in Konstantin + Käfer's excellent slides on writing node.js bindings -- + http://kkaefer.github.com/node-cpp-modules/#baton +.. [#] mfp is My Fancy Plugin + +.. _libev man page: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_OR_BOTH diff --git a/3rd/libuv-1.19.2/docs/src/handle.rst b/3rd/libuv-1.19.2/docs/src/handle.rst new file mode 100644 index 00000000..cdfb76bf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/handle.rst @@ -0,0 +1,264 @@ + +.. _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. + +Libuv handles are not movable. Pointers to handle structures passed to +functions must remain valid for the duration of the requested operation. Take +care when using stack allocated handles. + +Data types +---------- + +.. c:type:: uv_handle_t + + The base libuv handle type. + +.. c:type:: uv_handle_type + + The kind of the libuv handle. + + :: + + typedef enum { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX + } uv_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 allocate memory and fill the supplied + :c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length, + a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the + :c:type:`uv_read_cb` callback. + + A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, + not related in any way to the pending data to be read. The user is free to allocate the amount + of memory they decide. + + As an example, applications with custom allocation schemes such as using freelists, allocation + pools or slab based allocators may decide to use a different size which matches the memory + chunks they already have. + + Example: + + :: + + static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; + } + +.. 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:: uv_handle_type uv_handle_t.type + + The :c:type:`uv_handle_type`, indicating the type of the underlying handle. 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. + +.. c:function:: uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) + + Returns `handle->loop`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_get_data(const uv_handle_t* handle) + + Returns `handle->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data) + + Sets `handle->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_handle_type uv_handle_get_type(const uv_handle_t* handle) + + Returns `handle->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_handle_type_name(uv_handle_type type) + + Returns the name for the equivalent struct for a given handle type, + e.g. `"pipe"` (as in :c:type:`uv_pipe_t`) for `UV_NAMED_PIPE`. + + If no such handle type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 + +.. _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/3rd/libuv-1.19.2/docs/src/idle.rst b/3rd/libuv-1.19.2/docs/src/idle.rst new file mode 100644 index 00000000..1f51c4a1 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/index.rst b/3rd/libuv-1.19.2/docs/src/index.rst new file mode 100644 index 00000000..5ec2beb5 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/index.rst @@ -0,0 +1,62 @@ + +Welcome to the libuv 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 `_! + +.. _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 + + +Documentation +------------- + +.. toctree:: + :maxdepth: 1 + + design + api + guide + upgrading + + +Downloads +--------- + +libuv can be downloaded from `here `_. + + +Installation +------------ + +Installation instructions can be found in `the README `_. + diff --git a/3rd/libuv-1.19.2/docs/src/loop.rst b/3rd/libuv-1.19.2/docs/src/loop.rst new file mode 100644 index 00000000..86a99adf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/loop.rst @@ -0,0 +1,236 @@ + +.. _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 and does not + touch this field. + + +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) + + Releases all internal loop resources. Call this function only when the loop + has finished executing and all open handles and requests have been closed, + or it will return UV_EBUSY. After this function returns, the user can 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. + + .. warning:: + This function is not thread safe. + +.. 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 referenced active handles, active + requests or closing handles 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`. + +.. c:function:: int uv_loop_fork(uv_loop_t* loop) + + .. versionadded:: 1.12.0 + + Reinitialize any kernel state necessary in the child process after + a :man:`fork(2)` system call. + + Previously started watchers will continue to be started in the + child process. + + It is necessary to explicitly call this function on every event + loop created in the parent process that you plan to continue to + use in the child, including the default loop (even if you don't + continue to use it in the parent). This function must be called + before calling :c:func:`uv_run` or any other API function using + the loop in the child. Failure to do so will result in undefined + behaviour, possibly including duplicate events delivered to both + parent and child or aborting the child process. + + When possible, it is preferred to create a new loop in the child + process instead of reusing a loop created in the parent. New loops + created in the child process after the fork should not use this + function. + + This function is not implemented on Windows, where it returns ``UV_ENOSYS``. + + .. caution:: + + This function is experimental. It may contain bugs, and is subject to + change or removal. API and ABI stability is not guaranteed. + + .. note:: + + On Mac OS X, if directory FS event handles were in use in the + parent process *for any event loop*, the child process will no + longer be able to use the most efficient FSEvent + implementation. Instead, uses of directory FS event handles in + the child will fall back to the same implementation used for + files and on other kqueue-based systems. + + .. caution:: + + On AIX and SunOS, FS event handles that were already started in + the parent process at the time of forking will *not* deliver + events in the child process; they must be closed and restarted. + On all other platforms, they will continue to work normally + without any further intervention. + + .. caution:: + + Any previous value returned from :c:func:`uv_backend_fd` is now + invalid. That function must be called again to determine the + correct backend file descriptor. + +.. c:function:: void* uv_loop_get_data(const uv_loop_t* loop) + + Returns `loop->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data) + + Sets `loop->data` to `data`. + + .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/migration_010_100.rst b/3rd/libuv-1.19.2/docs/src/migration_010_100.rst new file mode 100644 index 00000000..bb6ac1a8 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/misc.rst b/3rd/libuv-1.19.2/docs/src/misc.rst new file mode 100644 index 00000000..07908c98 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/misc.rst @@ -0,0 +1,519 @@ + +.. _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. + + .. c:member:: size_t uv_buf_t.len + + Total bytes in the buffer. + + .. 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_pid_t + + Cross platform representation of a `pid_t`. + + .. versionadded:: 1.16.0 + +.. 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 (X) */ + uint64_t ru_idrss; /* integral unshared data size (X) */ + uint64_t ru_isrss; /* integral unshared stack size (X) */ + uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps (X) */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent (X) */ + uint64_t ru_msgrcv; /* IPC messages received (X) */ + uint64_t ru_nsignals; /* signals received (X) */ + uint64_t ru_nvcsw; /* voluntary context switches (X) */ + uint64_t ru_nivcsw; /* involuntary context switches (X) */ + } uv_rusage_t; + + Members marked with `(X)` are unsupported on Windows. + See :man:`getrusage(2)` for supported fields on Unix + +.. 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; + +.. c:type:: uv_passwd_t + + Data type for password file information. + + :: + + typedef struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; + } uv_passwd_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. You *must* call `uv_setup_args` + before calling this function. If `buffer` is `NULL` or `size` is zero, + `UV_EINVAL` is returned. If `size` cannot accommodate the process title and + terminating `NULL` character, the function returns `UV_ENOBUFS`. + + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + +.. c:function:: int uv_set_process_title(const char* title) + + Sets the current process title. You *must* call `uv_setup_args` before + calling this function. On platforms with a fixed size buffer for the process + title the contents of `title` will be copied to the buffer and truncated if + larger than the available space. Other platforms will return `UV_ENOMEM` if + they cannot allocate enough space to duplicate the contents of `title`. + + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + +.. 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. + See :c:type:`uv_rusage_t` for more details. + +.. c:function:: uv_pid_t uv_os_getpid(void) + + Returns the current process ID. + + .. versionadded:: 1.18.0 + +.. c:function:: uv_pid_t uv_os_getppid(void) + + Returns the parent process ID. + + .. versionadded:: 1.16.0 + +.. 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: ``_ + + .. 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:macro:: UV_IF_NAMESIZE + + Maximum IPv6 interface identifier name length. Defined as + `IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows. + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) + + IPv6-capable implementation of :man:`if_indextoname(3)`. When called, + `*size` indicates the length of the `buffer`, which is used to store the + result. + On success, zero is returned, `buffer` contains the interface name, and + `*size` represents the string length of the `buffer`, excluding the NUL + terminator byte from `*size`. On error, a negative result is + returned. If `buffer` is not large enough to hold the result, + `UV_ENOBUFS` is returned, and `*size` represents the necessary size in + bytes, including the NUL terminator byte into the `*size`. + + On Unix, the returned interface name can be used directly as an + interface identifier in scoped IPv6 addresses, e.g. + `fe80::abc:def1:2345%en0`. + + On Windows, the returned interface cannot be used as an interface + identifier, as Windows uses numerical interface identifiers, e.g. + `fe80::abc:def1:2345%5`. + + To get an interface identifier in a cross-platform compatible way, + use `uv_if_indextoiid()`. + + Example: + + :: + + char ifname[UV_IF_NAMESIZE]; + size_t size = sizeof(ifname); + uv_if_indextoname(sin6->sin6_scope_id, ifname, &size); + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) + + Retrieves a network interface identifier suitable for use in an IPv6 scoped + address. On Windows, returns the numeric `ifindex` as a string. On all other + platforms, `uv_if_indextoname()` is called. The result is written to + `buffer`, with `*size` indicating the length of `buffer`. If `buffer` is not + large enough to hold the result, then `UV_ENOBUFS` is returned, and `*size` + represents the size, including the NUL byte, required to hold the + result. + + See `uv_if_indextoname` for further details. + + .. versionadded:: 1.16.0 + +.. 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, and stores it in `buffer`. If the + current working directory is too large to fit in `buffer`, this function + returns `UV_ENOBUFS`, and sets `size` to the required length, including the + null terminator. + + .. versionchanged:: 1.1.0 + + On Unix the path no longer ends in a slash. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + +.. 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 `size` is set + to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_homedir()` is not thread safe. + + .. versionadded:: 1.6.0 + +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success `size` is set to the string length of `buffer` (which does not + include the terminating null). On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + +.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) + + Gets a subset of the password file entry for the current effective uid (not + the real uid). The populated data includes the username, euid, gid, shell, + and home directory. On non-Windows systems, all data comes from + :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no + meaning, and shell is `NULL`. After successfully calling this function, the + memory allocated to `pwd` needs to be freed with + :c:func:`uv_os_free_passwd`. + + .. versionadded:: 1.9.0 + +.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) + + Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. + + .. versionadded:: 1.9.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 + +.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size) + + Retrieves the environment variable specified by `name`, copies its value + into `buffer`, and sets `size` to the string length of the value. When + calling this function, `size` must be set to the amount of storage available + in `buffer`, including the null terminator. If the environment variable + exceeds the storage available in `buffer`, `UV_ENOBUFS` is returned, and + `size` is set to the amount of storage required to hold the value. If no + matching environment variable exists, `UV_ENOENT` is returned. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_setenv(const char* name, const char* value) + + Creates or updates the environment variable specified by `name` with + `value`. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_unsetenv(const char* name) + + Deletes the environment variable specified by `name`. If no such environment + variable exists, this function returns successfully. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_gethostname(char* buffer, size_t* size) + + Returns the hostname as a null-terminated string in `buffer`, and sets + `size` to the string length of the hostname. When calling this function, + `size` must be set to the amount of storage available in `buffer`, including + the null terminator. If the hostname exceeds the storage available in + `buffer`, `UV_ENOBUFS` is returned, and `size` is set to the amount of + storage required to hold the value. + + .. versionadded:: 1.12.0 diff --git a/3rd/libuv-1.19.2/docs/src/pipe.rst b/3rd/libuv-1.19.2/docs/src/pipe.rst new file mode 100644 index 00000000..bdaeeba9 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/pipe.rst @@ -0,0 +1,113 @@ + +.. _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. + +.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags) + + Alters pipe permissions, allowing it to be accessed from processes run by + different users. Makes the pipe writable or readable by all users. Mode can + be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This + function is blocking. + + .. versionadded:: 1.16.0 diff --git a/3rd/libuv-1.19.2/docs/src/poll.rst b/3rd/libuv-1.19.2/docs/src/poll.rst new file mode 100644 index 00000000..aba89158 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/poll.rst @@ -0,0 +1,121 @@ + +.. _poll: + +:c:type:`uv_poll_t` --- Poll handle +=================================== + +Poll handles are used to watch file descriptors for readability, +writability and disconnection 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. + +.. note:: + On AIX, watching for disconnection is not supported. + +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, + UV_DISCONNECT = 4, + UV_PRIORITIZED = 8 + }; + + +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 made up of + UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. 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. + + The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band + messages. + + The UV_DISCONNECT event is optional in the sense that it may not be + reported and the user is free to ignore it, but it can help optimize the shutdown + path because an extra read or write call might be avoided. + + 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. + + .. note:: + Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set + on the `events` field in the callback. + + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event. + +.. 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/3rd/libuv-1.19.2/docs/src/prepare.rst b/3rd/libuv-1.19.2/docs/src/prepare.rst new file mode 100644 index 00000000..aca58155 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/process.rst b/3rd/libuv-1.19.2/docs/src/process.rst new file mode 100644 index 00000000..ecc3cbf3 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/process.rst @@ -0,0 +1,231 @@ + +.. _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. + +.. c:function:: uv_pid_t uv_process_get_pid(const uv_process_t* handle) + + Returns `handle->pid`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/request.rst b/3rd/libuv-1.19.2/docs/src/request.rst new file mode 100644 index 00000000..54d9a2f3 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/request.rst @@ -0,0 +1,109 @@ + +.. _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. + +.. c:function:: void* uv_req_get_data(const uv_req_t* req) + + Returns `req->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data) + + Sets `req->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_req_type uv_req_get_type(const uv_req_t* req) + + Returns `req->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_req_type_name(uv_req_type type) + + Returns the name for the equivalent struct for a given request type, + e.g. `"connect"` (as in :c:type:`uv_connect_t`) for `UV_CONNECT`. + + If no such request type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/signal.rst b/3rd/libuv-1.19.2/docs/src/signal.rst new file mode 100644 index 00000000..24354e4f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/signal.rst @@ -0,0 +1,78 @@ + +.. _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. + +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. + +.. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. + +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_start_oneshot(uv_signal_t* signal, uv_signal_cb cb, int signum) + + .. versionadded:: 1.12.0 + + Same functionality as :c:func:`uv_signal_start` but the signal handler is reset the moment + the signal is received. + +.. 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/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py b/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py new file mode 100644 index 00000000..1d1dc379 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/static/architecture.png b/3rd/libuv-1.19.2/docs/src/static/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..81e8749f2495741d4b4c2c5dd8a6bca8803d8818 GIT binary patch literal 206767 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

|<0@v3w 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 aM1obxbA2B^pWMfP?%y@PQ+oUP>;DChUmDi{ literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg new file mode 100644 index 0000000000000000000000000000000000000000..439f58109369c37760ce8f9b4710711c17993d8e GIT binary patch literal 19328 zcmdqIcU)85wkW#jU8Hw{(i8-wNtJwvbQM97PE8W4fa-abnnNh*?fLkDS1}|K-Df_WEA~r?UM= zk3Xh=%Z!5i`@h=$HTGX^-uVEadI<97<-ghbtmTs0gwDePMPZ9 z{m47OSH$n}0|zG&ng3ad|E~xB8(RN{$0ai-XD44LFL0@Qpq9CLxq#yKa&+@|^Y#*P z^ZM^3{C_#@-*7ku|Do3)z)?s7IAOBD*+EW#YUevZ&A|jv+2(>zDE=w88w~e=)17Al zS^J0HgE08~@B4qbQKo=jDgE4BL{6J^%dZPgt0akz$-~)sKQQ!g~ z11JD0fClgvpbHoQCcs_53a|$p09U{h@C5>aFyI*w10(`3feauUKmdh6DNqS~2I_$p zpabXy`hlOoFJKy209Jr401aRPJOu>>9R&*o2L&GmghHG`nnHm>l|qX`m*NJ68HE+a zeF_%}FNy$)Fp4OOM2a+uY>GUJQi>{yMv4xKuM|TRlN5^-8x;E#CzMo_%#@szLX;Ae za+Io++LXqWcPZ^CT_}AhLnxn9CR4tq%%}WFSx4DH*-!b4a)EM-@{kIkVxr=vI!7f# zrAnnkWkO|57n^WvqFQV zrKRPjm84anHK4Vkb*BxbO`?5Ai==I*9im;PJ*19gd!f9zw4`uSai9??oR;pGjXv-$p-7zebN|ILjc;pw3{z;K&fnkit;N(8Msv zu)=_6WMhuB#vaBQ#y?C$))3ZA)@s&4*6p(lXC=<+oPBUM;%v^@#MHJ zf}w&1g5L!Xg@lFlg&qsN5$Y1!7UmZIOW0lbm2jKz2808m1#yGCf}kLqB3vTcB9BB~ zi*$>i&k3G0I2Uj(@7%yS{CUaq=I0~NBhSx@GK#8-I*Yy%?G#0eLBwu~g^87mO^Gvz ztBSjdXNmWTA4y0`SV+W5)Jv>O@=6*?hDer6&Rk%*0KMRIA^*bYMcRw17dbJL#cIG?&yad0ooCG%mv|qb>79rd(!GmRt6QY@}?x?5>=c zoV8r4T%R22vhw9emkTdX%d^WH$w$gJ$?q#jDL5$PD2ytyDC#M~6&n;WO43SBO1VlC z${fl!m1C7Vm5EnWuJ~T5yt1JprgC59t;)D6r|NChB-Jl!G-}t>;A$;u$Ld$q{nbCK z?`g>{^j^r@n37& z7q#8BKWgt@yL`>}TJ5zX9d(^>o%ZWg*Y&R_Tp!S7*EQG8)}7Nkujisyu7}oF)(_Qh zH=r>vHb^xXHxx2-Ff27h8>twD8+98q8{aX`HeR|Rb;I{Y(@n~oMmN)M&fF5e<#nsx z1TZl)NjI6jEqUALcC#t1>21>-(^WHhvoN#1I~;dlcgpTy?_Rr`a(CMNf_Z>>=RMYY zw)aZ!9a&trNV8b5l(P)C?6=~#aHurX1Z>>>9}RPVcZSe5$;DGCLSdo9O_dOfE*u6Zwy1j+H zgS>|xOFxczyx^nmli`E*HTEs`qwuryYw+g;ovH5u7XqRK7N2N6$$5ecycbv<#1`Zg z^gUQAI6inSL@%T$lseQQv@`5n*t4+3aP9EC2#Sb@5uI>R_;dKmQ~jqOo-sc2c=jXm za%5WML6k*Q({rKcPoFPG>qnQzoQd&`8IRS7MZ{6Zxy22{E5^TxCnY#0d`rBXn3+gO za!C62LjJ|;7vyB;NMlP2Nn1|8nO^rw4*G#2M zL>6OKK-R+R8?PJQh`o9FhLG)={VV5M4)U$w+xWLf?;PI^=l+#ji4a00B2M1By`RX_ z&#TLq$j>aGEqGF}T6nLpuSm71w3xp*v6xumRkHBG>_c~{N@;1CU|C8zWqCmP#z)(a zKP#?RG*rq|<{`O}iJyQ^0iQOj?pKX{HvZgMty*1KBVO~imZLVIj-oEO4qfkBztCXS zFw|(&*x97fRNE}uT+(u`C8w3EHKmQQ?Rgs+6@of!f84&^;nK0(3G1Bhvg{h|Htinh zG4A=&tJmArr`?D8a`j8gSM{%r-&DWV_h0F+`>y=G_J{J1+JP$rb%QE{4L{X>HVtVG zwGBguJ4UXL^o|;i_W!!|YiP`TY+~GYd||?IVtw+_BxdT#6n^^Y49!f!?Ah7OIl;O7 z`HS<&g)0lKi`N&wFWp(1UUpdC`tA3du=0GBWi@jRvR1mTu->wvxAAk+W^-lh@fLnN zW`}L(?e2x$n!UgFzN0PCD;Qr4c|Yk7-=C5LrGw7H+lO;lPb~f@0mp~?aIAXVcVcm} zh7Tmr5ndB75}QcIq#3d&nM_^;Zs-QNIRn7Wn}8JP4bTG=v2K4m2B*FR|EYrjP`#%B zsKCE}$0F}3|MMvY<9n+Agn=)o9m&&x4j7#L+eHZ;*{2sZ6%{2F4K)qT-yd3fS{hn9 zS{fQU20A)=dU^(W8d?TM26{#iraztJbcWMW;4eKm=Ct|$>>{@VZ1lhv3Pvi5^8h6q z1r-|wxf_6hG|>D5yHj*eFA7R3Y7iHC21X{ZL+x3Bk^)4PnhHb|^o}UP!RG)q8x8w8 zd2Lz_(+70teK-}KrRLF#UaRWhG8;mRDL(X#WMJgx;pO8Omyo=0QA$bqii)b5y3Tc7 zJ$(a1qdRxa?^%Fun}eg1vx}>nyPto+lfaCR*Kflkqrb++Cnl#BmzIC8tgfwZY-0BR92{bgaK|U7 zbb<2uC)58Q>0$%vqNJv#qNY2gi-I!nlyEj`nsf5B?AoSu4}3VzD?Fp;yq20*)xjXD zXolu`=sU#7EvB?6jyWamZ_57n2#fr`qU@i9{fn+CfSHN{6dn~D00l^-3;7Aa|8G9X zlolUM1Pk=es4|2%%pD%3bvCOv6U9o<%H+SRqM}||A@$xobuGq;MeO6|)AMCzUM?D+ zT1=uNG{fXD_ex4|q1T8tVSXRCvgTw*2^21DXc9sI8h0uGkJqE)5l*jUXpYZ0UVrDZ zB%A4zX)=(OGS{4EIBl`DKMw044pwU&<+qq?@r7NdQ6UY%IU$fxlDPHRS+Jwv-4yin z5|jQ)$qo}nMxdGuIITy6_ou4FiWK4R#@6qrV0p>j@|Ir2*xj(p;-GkO9cEt zFd{OMX3#mm#n&W;1oiOYgxBzNHx$n>WZ@OBOY;7vzzX`A!aHkl(Y3JzC6n&`TlCP$ z5Me!aGSDBZqZ_$aV`?u4?edQM-1M3ZxWeMbFp;--42KLwf2KRaGYrW9<9y$OLdq2D z(u1$~AH}ZGSsRIGp_g4j1{+EDI^aAo44OzqYz*$rMYBK`<00U2xR1m1wD55uEM}hV z#+)OfMy19Vhe2?@11D&FUe0#nUwveq2f={ha5JSrT1&;oo}p`SR#Qn%h_O zeBZhP+!Y${TL)+y{NUg_TZdX?fd1Ha ze&1w=52NAp2vg)5L^VRvR6GF{Xa`gv_^Eo`Gbg?$NeCiZrkvxfB3@VZt+FUUW9HA^ z`Su6u3X4z67}(wj5n)BxT4J#Tzf(j_?Jpx(+Rh&r8^S@}^lIKe@1`#GG~D-5d{NFK zvYXF2(*Wd}cYG!W(#XFNa*m;|^pn`B&W>6n^rP`hFW$1-xLQ< zPVLh^KW(FP@y@(sSvZS7gjMUj4Df;Ydd>(Pl*FS20LJaqP3lZW*}2*ot4ox(2ETNSL42N9cwSA2)e3dYO#$)Knb?E(nZ$T zI!K*l$|Ysivm4p9Q=95quj@=NB=Z%>C|xG>@alf+-S^}}ZrUuYXE@?MRcm2|6-Rxx ziyn$ZT(|gqnVInubK(7{p9y6OzuU5!QOlqr>`KF@=d7Cs--*}eFCUd9kbz@x+lv1g zIX1${<8KC~FWN_=Axk9*T8d%bzfccbMX|}4GbxLEJRa5V>~#f;Pe!a{+D5zS8tQFc z^n~@OI=-g4!>8Mg-rJGJgtkMNYUOYjTw+_`n3N^DE;7In@v}{NNLhw<&$9KbJuc9! zI{K34v`0K;Z|0wt2cnJw!V8b-ky~=x=wNBD`>|hmDXzRI5K`Ufm2yY9VY~yKLbp8b zn4tp2X^|zpN1|Ca2V+~sl?C^9T%geCM_~bYiZBgaGSDTxS`+HSbyauHeDdI&V&j0t}RvFUj`)?V|mz~a>c?b|*WNoz3s({FGcE|vQ3kn1-$oV`WmLlE2uW0w+FgGaHz znEc#A1v~N@In)bnZ1Uy?%B~tSE>@5MH|XfCZe=tj}oXzu#io6xHhK9Za{9jqn5bMampI<2i#;6Ju z0SmY1f2uJhO}lkF`>HV0r%mz4&t9|IH=K|G>vsN;XDMoAfLrV*UFd)E!G?5FL6jiw z%E%Tv|Iz&XWGy|(U$PbO8nR{F@?GG0mwS!E;Vor&ta~69^cn{5k%6`kR4vFiZPYU! z3}~H&DT$JjYf+uq2J~LQlvW=P?~eU^p}ViGecX-c)K_T?gPOiqHAn%=FaW8kG*8*a zSliS3{w>Z}Uk;x{n0H9jM1+J>9|#O0G152+TF~QzaEr6V(PGMmUG1we9B! z_QMOcH$|7C_o523!`+uH>+BSFxSN(|#W!vE?hNSB(zInuUTB~BYlmZJnyCx>Bul;y zoz-i_>;?#{wYCdC?;2bl$5e7|9+Tv+qZYzf^lp6(fo4zO=I~gay5`}EnjMv;GtU;v zV*)&;TUonaFdzBI{2(q_AE()ATwdl`hVMF%Dw zs5w^U66S-f1Wd;r6Fe2%L|YpaIUAn+9!dPDC&E>1o4HR0f)DkvD7?QA4BC4kY9;4G zJ$$_1X=~Ih(C`VV&HG2LBsvP~p0a@Kx*EE;7ONQ;x+EG{K7o7YT^m=_(13rW&>`JB zVyI{^*4>`SEFM=E7x$3({c(>F>YhUiXaWdc)RlbJn;Y5fxhFFDV_K)ZWjD5p% zU93mt9JjT#MR+%E!luZ;&M+D9Ko`2^XDqk;68U4uf6($qA}a)M=L@(l~SudFfvW z0U=qZeNa_pD}rcgn)sl7WzxYCMeCbOwo7=A`)V@O*l;zjG=D zf!wI_8UV+vOVpD@?87thw~nitB#886fPY^uHaiQkEW<7{*$*WpI@lq4Z3aKX)&-aS z%}7Z#6d9)!8lPex5f(JP9N06@6f|JqsVOf}v1moOo6S<1cuRqPhYVD+jNJO3#sh7A zQ7~i9AsZ#O99TkN!A+JDVCe9^ga8xT863ZVGxyT4@vo*C&A38I-?AM?H-5=$3TZm$ zb6+jxSlFc>UyZcZfNsI}UDmHu`K{pid)HLIwZj#ly)AtpwI9drmOK!0i?Z(m-a0cW zBFZIk<0}^3d+`vV3W6JkM<2~yvCJf+%WJ)UWpLrBb(nj$261^_X-RzkQlJYZv<6tz zL|)=yzf@mlM+T5vn4eFE>PKK(C!<7(Q_i}#>U5|;-G^!o72g_kLD3Yjms5eguw)Aa zho-zoWl(6Z`k7eb2mk3G3gdc#k!C{Y(iUu$%L~We?`1%CxRa|Me4D8j2qFXbNE|c7 z@-Fr7Zw6%T;QRc)#DgwYAP96PX|sh3N3ijAAD=D0WCe(tsmb5#wq3-vVxWDwjBUeS zni?gWCz(;u80B{EF8!R_Z)$t+=SI@mL?7LQ)h4x#O1fS;Bi*|TcZa4tnW`%<(nhmd zj*8czM&BnpeHvw-!m4J=(;J4R`F`78`ToGR_e)~RyqR@P=H3aZ&F+VwQ2HJbZl6*O zwQgYz$G-FKpM86+@7O{TEp7Ibt^*SFl$gg#INxN#!uT7WuREUb6?g7~yGnLN{uac6 zG)DR{>o0Re|9oCzC#TJ`aX@iEeI$Zb*ExcLAS4&?VNZ*D*stzu!rFGKzlg8YTTlOo zh3~TEW%sx=sWAD=K`z2-&3YmZ)Jmeq6tM3o0w)KFQ68^Dkii`x2_iTZ*d`{Y1 zZ?I_b(N*<^m@?_YrjvqCQ6xrXGC;%DQd^6v#+4#xCU2haVIB&C-tfj?jlbA9}~+x?u$&cLhLKNo@~TY9E&DE$3R zVFlb{(BUJTgTC-4DEqi(@>f$4gPgx#GeZ>atV_$yKvibfr*gh<=v5**J zB|`(7{3xU%OsG2E@Is{ADw))$p%Z&YKec-z!!?^bH7h;6SGTqfC2$;(7!~o?3Ac%P zVOPVYc#XG7ZCv-9le$y%pxCnl_PpQHulG3$@layA1)wy&e zMpI{m-*^kBCw*@cBn2F)5V&vc?N~soN3N`z3O6WD_&LG2-u$*y?yk9vDSjm`&@inx zjJVk(+S7CY!pDJk%3RKsx-5`BhBoX^x)}ec%&T;Skbo^4IufG> zC_v_TLSuxqN5|Ocyn6j}|4+J~K>ud~4>>_$+xA+6VC}G^IU1ZtpE+_URzK1dHZBV-%NFAY-u!nVbAhmn$*wtYH`tOr0Ci6%{Ky?qz)1sG16ZYO>b!Rs1=OwtmW04+%;=GKew zB0JYi?yZ0`dv7mgq6_2jel=^r^0`WWQto1uu z*I6&5T&?%)4d24KH)MP2?S{TFNLzK|n|6QJI`Mmf;@Q`AY5W;tVE}gnF^8mXQ@Iw1 zcCLJ;e<$anp7cVP{?|{hJQl+PVoo~$%Sw%e7I9?JlP{QJ!y@90tJ-4 zaZ-UheIGq|vO-*XJY*>6+^q7dKBITviQQYsWn=!N`TPt*QT|A|M1{a9Kw{MQ6dbW7 z=wSRWpI5AgM%Mf?H^+CUJ3Xb-nz2|#XIj2j&uw|i@9A}TF!!C}l7c2;}#4^=v>Xer2#LD+Jr zb0mC^YgTr!+56{-)MUVgn$qFKV>vm|>U0w0GkicFyTQDm)9o%PlbD($6){J6{=Nb| zLHekR#IS`o#f@WM<0wh;xR^SYC8DBD!%uJ7ihMTl<78e5t2)*U2CLDt4Ys8sz+-48 zG6li;5Z8n8=#9`AIaq#=b6(xa|LOlOwNE&&DjBWxLw(8Iqw3Nl(V7dH5SKXKXVHQ)F|%@6M;^~XCO=k-#SY?> zA48vR7A}7x^*4hiODz*r%*-VzV+Q_P^6B>5cZOANTG_!3xBQ#r8yH!c%x;gx#QwXAmVpCEb2=>E*UIMSa+?D@#HhqAxjRR|8hM z0IoLMm-2|>Tu5F`V?E5b`b!KA*Lb0Y&lrBSt*?-pC;HWQOh z3L)?S*`=B}iEybq>C*vxy$7g8kEN)d;%fHIWm^MVk zSGMWPu`ak8Gw=;Cv<6yihVMfcKEUgZc4RQWCMdy`Ip%zuGE^O>E)Lj(vXI;pzoHxUjY6{Zu^#fida$ zw5Fy=1~xQfTH)BL7Q74@coy8d?hVyTK&1}$4GyBfybOEWMYpD%-S|bHB^C{XWSh|P z7kXW~c>kYn(-nCQmwQd0fBw*r=Ggf~yAIm?ii+c;uM^3&HHD0-sBF;*tZ?U{+}suL z_+fktPcwU1c591yxTBWZ>kH>wu?KCq}xV0xPW$JeyatZ|BHtx$EqC(N~WW9`I|94}E+R=nEz=X3nc| zmtJC1x4Ar3@dgd~&iLkB)sp(rjw0sUu$|BW{Q1dl1^c`v$46nI(U87@he@rv@SKtG4D*-R?@+JUVqI5tlU$3@l3gAFq((y zw;IxP(V58~=N=r#RVU`s1R=Ija4a$|eN;5FYO3+uMDQsr}Wj&%gVCv4;6Eon4u4__G6K zA1n!44Q)?Jo@y{Dh+c^C`VNP7& zqFgdb9kbf#u!x{{vzPkiRm+60?|ytOU$d%D@)IM4*aBck*=CYOV$31~)PsS+;y6^k z!SCNy=zEohS}4ql?VrKY1^0{U-(EF^&LCIHTr!fE-kz~j{diA;({b$Wh^c3=T>+*Y zG*%iYN58i?h)o|cR+bFlR^$j8%~*p4&*km{^!3suX294Ol zIyg#y712QkCgBT`?G?Uj;M8YYc$N0p4B4V~>Q(&gj0IiF@-mXYA5BN;!M$f z%ehe=i-YlVe6<*11a(_@m4c?()Yl|#!?Q8A$@Fw|Z63Rzs?*#A&8Q{*3 zjV6&CFf*r&Ap?$4X<@8j3TjAiF*vzW5Jj1;V=x;0F*gkO9X#{Lei3J@_2{AZ5~_ z!~Q&YP!)ppudTbE-+0MH?-u#^ar$2TR-d_R8mFomsUW@Wk%N%d-6!Uy zB3;TW64gQd1o;8JxIT}*F@GW*0wJ;SqfR*h?-~XffH=5!09woc5YXBZZjdF;-5leS zW49@JT%B7VcdV=*^7_PN>?4FU6LHNQfi?kUBxl~%go4M`Kar8nlDFO*H@*HmH{lt& zVB-FnU++M{?Gn=z5jgF`k7QuN7i3Yg#kLP9gM5&Cijlie?wXrzDD-o8GC+vF0Y%?M z;3TXMK|ZnK(*jQAaJZyl)c+q0$qOpTfdA}8kj|u#0kH`66r3b{`z3T$e+;uhYz!PE zT}M{73E`j}Fb0BTF-~-m6zj5xVzJ(px9PO{{M~opdv|r!RjYW3wx6IoVM5@Luc}{~ zi!zLySP|oJ!_E9Fjpz6#E-9+le;yg18i!u!q^(r_7L=6L&o1Ds$#U zR9K>j4TL3JA6^AaYW(>y;Q?cB5fZMbnAX7tA@4V4PQfp*UsKfU@{Kg4s7`w8AkhLA zK~8s6)Oh>JIEnS|4HeN1?;3$GywLzNmYuUdK~whd9|)n)2ZJ~XLowFGCO%P8;R_fU zcv*e}8h5sc=2oV%u53a@)=Z%}l*9M6tfe#O@P0XjWIzZ6l`t^ks}OvVZVcRd!Ql6v zab%b*@h#@wImKk7h15PHqSg>}p%{U_ zX>!*6iMn}guN-|>fR9v{z+BKBvzlnjw=DZVT&sGoT1`;QjL%um6QuT7a4x2pk~oeI ze&}-<8Gh2*okmO1+Q@YA^Ac>U&5Xx>Os_^Tg_+|#&}+*sF{nijT-IX03Hy5gg@$;$H)8d#D5-kabwux{ zzSPqe%|m9U5I9g+LrKZ@lQHaR7q9>Hz$IJd$V2~{Z_*)<6U zs*9Ol%2^*9lr57O^T00MYJI&z)XPZ1?UO+=ATs`IQNdm`?~D!2QKZNI>%R!8WJHhFKVvR6bZ_p<;t+&28HPrDm zz5CI9@%-Cz-q~+g=m+RUMT;Uns}Q&}NDN5@GMFfB$dTw4gb-zlz)2wp9Q3{s^6OBX z&K8sqWyjHv%Qx)3i(!FEMfZ1aSCwma{)gI|5?`Mm4S**J3pISM%?_1TZphx$gGaNVG&fOX0rTV`3%4s%b|2O!sY-;wN=l86%`YXkFhn9DhCN zG-7}QV3NtN+g>7uwmJQ#o$TJtT!U9n2jT;m^=>!vO*Zqbacx2&V1@A+ygDUvycZ4$ z3w$30>AW)_bKYa3@ZFxc2tro%yndz`Aog6Zollhu!a6`F#)wa%Vc01Hc z+;Y`RS|(!p&7^PWQFxZjE+O^!BC%?4zVzIvb7Q7-sDI|tk{*MgYxA3l1K^Ay78&7< zlU5ISu1uW5bD=wLw@Qj00nnRB{wpim%Xj|Y;)1JatudLqm8aEi>4|U@6-_PcL z>Ckw)qWu8*UHhY>qbfAT`XnAS>7QZfn?1bnDV0bKoQ^%{ZA-O-5h6G*b#256s`hj<}r^ zmA`h0(T;i1M-6|ru7AE1OkN)xm#=T3aMGaqv6|)#pl}<-_Jc{@IUW4dby~%}WeA+K zB!PXD(xmqt9Tm7snn2VoaORQi(wR{e=AKJeV72$5Q+KWa_TSaTSjO7{qG_4`z1cI^- zB3(4Emo#~m^k>UhwCXx_r2cp|>6hLcQ21e2#lgv+ybZAn0_RM4zkxvOw`(h$9w^#7 zImk0`j5!8{IRoF6pj&}p0MzCKeelSQgmdgmKXBYs<2ozp^M$b>J=qU7%{PKtNU>uE z1$V0rzOmQ!7W7qqZMIPo-@zB&LAf4zE1N`<0XopZVU6c^YKas`d`G1}tW5vjSAi>= z=6+#v_i9biVqx*|gSe;&JsiBC$7uL>QF4*wBzR)d!WlNdsjxRd>}wD7J3KWO#0Q=& z&DtzsYyG?{-NqRLok}j%gU+DmG?Vnq^mTNXh@th?wy1wJ=ed__Q7PN?eXwe80!P>4 zlN{PwjNHQDb|QMqAlpPjx;0RD_|mz|8!oQF8Fvx){p@e~58_0Z4zoxMQ_!8QE(F0m zz!Z(O3`V(G=XiRGukSUHftZofU&ihHuQjh_JaQ61R%=YoDwlb}LXk=-D;#|YI)X+i zE@7L%it&zAM#Z|OPEWa8&nMPY$Zp+9y>m2DTk#uX;#G7+W1*d4uDOfU$Lu{N0YNDp z*3R$HsBRKx*3zcV!>q)B3jGpYY~0XttB!bQPe~0R)2u6YN9nV{AIRJ}X2b{*>q1~V zZ2SW<_{Tg+s|DQLJ*GqiDAx!&BAmd{06D><*T?{u#Tl9sUL(dD8EKfE1uWpe`gp@B zzm=%FaCpW&?c@jRoa?WH6ceBDOk{zVNqKWK^rc)9I_L_k(7X+fabBkuz5RsWm-k=` zbPk8ttvY3&rs;_f=8E@AD>?2beY=Yg3ucq&Wf_FKlg4OL2yDm6L!dTM?_LTGuRdj9 z=xQQfB%)hbV%VP;+J&ml+Wxg9#JDT3T(OfCqcpkDm~`OppHxn@$-otbo+=7SdnMg< zZ#MJWUjEL+AIQ*dokC5C4xiz?jo$9O4}r(a`xRP1)8#|)jqjGZ(34-pZruDLl)#Q( z%>5j86$9yjfmvA4H$NNfaj|M_r$$2{`L`hMf~N&2kPol(F85v(mN9--9jg+IS%@jv`35cNeQhMBbiS**!a z4DXQ6>B(j#NI%2V&IC=^7PuuA{CIzLZ%T!w_#B%YO0{>+&kEdr_g=|?%s(dPU3+Q} zW%OV`-MudM#A0iX`SIueKiOP%<{G2LHItzmh`h(h7!R>;eo|z>>V;Q`VoKxZ8pp%H z8Ith3G!e_BDuOQKbe4v1p$lDOVc-CdSk-b0sWqGdy|-YWwSGhONUx()EE(`J>1CdJhxMC}^Dgvao1>d9sAkJ^;P^h>i%6K{OJEs}6mz zj1L#RixKL6(#G%hk>^H@N9~Mkabvuh#g+CYA7<&*Xt(aDekcz?58eA_VNk$hj(dn; zUJ}%2RFldsV>Gnnx=VE)Wm%YZ{+o?Qu&+T*MqP6yFM7dmMpmMrNYCO)+Yh%;`yHEb zR(<)!7BBX+in!QIHg%YgDePy@9pvl`zL~^8AqJl1G#o?(m$6<2u}Od~1~QS=CrpHD z!}8|QJ_X;Li7%JVknRm~%G(ke2i^>hp)}wNFRfs>3-#ORGX|1&9ipW7S%)V)pgj~& zWSXA<P$9~1wNs88)ILv*eb9v*drv_Gc{JI6qy+z`Z-1CT@Uu1(+6q&y46LY2azX=@|U8G z3~LMk$(Nut#N+?Enw0%6JILhD2&&3?{9N|j;kO_B+CrV(RCjk9R zD<4UAsUE7ZI!;@=Ro0=5!DN+JSh(C-1vfEL6<2upR?qaXq2l7G+UAwRg;9K)t=zY@ z(F0_|IbwpW{~&viOIL(6u4wTK|6W%}9qNNgk$BC}2GXJIW{I)K>YSbRbTh-bhjzs; zS})(XTIbqtnq7Pd++_&5XbF?xB3$A7%AmfVcJTH*C;Ml z4Zg-?+*g}3Ok7#}-Lzl5<&_&EOJs5AQ!_?L)*Bwr1_$W(458&4(sK``-!L+(@@^eg zB9|b~=NFGs2tEsH%GAFkh5|xc#Va!vA{V-(uiIV}`{3EwdrQ&Q;keDEKWRC2YtPKj_XvD%ki3q03qQbMU6RWkvdOz2{nrA+w?9XN3FV0GaavYBz;L)t6 z=tUeC+HywQa}B}Z2Kqch9mj2b+#!Ep{d)v~%}HW)o9IieJLo~P!EyW@W8|jj!YyPT zYb1oW!=@XGPH@xY9Tz3C%ej-%(I}FxG~osrP$Ip8?cXyYoF$}u8N^8|@78d`B zz1YppDcFnLn+LbQn0xK~cr{$6DrE7UO^X$CKDQH<^~7}v0+q=Q&e1#286-m2fA>RJ>h5I@S|+ z)FQ}62I!x>e+=LI6{a5_93Jc}Rd|2O$GULdkC1(${o8Wt&9=v#l8bt`Uu55`5NI0N z|MTY@E)cIA<_5k;Cp{<_#L@9-GvaJrL*|_4HBYmFZ@kuGFIJpYI3(Dpt1|ueWfwCm z_jHMg5$aok*vzaGm*^H{&JFKNinAV1sy|klTufl-v~KzQTFfat{kgoVPVK~kaMxm1 zEXsTE`4bl-w0HYn@=Mp|N+-Pd;M2-AZ83CQp-64p0=?zy_Zob8aZPPMrSIv2M*pRf z5dvKabyMo;w3W+R2rYD+*v9lSPE($L@$UQMlvzDHtkmu!Lic0d0M^C3tMyJ^9^SP( zKafQ!gP&(&WnZY9_1x}OgUuUB4ccc*mi=kn`yCO{;3Q>mY_Q-1tB0Yruihd-r}~$i z)466xLmbHfYvo!t%bMfoz7G>pYC;UAVo!xTrpHk70@%C6QZX9%Vh%}5YB>p~VG8PEtFc8w z&R8C}oM+j$xP6{SdI`^t6b-(;XLd}ZAc78lvM?sgp}jbmPNJ z;&acxFud~$8PwBUoRJ+G@ebkuy1-ZiVxH30Eaev*Ba6||oopMM3kN$MCT)s?0=A-^ zn(_1O<<QBK69YLN^w4>~ijF?8|<}xyi7rjgh;~q4Aac&Z(ZC(|Hc}cIIX7=RYi)@;Au*}` z_U-rNu$=f}N`Zgh+)3swMKK#wyT!Ko~L)2~~-xX7VwJwiDBUd`wwS?`;pR@0oRvG?|KJOE5T`=<_b zck~vE2KWw0k(Kp?RhTNV_(yGRQPGQ%oQ3Jh>~BorB%{t@o6JPlOkHutOnt|PcXyB+ zJXvPu?xF4hf=HRP+TEQdud(|1&G`gD z5-TcY!MpFKksYPR=&-w;Xw4Kc`v#7TK=E6=du^bM6^znAr~v7&hF=P_z&zTG<>K@Gc+-WOt@(_8>UWraf%`gyifO`u{1 ztJ3G!591z}H5WcQf5Ei&FD{~S*kfY0W+)OIsstX4piQrcsl^DG;DQTXZ}$o2JVdor z#mrwwnxOjb%2@h{`O^Tc$03sXqUII29ckE9ISY`rl~VWwGKN{a~OIYB%d{`yDi&T5H~k4ITjIw1*$ zvxo7yfyGAzeXvp$ywaFyEMH+uU+D2n1mU~a#h|%SPu0a&B&jj2b>Aq>BFW{$ zo_(w2_9R{p(THYRwuEA(VJBd5Q7VX-19u$&D{*Z~crdz^4hMsdGS^kLa1FfrON+UI z3m^4tvd!yjOU&*~ZQh#8(&_=_c}*59;zO&uXur%>!Z(shsJ~DP%jt=Opr5_Ughz57 zo@@jxK+p!zNegV`C(y4F4!ez!>qH6SRNCkG>VC-vFcDphvwMU}Ms{T!5}?X=zpSj? zi5}pxeCvZ~g)X$ht1Wt=FYM3aD3<4=BWT9kL@a~s!yist)C^b5t?tq^bH}J%H(+X_ zdeo5+sqM7PCyLA3fLZhQsV+il+~4vvSC$ocd&`8g9^_!*@J=t6*z(sAtFje#F1r=3 z`xQGaHTEw1>MdNhyZ6H8S0Xf zd>;#{Cm0Qqffp7xT$jg6O<)+|aNDl)x#{mDHy8ZurE&EbSf53FY0&giU`mT!n9_0) zL#>eg(h8~DQ6VR+Ien$(`4@}btcTs)Vq>{E_`kw@hLwnl2E%O%VJ5=|jg@ z1(&%W-MQNH>(}>+OXG?f+%AC+jTPAq#eSz5e$X6;$werxhg#I9fIIC~mkL3#uaDit z8+RQv2)JK#*oVX-1~p=?mKp{4zpvJ@&|}6=!CvB9+bc(kO`3+8;!bfT;421wguyWc zPG#sBu|`X5;WxaqdK7-JQ8a!qg4UV@cbO4Eq~EBI#O5iTN=HXzhq@C$r#tdYL_bO> zi~_T~1n-5%!I)cM=%WtNjz733vxm(LkBVBGv$4aEMU&0%Io+)b|B*!bP4R2r0UH`( z{;L2dgmzXv$j2a~m7W&mi=|>!o8FEe1jbCbzxw>4x6szcb1RSJ9WJhTNlQAR%!EZ* zDUZf~#KPD-AkX0%TEBZRM)*7~hD13`;8}(;;$m&Hx}5^Teb-EyM!bq&aJxP;wi>fc z)DwdL%9yiYdFt_AOB9EX8ze|UWAw##A?TdJj3clz<*kNv&u=@dMjHz&OU7wkmG}#H z2i@k}8(|_~yR7wg<0&bFKPYPXIJzi(QKhpmj9pY%weixe5cn542y(@KM3;w27|aSX zu=aJycAyc9k8e;4;^x+X6G6A^{q-{hn&tm1xR?hx5GK0iG5h6zj$5^|ft&H7ZlA4hjpx4f zSp9qahuJZc`+(EFY00y`d1>s3_&DVw`|)kvXX;ykYjQ5`Uj9ezI_qX&OrELRa`2J; zE!L$e@h$hcg%phU`ODnt`JIs2ws%>Vo|sK4aGl#5aps5ahb5UdF!W2u)EvH&?)&zA zSLwd}AD;yp&VCqv=y&dp8~nX_5hq_?_IWJ&W=dee#z!B44w7Gz{@G5XMzhJFfV<++ zi)r5vT>8(jR`H|!@v|%Le^~KPQpge5IzNbW^kJ@)th!3{D*%DY_6I0Rstsyg# z{ZM^tr-0u>Qg{>!FZKPEr^ZQ@lYRAc1eC)wYpXV7e0ak;2o>)R|) zXr2TH%PUJK=MSqN_8xJWKOgAI*5k|BeV3gCx^ZF~_lM;VTh6h$otM7zR{gTN5Brz( zsf)T>`z8DZ>n_N7d#fMnZ%y(^aoYz>Qk5^yO=GM6y6p5L|Na*->WBQ>f|DhbkBc+N zpZ8s#3DPAq|A@TYVvjTN+;$Q%JGpo8OULvs`TBZUaTk9_oh`$XKiWSMZob)Pwo|ok z=VkVnv%XmY6N)~2M|}pTxn!M4jn?)655_&kB@w^mO!m}mX+JVwe%s>uLrZ?7dB#ix zCgD9lgXgvXQ{C}r^{tFW50j6x1G7Wz44*o&8hvs0@^||mn(aJs+^>GK;aRtRN`DvF zOxBstWheUnfRf3_qbHNk`;}}k{&5``ml=%RWEyKTP)8TewO4bia6P zjB6fnA~_-{)>g`QZ&|+YjbmTWJ$zBe`=M^`gZms6;fKUp*S#%SYj)eWD_kNoNMf47 c5x$nzv!z=CZbSh020L?UENY+x+yB1_0L|990{{R3 literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ffb21ff22457dac44441fb7e83272c72fbc4d59e GIT binary patch literal 12655 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 N?>yyS+aZMU{|8A0VY&bS literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip new file mode 100644 index 0000000000000000000000000000000000000000..17aedace14faf8f2990df3232565328901209d5a GIT binary patch literal 71160 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 + + + + Template: White (2014-02-28 09:41) + M6.2.2-1878-1 + + diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier new file mode 100644 index 00000000..ddb18f01 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier @@ -0,0 +1 @@ +F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA \ No newline at end of file diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist new file mode 100644 index 0000000000000000000000000000000000000000..74bc69317de4fc4ae87da8c71d1615385d70d1f2 GIT binary patch literal 340 zcmYc)$jK}&F)+B!$i&RT%Er#Y$;HjX%NJ3UT9#RynV%Pylb@WJlNytfpIn-onpYAU z>gf_)mRbao1G6)WeM@snG6NFRQ{x2$(=u~X-SUfa6HCG%Y9fm>5{ptnD&qyz4Xmup z3`|U&4UCL+jhsv!bxoX{O?55Y%*}M23@scDT}@4m%q)yTQ}g2eeBuRE+{`RpEuCE~ zbzNQE40TP6fZ8lw98GkADjm(;Tn!D4oE(A5h%u8h)KJez&wxln88{fk859`Q8B7=) l75HPbcg8&-~3o|P_8#_BY8yg!t2RA1> z2Nwq$8z(O(7dJN#4-Y#hFCQ-tACSonG6bZT8LXF;n}dymn`H3+0D~Y0gA#)-Goum% zlOQ9rAmjfd4Dvvqurh)H$hjcE$i&RT3Um?B9Y6(J1%S?HW@Z99mX!tQamHGpJOhg$ ztB|6hBb#twBD+$dh*9Ijg&fLG8xM*GUHqV8oK)1r$t5N(At|M*rmmr>WnyY(ZeeNV z?BeR??&0Yb91<+v*#~fzWVs- z^OvvRzW@073*;|G24;x2fFxFb2?G7a1dIa~c96dqnaV*P7i3{oG-MNU3}jC%6jm~7 z}foB?(N#1IuXW?>BshW)QfJ}f2%s+@*m9)i(RkPC|nOXcI(Q*T-V-RCl0FKRTS?3`dm>!lU;LCRZvac z-zGcNKQ2EWK3bda{GMlE)z6B4=FAO4AEOG`!0*0awzqd37Y zOeMz8aF@b5zj&63vF!)W-%@_u-}Rp%bK8Y~N`LG&Ui!oP?Cu(=CE={^R6@cGCe1#t z-#Bqg@~s{7nd%SP{;7V*-zVj_Hub~nhg0YEFUu~xbG%Swds~I>q?-1abDjkaf>Z6y z1LNX9nE&H6{y6d`o*`Dyvt%DDI5TenV%vOOxNbo^Y&%RT!}1#K>$zH4^ew~f)Ue{auE%eZIu zQRUh{F>~?n4F4Ijz4Xf+R;9IG-?T#G)sdC$Mt*W76t zd-hJ8c&L7Be|*)S-Ix9|Jm{2{ee+h#`ac7Ih1=U>cIDSogD)==b@}Zz1mL0Wi?~va`97y+lMx1V!o6q9Rfv9VrrtpaO!3fOI5C6=~9?2+{=+ zgixdtdMBX<5|VrP{^tIEb7$Tk_r007bM~H--PZc7viDkt{Fginu-?>%>H`!M06+o$ z05S%+rWfe?7yxeF0xkmpKo3wvxB}GR8#oH^ffWEKvnc=FQ=dik@AtQ-gX9T77oen| zIDII=2P{-HRHucOnwpA+j+Ty&j+T~|j-HW$j{XciEiD5x!x=_KCMG622IjNOOlQGY z#?wts*HZnnmWGj@mY(tdx{!YWZ1liepq`3C7@%aMpkkvSw*x{T5*mts$|<|2g@Tfb zng-+u=)&AXgTgapcD4yR0xgxL@#o^yoJkj z04u8a&?k)H%sFlzUOq8#3CT;BuPQ04sH&;!-q6!GFofPTGqn zuisPufWV+ zdj`=%!y}`A$Hp;p^9zeh%PXsExSid-{ewgN(eWuR3V`Zgu)y~Jh>H!xMG5MFn(h=A z1!ce~a5ie1i}JMWI(O+FcykCVgwk_fkNZ^K!XTn(isgFfGjQgd=v9mu?iAWT$o_Z0 z!v3F-{TtYSaE${@R1~1{sMr7qa6-(Ek_7(0)+U>iT!^a_>=oa~-f3xcsgk3wYuTES z)Vhl0`+HsaMsU6xBB9opj!q*QX?jiNz@LAR?quNg5{%OT2RFtAM2KOBm#RI_Py6R+ zW#*ktRfEPf&c2Sn^ZJoXvY3vDglmUnjfsMGV|J4l4z&rv!heKZz|khp70s~QnqU&Y z2Ujl5q>OD|sQH#8nF4(yy0h)xleJjOs#rBzVS~8*XS;azgKn{YY4)|)FZM;^L2a_> zEz5c0CEvDvi?ZudwOLnuy6fhLqP-vsQUMdB@joGKF3ui~LnH?S;w=w68TeTh?l)wm zFhgIZ@}a??&_jz1RC|yC{H750bCrVm#;~@|3rKY-7Q&*OBA~?8TiYtYyztm%U%1x? zIR_8uC+X#Zcnz|Hq9&9S%?_!+k%2cQGhka&Rf3Js z4N_5edo+K3Z4~+Ich=dosHJ3#Ok_m_L*bS{Uy&d3phPKz#RWR3Wr8}6nmR!)mjHfy zRth1kE03@DrlmTr7ulmuiVTRC1z3VSWzD)<`VUHGJPB~ae{Cfg`Lp?wu`Nidh? z(R8)i)v2G6ElN%NaGRuN zl}P^fXaDIB)%KChSEjxwojJHbI~4yohCv$Ie4<3xEz5a!-@fBqaY!$RESeBLCq z9R;LCMQ;uu5vJh3qZLU?x64AO>kK9^BzzXbe@|^bUHL*R`x5~Ho8c@9;`n-IHenF# z$VpmKwPpWGy&L5@F-O7^KU2D0it%~F|Xi1=&BA#VIv%A3Z{p39 zZ1?^2;q+_S2W#}} zy3sb}8-A#>jXK2zFRHw833=5 zN#YH3ae+(OQ!Q=YJD7N*50++I3_tUct$l+g#LlbDM8;S$5S5d7AdtF>1ee%=ZUC7+ zfro;g5b(aZ#@FELZG|#^TFYa$mM;lJ1GM{Nm#yks>X%qCaa(csOg>TL^wJsa_E31k z*uyWj0)G8SO6TpHIs06TWB^-Pg*s+(MdG=I$N-mZCL503jgOS(z6fZ2BdG=Us8>bB{$>4G->5r1t1 zc$nWVN9_njkO8)k3&_?#>H4_0&uB=Y)IJ(+a#NiiodDYs=R}nvRkzO2-bDCy?Ube= zVi}Y5EmX4uKo*(mcuzCKhAT!>#%u8%l1(%lskS_$Rb1F_%Y| zggOX`OO3tvu{0+IPrLV6UJ44=p%;ULQ#_QG!}X4AloY!+Ah|0cSCGW#!s@V_+x@G#5p+B^U3Y%FShpdLtm{Ie6p0) zfEW7k-Gf6Cg9_%-RxVr%-Z6r$WRDAyZ%)!+?ojYvgRlB94Ti(`%8SQ+s?)5to~8O< z&JD;+(sHNI{OgP}h zZ58I7-U%W+N{qSbH%Vw)Zgzo@7vnh(6^W{kAM>n0mF^;E<1^2h)Rp1CAt$O}M7?0o z*4VKkT|5+PL-{z}lQr&%*fGUBapmB2 zF|iQ{228`fDkNL;8?(*ZpQHB0SXz2Jgy7yBQv`sbO$rNUUH@#=wRf@0U zP_t0RDG#iE%s_LK7%pMVd2S&)+DKE`pyNxS5k@b4mJZ%c)!i=JR99(Mto<}e`Vpc& zR6+)3GsY{^*HKlgac-;5m)oVh^$_M@k~v&F;4V*?G_ru zEf{8A%l&yxtY@>&H%S1#?}(9Txgs^Y+vOC4u$yM*l;p-M@T`W%z1@ee2BvY@U&U)b8*u(*pH(Huh6O=ZV*` zun2@oUM`7kRCFjmeqlnX@x5>b&71Q*_s)mq_C$SKGqsy{>7Pbnp)q_5dI2AjH~!v1$({96kdpiabAoJ{>kHq%WM2nIC7*)u|-&4IagXzR-3 z#O1oQRYs_<$ctiI08su6Q2a6L^DS0ZVcc-7S@hetWb#l>bhC>K2-pa52$VHIHwMoY z9fgRmSGbn*JZj85)>C2seKC%LN3%g-@%usMM*{;KD@rxJ44IqCc};QoTw|f4bSmRUT5h0)0=w1Z#nG? zL>&dTSz&2r3LA@EsC1vhSrQbrT4UzGhKP9IbDrGw+2rJdN|841cOGnI#Ja5BIY z=*Db%jJ6CCZA#l@h+n9Ga$ysY9G3&ic)o+2-ooDuF68UC!98u1ZqIcv_FR0|=53tu zENvI7w#6PU!Dec8(_N{+F`Xqg?{*1PD;=#nOK9LOzhIYpzkcCCVuiZD((xNmCAzpP z!~HG68d}%qT(hfjMjamSI$lYdo*S=QQBgeqEWzRCKd@m9|Mte`CWJE~{g%y?)y#Bl zFqSLTM$s`J;e);|R;*4X`Yd|qshNxI`@pt}u|nhfbVcJDY!)x0|=Wxlf+ zXZfeiJ^U4oBU8^Ajl`IkH4HfaV?)kJivFnfC7>3+@ z7dTnBSH?nkK0_o-A!qW*z!~7MEbQ4!djtdrH@X;?U44}Cf>B7uIO8nj@=-&_3}vyV zQCQ^Zx>{x>jGo*a?MGJXm5_39 zmn4*Hg+~TQ{L?JozBcYOXNnt27;JilHwEzan6fLiWd|0e{Dih{2iFL*#j=Uu1MCR$ z!8WDqAYMcVy&q%L-Xt>Y$oyHcSk8d+)0^>EisyE%&cBd*Hrfk@7$h*TPhD=ArX~YT zrwPmc^8kVskrHo#YsT0@308rxH5DIZw$$)i8XO*LXbh^GgEPN)32Wy@#x$4ArV!sBjJfypr?wzodR6X1 zyb)?ICNj4o42jI}Fm1Lwo9jHFErx6nf;gjI@<~67?LZ3RW7}#J4KKcP*R`$=eS~m! zOM2y@x=dLYEHtKgV1#zh4(pmf$V$RK>S7^^oy!;PX7c8Z_LR=rTccRJJf%69?pET5 z!p9Q_8a}nB1burbUw(VSw*%6t!J|BbwS`0IbL-_ugCapbq$hF#HBNhC zQC=@UXQUK^L;F1xD8WZP4kb{8fI{Weyhr;HLk8ZC);Coab}zP_34Hf^sm^!6oTs8U z5IFmc0$SWXrpsDJ5+hyrnqwHhio^M!H`}o2KeG`;?&djXv)OG*$CHU>k``2g$lW#f zkRz5Zkahkf9qe&v#;K4PI0zaDj=`+&_-ZirW)1WiT+`(QW7&>kO6N|)TYqBO&jzmA zL5Ol>V8gS4WCUL(bxJ`N*weN{_TM5uN^?94%3?w15O*0%& zA)G#*gLL$d7SRYn&@fi<^Bv8cjT*W5(Uv9-QtxoJq_i`f`x|t?Db8{7^@7vSsSLJ0 z`7WEFlW>TmlV|$;6EM5|+u=+GI^kt_Is$V@cg{RZ#1fXSgJSNvN8gS{x`2WStF8Lf zZ{D-f(GN{eaZ-Up4B_$fcxbbwD#O>IUvaPG#n8Rc=XNe-Ak9d{st)z1tzVpdS^DqY^9h4QQdzwjn zAIqVcSd2CtBcL|+u--fEtU+kyW;-GS8oB{_`2L$9vC2t;@+yT~MlCgN% z=FVy4oIREdfcTPyhzT}Gtk)A1E?Mv#T^2SMc5LAdqXi76&ObdK-Ldpen_HQ`+{$GG zT}l2#itq|Jqdc8msZB1$ZRL0>!tcL219c?YYi}`w8L-Qee{)r0Ed0a{Q?ygh zxjj)fRksJ?3OgZs07>W&Ayj@UIIWvYm<+T$Cn;w*8)JcgaVXvd|8^3m=}_NNGpL_X zc)gOIZ)yC9$#8K@`Rfxojhy$6yhnVELrZD`v<%mEx;__Xx~8D}&1LLGV*kB5W-3YlfXKC@O$M>e+SHB_Q)%?M6;-D2F9-@kz zt$91&LZXSuy~2wVY$E8)Yd=z*A99MAhcP152CjOt;bTe~gTedg{#el2UtSj#w%$9s zIchqKE*v`+auIIfVh?<<&7CKdgf=oz75nPxEstrmZQamb!*?aoUhm#9e$h8Cr5@DO zzo(GO)MpOz0>yq00X#{Vl@)q>-dAfG%*gG6GIe3R(TRboV-xx_H%9DSek z1dc02NG%TDHhPp;Wm4eksYX{`HY)ZHX^J>SGCq`JC@?ESM;7aT$H%}>L7Nw!4|azEj71?7jw3sxR??_V95P3Tq_vg1v|hq#yG_(7BQK7%@3g z5C)mefKY1E%#~=^4K@kjd*-%{K6;c4ZrJy;#@$}L!mrFvO%=}bvs8B9nM1sZYi02` z=VyrEV~!8V*PLk$x7|sS*fPA#>zK@P+#$vu74?)BT~+5th|}t9yHIPU;NjKO$g(3f z{}M~Uv@2KqQi=5x^On02r6pIyDZwk6ao(qkmxpIfA95dbFriT7Suy~ZVph^t2^8tz zdzE(AzcNz_y1D#Hjz1akNT8%T#BB1}XgmvEEcpj*%nXTDR*0B!|94Qr9{;I0i{{EX zO3qs5O*L#J>;CNzROC&WUw>E_tioG0s+b0!GRm&i-L?6JsSTCY{Z)t`-gpq)o&6$6 z&^P6rX^{vG@bW8N3zfhBTR}G%-HISD_OPQrf*Zw*(D6n3LL#M&M|SeN-Q}-RD=z{* z9bGjV`;goS5`z<#%H_(eY$TP4>h3lqXJn==7B7MP(f^vHfNnIv%tU0$r{5VUJvTSx zz*rPHXmO$F$oTKW0_sO>ahrDUF^xCfh|%tzQhPg^J$4kaW--H}r618B_u%eVP7wWx zkl9&|*m2z-M?$+-YDtMu*cod$w~g_qy`uE!dvqF@xSR(q0_Mw~L~u%kHv}^h7}GK% z;mdmw2?#o^MI-DcpQlud|vUzCVH%SQdK1zCE#dY0lG2xbd)qznZvA3A}bX8_B;0;YB`cxo`L zC}^L1o)6mk&D9WgWQ$4@J&_wnN|U%12F-_CK%~R9DJ}=`{-mSh znu?r9H0ANOvVI(gI}IZvcfU3XEt#*Q3)Nb?^Y??ro9hvtWPpxNh3Iq`uAm-h3ZAwJ zR!Z226z`Y#46AL4O&CE8apj~!$z28vwLM>II(rwc%Jaj68+gQP(t8{mz;rnLPJ3MD ztBj{g3o#(K0VgO{R)iQ%_fM#|SFrP7bNa3}f5$_dS;?)=!RNN%aYBHFBMf_X-d2RO zurchm+#3_G4G#Xb0}*^U;!*O$TE;onrS)}UxVoU+^N5AZL(?)t+n?h3r_4-~F46J| zuIXFR)cP>q-|ZhwI|+th4P?hQEm(-c5Drp^_d)vG*s}9?X0QgxF&qyCMktCpVSH{r zwu=Y!MKb~70Ac1xa2^K}c~<`vg5@CtI|d8X+QLKbj`B9J89n|aF?P%_^ofTm9j_|y z{*T`lFj)KUNb^G&iGGuymG6s@jiOui_Cn^Vo8U#7H;#D?P6_wn#+O1=x4ex`%sZQ_ zg}}W2z3e#!y{gN|S$Q(B&>x1Jecy}3V2~__2P(v4@N4y?)s{r->oG8M(^czCbW>j@ zS(hM23ECk)X6PYKNI{jTCe}dyE)_x1sA=0^sAuC?W7up_(BtcDjFeWve$+c^Wd%gG z>~2gmtt;Qt0kbQwKPdN^FR;gb$q2F7PZhK`lWwcGuxSWD56J!@roa0Z&D=irN?z5v hTTjPe8mf^$qfam(9ELz3JP@`hcL*nV2R?;Jf&&6!&td=9-*9r~aQy3g z4%S%^<`Co@gq@9z^~Dapz>9;6gZ0|M$;rXRy@Q*Zd&iC)+&uie+&p|dJ9h92@bdBV z@7%eQn^$0$z|LLZEkElftZO;`T+7AJvxA5K|MiRc4YG%agA@jCZS-rM|l1%)3! zm6caie*RKb-_Y39jQifw+ST3D+t>elU=Tk+n4FrPnVp*_t*)(akT)q?+pKx9K{)R38p)(fTH~fTUPdwleIh*vVw2oKqq$N@G z=G{&{F?luoK@w|fe`fZdn^?sE)Xe^EV*fs`LC8)HHn4acdmu0fo%T9L3G&bJj}HF9 zz&{xH2Lu0L;2#Y9gMoiA@DB$5!N5Nl_y+_3VBo)p0nF1{ImVE_CS{9saqS!ILwgoy z;;m_&6`^bUL-s?SUejccdBMqjy=iN(hIdnNNEH_h6~MZ5NX>6smD!rlVK`45YB;~P zhwp=a&Uce^GJFsFQN1&I^Qp;S zRBfF*_S2(lwLMn((L#u@UhktX5u}04heBxb>Ez=~NJ0z-MiVxh*pYWt81X?R!TlU_!>zWpt^RHz*_Tv;C{<{Jt_F7qP`YLqHZShP;8x zBooqL5Yj8m2z?Xmz>O!*Z%@Q%{l1$!Rm?%=qC~%PIAKIR7lMzTj18AWC*?alwVjQad_a+;%Ko{2f`S@PM`}N?drg_b$S3dAAM$+g zISgICX5)h$f1a(W?QGyn8f#o$Jaa4LD5vQL)DwnQC+mr9fw2iHFa~clVL>Z*m7yIH z$*KD#M(Sz993$=I#ze^&ko-8!EUv;_srdVQZ?p-Qf^k%Vf}O6sPUKZ zJ?pCn`7|@5Tk>LLblOH&Hog@HpLb>w6s*X z${XeBXGhlHE}bSUu`l(2bI@3k5?LV!MrXFV=i|MQ;vP5DN@hDu?ur$ekJ1@-L$9Qm zM1}AE{Ec5_IF9k7`OayYY4}5feT#^9lr$JcL9j74mA?St(aU~d>ooPsedG?mn9(kv z57?fvA!ljqk^n*KiX7MegjrQaTH+Mk$-*ovHWhj}1jXQ8BMF}S9Lfz&i5%&Xx4Lgu zAQ<$GVVy~UQ4}#vs={p_eG_ZttIONZIv#Aij{0UfS+L#TUuHSuJZ03>hb5X|q?_vv zDTI=y6LIWmo7@}=n|DIAL}q=$$jnXsr|&N9+nk0UAGcX|))s6OwJHsIu>aBhPa> z*8pz8a(0Ypx)QA|0-1xAamRQ~E^@%`i`|Jn)1RurI{P8iBDCr z*P(IR2z<2`^=!ynygz#V1xAj})%NfT?Htg`BBgvn0*|($EEQk-@eo?=nYV`t`5MiH zz6si%p4sjn4ES>ci8J7wYEt9jBpj)`@eq$z{ot@b?PsW0la3wmX*WWqC+m+e zv?vLIao72u_~@H$`URl!!qfj6xljXxcZj5O@sYt>;8|27752JZSbnBT&0Rv{?J9u< z!1kIHgjYZloDL+fF~W>pVK11FaQcS~s>UCeI5`BTD9$tqe%KO6mBHgJj7Ik4wcuzx zqa2AIdC)}(Qod;|$0d3W!r)+SsQcTmN4P&q{6>~<(EqI5#E2P#7eg|!>Y2(|A*6ls zn?b!#GyFO_+88>M=+zr9$l!fJ;x|qY$KcRHS2Z__Uw`3V|7uS?9D`WYvRJjH=@dAIJQ!=VjKhyu3Q149$WPTYDb<$xKKYc{=Y$hTM}PrW|6PV-!d zIpqIg%BWcbMKnQ6x!D%`;jszG{S{g5_E(o&AGd6}RJRllVJM0#P5edHYcRJC$rn!% zIR{%Y69&s>eYK^3BHtE!2U(EP6M4Z0<|ep1*40vTtN-o=)Jnms{;MK!hIBmX=v0DRgG$-5ElCrNhhOhBV|j7|;NK$rX~rKamEEc5DP8Q^M~nlCww+>x zK|rl0mWe~lU@_H^E17Ta>c3rpMS3n2{+)3*a0|x}e&m}^5g{byndErSJ0fV>PFQOW zaBkzz^q`08PW32@N8i{11Ayj?sm)Gem*#1}GRs2!kB#dY_79(_Z%NAYc8gB~?kac_+?yz(pofqy5;vN7t z7j{vaRAg4ejw3%H2@j=2to{sI=KiQQi7Zb=fjf6oa^HCf8wZmb>|S2>m;b0Y5UQWs zF|&p#SNh}1#RmY25vbdp&-JxDf8C-@pYl0lvBY?Ga@!_#g(j@rY#%AMLKurvcp~^k zUKk6DpIOIX-u-c8XS!kIndsf?Ic@ojU)jgX&unrYcg&yWnr$+LE((y4eYOrL5Paf= z{i@Cd{iJXN_)#Q5dgTbjCiP&6moPGpp~=IDaFWUJCI17So)4?3l|y$u;z2}Q!~JrK zg2!(UUxh8mMb3oK^m{{oH+i;rDbICO!eH7ojrTauL>o;ac{ZB|&0h&A|XAeb0+BEI)y3e_;Ar~ToBk5j^H4rBeI zhW#w7xtTG#M!rvCAF3KZma%LsMLHP)D(tjg? zQ?GoDs?$Wu&h1Vuqvz1zx8GdPD+}I_OwZl2?O(TIg^p(df5MBNEafK?A|ObJ>@Y9A z%pV@?bPSeiOUh@-l>Vf@)hv;r_@&&Z)KQ+4*m$sAiX^&G4qV`t1<3_yhJd?~Izt&N z#vMTvn1n?Rh9?e29;PSKgrUvEqB15#25}|%>FMJR!_Fj_*K}`bVM|ykUe{ z-Vmhbg1f>pU&GxKdj8~+@?uq*Fs!*>tW6q+TiN@O36U%l-&wp4^&)IwFm8WVSs&Qt zc!rE#mm(7q4FiE+Y_O?+)7()Gng04c`nTZ3RO)wa-zDLRIjb+vM@UQvo2HlYzj!fR zKa^#nj%D%-T5_vM?T`pA z7@|qwyYf0HEF|d4i}U}QC5*q2Ini@jRbMZp*6kbKr80|%lIobd%(59KWKTeuvNQE8 zrMcIL=RnMy(WI)O^1|RBKlr^9`Hcw?Um7690-s^`7-&6X2~GUji5vHL2Ed1szL=~- z3nQH~JwBqa;2Ed23G;5*?*HBMC&Y{W2F^?s5$<_UTK|;iQ)l!EC7<9#S_ZVe!Ug!{ zAjHKU75o0H^j9<&mAA)sU*eiO~c-RR-?^0%qqm3B(~%f1}1_+(CTB z=f{ct-eciU^APXhLdmOt?kOQ(4|M_KIpQTiXR< z=FuyNU{|o}&7`tpS}BB%nB?1>f=5TkRSAq2DOXg04W!q?Dx`8K_+p&G%6R0Y-vYWk zkWBYn(mu2XX8zq4O1!ipIdVFQ<EHlwetD!=Ewb-gE4iOw>@1g~1u4hd{_nx7?VJo4yiT zpdu<|8<3 z8UQcV8ysb{panB-2>RU?{sKRJffzevYJBk$6LNVmV>-PKLn zHokgmOyy{@2?;!CT|GVeTV}(P!E=CmCS;6!pW;UnTOhc`lw(DP-3L?O*nIS`HPvw_ zGB|MkaTWV%#W_cD+P)$tMAo(*zRl>tu3sy6WI`T#!6u*4ESQiF<>`#*Goi`44b4#KLFEAta4(ILrG;Wp} z?Kd|OGTWB|e>FzDl=uX>pR`F6cBre}Pg?#|=&8NYob^t(>M^}x_}V4QM zpNAxeu-DoH4W$8v!u1a`T43cXPjm%|^=);ZW(U2?Uw)`zWF4uLNE_9X@_#=s_yf0Z z*YOR^2bSg&2WOVfQFqKb=};17vc$?U?wd<@(~gyCjN|kgl}ja_C#I=)D85{uJ^pU6 zZC%wg;zGL#Ab{2Z@kHN&=a&R>ruQQqK4ULB_Fr@IHZ*C z4ljpZQ+O1qpTSQeVQ{soUoyvkY#TiYkbfF$;#NlSEwR@hMO5<4cQ7XQFFowp=#6>i zytmkg2{{*&>2dd2b{ZT*;~>w+(4Nv`VdLX);UUVJ*)Jx0oJe1f1;w%$_I6eG ziv-<)*JdMayH5@8v3TYZxylahh7W2^TpMeE4pib~juB1lhT(29(lxz{_U0}T#K&claNO88y7*awQ3!C+c2xjGR0KuOFLMx?(LqQQ1wx zZVA4|?xl$`AzWJ&dz6HX}|Kfh6kIZA+@Q?=H|Xj8tE;L z9>%SH3)1j0=XIeN$|i%C8;rC?nMnSval~KGD&r8B1 zrulQLO(z{&@z>){Ui!u^6r>B?2w8#Wlv^LF3YuOhIQA|-EPzkx^`|3BuVWzpyB*4e zm7&i++jEpP>T@z{#^LQhPi#EIv`6dzcYMk zyFNzgoy7PU(aO+;9!DMxyXr=rV*l6T%J1 zmhY*=bOyFul`igW3mYF2+&TyoK`p9)=>PgwA&PhxLyLytI5B^+CLim_fA~(cnyoleRA-sR{lTPBc#3GSG~G zElL%l=DbIcw}H>`$4<#H07rq5)?`91OklcIDe^el>&!YRS)doTUa|ZUO^cb|W~6AK zsY|d63=0^){@xIwnThm9j9`eXVL-xKqkUGz3y#mNxjzp#zoD{EU~`y|D3C&$ML>7y zi#UWBLL(W%y~T2sSABfdRZd7{F3jLgwA`78hsu8#Jbekzejma>B6rfxz<80zLadrh zxCav>%VSM#TiSJ3WN)SWgt^{^NitHA60}=HTr)J%M&>vru=uKnlT?p)ZLjG1-9(k$ zJ3l-{Z+JaFkow_D!A`avRU}CZo55u!pG99uO&J|!Hb1jA1I$vCo^gZ;xs^D? z-NfJ{mcA%6(aQbWt=o5`&0E*=@PV7g-kCqb5*2To+0!r6U+T-jY34wiyXLi{qTiet z8KiJKc5S94cMjqLeZ|6QpPwQ{w?J~p1=6!J^q?zwf`ocf%@$O-%~cv@(!Fe5Y2+te zeKB6%wMs3*&}w*hSpOVq5l3V&A)sia?Y_;xImGwPQ@`0Szm2X$AD%l}B1;(6GH0l_ zDJrJ7bhP!mJIr{~+TXo98SA)N^RX=;R`s#`6Ot6;{M@hI=u|KyLfNCXH=_SSB=QWHH z!;5i;A;E;SxBw?dk1WQn-|JtBqKTg*2Qwj$N2t5z@3p70rQ1@%?`BLMJU#6FZFSjJ z@0sDW6%*oUfILV$^zPNpST6(ae-}HBlmlqy)YpJU!YkFZxfb82 z>FabYtJS~3>v!&@p1%}M+W8K)Q0xWHs$)W=fcCE=f7|;$@=_Rc9oLgR_2zO*uz&O< zY;$2Tcm8dyCrK=}kWq)Npbk0mf+Q55A7km(G3@y{C+k*xZE~XsHL7UT5aftl{Pfyu z0UK2bgbCM}7tb^#O{DA;6csBDR7&V~c28YxF@F}+&)}kmqK6F_g++!=a3X3wbrW5T zBA$Z}bTfdN!`?1vm+er2PY5)4rieM77)qKNIvQ3GkLYAVuEmEZU8z>b52^Bm1T`2F zCwV>d=Yl#1?du=%@3eS#-dvCU9rW?F_ntl09$G3@_f*8k-OuiNDdI#Acfyc>M=ww#wu67WqOVth_quzlb3Jp7VNdD{e+1DE|BVtt%QAhk#s3;J3eDc z`ogudCz+5>lAnDJd4(4kh+Nr8>YykI(5iwL{Rv-G^r=_h7}5JP)O=}y@t(+LTeDEA z5=}ppLHxD!G+dND@fROJO+?JRXCAUy|5Oq&c&Ls?W+jjhwb)xs6}-mZF(CJCmyY`$ zMfzGQBlVAK2dl^RjUKNr&-g7PMhW$$YE%3fLK0=lU*}X)sAv1STkM2(M`;S>cs=v| z`qDY$6DVZP(-ZaOkl*2gh)@?mlLRyNEEIcMlxMfYDhEflz9(sy{;Vz$=el3FzkfKu zDo^v`$%sJ*hTuA161hZxo`r?3xlUqeqP`5?6jB5E8NHllG_ewq&C3`hZqSRL-MI$x zx2q1mZcDjFGLHQ`gq?5hR+BMbu;bZqcA5nd)RA;NoP%c7ZTMm$T)TN&ITKda1benR z;&|cVkLVY>Y|iT*=TKiiD5^602!tRPIvw@%*~olzrL}K;+d6CqO%O~%kN#R6E9oxg zq)ycOweI=#_YG{1;itEbnLHBTl6?;y-83#W(P)|^aHL$(R|fW|$b`5`ypx%xon~w5V8-j)M1p|7jHi6UE+OLMR7N zjqn)Q?sd8exuEM7(Kq7#q}{Uj+t26Tc@*wKJSW6QKiYRAi~Llum3I>P(+uyeJyXB( z+Srwwd@1d1<6z-Z?Ds>T+W54Ojvmvo-ahQn6PWwGFDoJo=6W<>gHZt!U_v}rC<_Xzp)~$+hgBTy%iv)~I}<`QFiXHn z(co|G5cXY1s|E26HjSIx#Xo!xRy#bnRatI()G;pUX+cukE+(YvidDY7xv^gO**tZP z(a|Wp*(21vW6aQUGl2Y3J#=D7Ru&9Q@;E&co=Um>JvC*z8NoRDFtI!1kVVnqJ${L30&0!#mvzS7Rho+LcaTW_`0(G` zss3O6_m~9WW*pd2-kAHsXUB9i%6M$`*qy!&(9S_yYa21KFyAtFm`}$8W&Vn_cXl)^ zAj+a2A(#+YYl&2h1Ju3KK$JsQj=^`s#|L&3C9yP*zKLqx9#gNO^4Vva4G4ZyqF+wK zfZdprnj3|1qIs4u6-Cw{^{};u1|>O82CtULrb82cAk|T1iLX@O#rSdYh02Q;n2?p^ zHu~Y(7MR<{J*C%ga{gD>^Z$(en5S5uzDU&}TQbt!)>GO}1iOjtTB=X{ma^5~Urt(C z8go8cMD;nrS+J*!U{}L&R0%`xfR1phva|;6z$bYrN7SK@TYb{|wXWSGC&%NIt{}^XN zhAhqIq{IE-P{y#WOMD zA>%E-nmk~_p%7?6@!0Q-Rppg|lX&Vt#GU{*XV{9;;232!V;Vc2M{I#Dni0-G+VvZM z=sjNg0&A^gLT-e(RML|W?3EsS+MmTip!Ie!=%x#>c=&+gl1wQ`5ky2R3?Tp24pEZr z64hT8If7zO)5WXvE5Ppt^3*ZT*7jnOP~QCNSbB{ZrucwS=x%^>7 zs|&P_-{@xep_^|Td+v?ug;jsTQ(ff4KW?^m=F zbwt>5Sr@$fN1T7O^Zx~Qa;p;zznxMn-TTwz>e5ksWRdo@tz?@B|1^tK*r*5_GDazf z{e^n{>66NAbPv6Y^nfAFG&p{rpw*mRQfqtg@XPNb;o`r|cjREto*MZh(EAk~wa^{_ z)5*Uu?F-Jz(47Ycardu5Eae>$p$_1v_LJ!udeId{OZjP4E8v}hQ;Nz8q+f*wu*&&fb4m@ z0yxR++_iZ_hqW)c?HlT(6`ClH!8ZhU(&ZWZLKK_yVMJuX1pQ=F)e2d+C4V%py6>>8 zyS=ro<-r5y_cK!zp~n{BrU+F^K@QEG;`b`#D;}Be{hs3ASaEFL-h1QgZJnY}b8T(< zxm|*Cuj*dwuikY~be&v6wJ^e;n~b>Y4OXq!U{AjLJN#NlB+OR|E`+MPfH0-%s75Xy zs3y)tEYWTSc2pD@+({mOFLV0gZR-bK%cEy-7dNr`S?I%PqcB8fEX@jj06ywBUyRBy zMGBl4%lau3Tu_*es<|`vX=Ul;_}E}dU3%?)3baV0G|zpod^*Zs+5V^3&FZojud-!R zWJ?F<4afPibDp}ZT&r4H?S!v*uAIB4j5W)~teP#mz78GkoVk}#FhlK}`Nf6R$ z73Yf4AJ4jY-DfVzxW%w#!(G*;3m)bcg^ z)Ct06%a`uOQ@3lq^C)lcb^OsK<|zYsj5_;j6)F_j1l@&HME2T?735KH6PM9912AlE zFM7(u=ohDXCN(r#tu>$jh{4ElnO{t>>x8$;g2MF~W3U+SLb`(e;N4G?d(Uw1#x)KJ zF5$f^gEPq|cPvo|-*GR#P7RHgB~QM@t4u6X6$h!PZ~e}vYTXPy-IYt0f=$9gH-FKE z{{<{qn(z>V&xE+f;4>nAGA9Yv8TOXd*fyl+n~)SEH;Q~edNB4?OZ?D0Hc8NN@GLkS z^l?&KTeWs;eTLU6D4CI6u&rJgZl0^I9`G;lx9Zr;?I=+C_XRaVpBAGny8)ZIvPPd> zn`QrZT*-t({^M0S{K#On(9ySrp^Wv=b+*6j)@ueEP1L`yvh|+<&p%`RKj^T>ER-B> z)3nC;cn&xA;bWxN*u!LC7y*Yj_S*7F~iljR-%z$1s-4B@Sw zrQWl4q#63{l`lQHs`Pt_lz9rWI2VX93vO&_dsmweV!UflZE7>+=H#&5u<3y|Gyg;S zLykFg5nC6R^{&i48CW^Vg>VRkqRRwu)Nudz1MXF=yh&Fosu z;e0d;9Y03bLq}7sI&wR5_;35(3yvr;aq_rxD>V|4ND(SRX{eiY6jXB#mB-&=Lb}1x zX?$8*&z}hqQZ+4!61n~q>_*(DOZTFR14LVCcBeWQ1?lI#vFjecxDs_n6SWH^{vv$E zD9d{1Ul0SK3M2peI3SbtIlVuqubF@QDU5tU_PNZ>3|-_AaVF%pn#6omw981IGb8gH z6OwCrU+3Kr;`(;X7C*T(A{^9sCPW)Us!KnIUJ)ue7x9g&Am(>(B>^GeBipuj%afE|BhpW==x^^MOyvYf1Q6~+Da zf!VC77o)x(?nO`1WuK`?1GNg`lj{0=6y*?CTvgPf9U-7BwmmSW&$2cq{pm@~@j^4a zEovN{)B;`fA3qbg8K08Gn9Dwkef6i54;mA4@F{wY-u40A^@ry3vuyO0vMRTaGa>nr zK%KsJwSi}hW@c#OMwiM+;yCEC~ zie>P79!0q&{(gwwDv|VM#CmM{QVy#wiUWd_OMsrHF33AHTKkY-Duh=b+Yu7ME2$jM zeYLX9;YYIKj~KJ>)KI?3xDy4Umyyk}1)do9gYuPrlX;adol3WG1`1jR)`bO?t}S9{ z*AAO8#X{s|>YEVXh9b%$Y>r%!fL#BAxfv4{paJ%Fcl$&n57j{Vg&~?$w z2oN&PAe+&p9Z!(E7vTJ`@th1V*6 zfr@0}m+JVBa(d1D19ci1<|zqPY71AY(~Vr(yn|8~mqI3|ho`$f-Hi#hFS3mKI=P%h zR|yXUT-<5O3W>x}M>x@wU><V_naW0yGIo4guD{cjU}bEZ68% zkC>fYQg=r(_l_|E$=Jw2HuK&&H1Pt4ANdn(0fLRmm`ya%6!TcPGLj~o)AR~Xv(?w= zRrl2MnGfBcS~jE;R+*+{!O7Q*clo~B!!;oLDHu&W-4TlvtEPyP#OrNp<$t{)nN~KL ziJNJ}Rdz~ICKz3}*92;psK@19gO0E53Vr`F{51kInkwO0Nvn=AJy==QJ#cN%*deu8 z>dKVZL`M9Dxtf|54a|J4t>1EVbvRfwtG+-uWxr|S5*M*`=@unw!k6D}F2mE|jL2hM zWB(KGxLZecD^^z|jefV@Gh5xFjxw|7Qx$UCpoX z>KXh-sdju`0$Yp0*Jp(vENvOZYX0nb`U;c8&#_`^8Mv` zwdYHdpZiij+?8?2Qs;YmocfkC!tfg7>(91js&5n(yJJu_Dg&d@Pxie1z~F|xC89Oq zBV%>5vUe;qEyZ4=CO6o9cw46#RjIh7jE4?bk*`pWkJFJI*7O3byMX>RBXiPaOrC?0 z;G_3qu=0+(yOjgAaAS3f-Oe|Zw*o3EFLZZa~E(R6l3p$ zeztO5_wf#q5Rdxyey7q)QZJ6Yt%Pg*XwIDCkw_3<(HJ{=O_g$Zv(cF<41i?-bLkl5 z$B}nod1yMjO2@Gx9u;Kd9pVi6k)O)@)g{Y?Jppwt`#4=BPH=g5P>w)pqTJ);D6j?_ zBy1E?EQHX2+Kq4_p-z7$Rz3=V@_YErr*AhkzY=yZlJ^_@s+m^n?oDIABAdKiXnili zJk^7L>{(tO#uXLB>+LFI`?~+d#>EZ+!O{A7@0+<&UzgEM%F7w)C&mm!wim#5THR&T z_-ob!9p@(Czkj3Zl*@}X%|6rL94VK`{nWQkQ7jLc`uHi0KQ?)`%ZPmbONRf{OJOmI zgB)$F&V{oKUYaq5n<{{i?1Xt>V}nr=G&>k>h0m!4WA^&Y8y@GdrXlZryFVRmJUn?^ zOQ(YmVgWYK`5dm$Gq7Mo=U~)*gzwbbO1z)|CEcXQMoYKRTQtCX~29WQsYu{=SyCF%>!x0QbHGK0$3XHQO4(nRDY%xEGf$rV); zDA0Hs>0o*k4K~jI{T3yau&RX|Pw?mxSD_ ztjlYrMw)0J&L`FM;5jRILUtJKDa^U8n^jnp@{J>gmP^ltxs04-@JNvQf&VQNU%Zwx zVu#>QYwxbZidXA+%cnd)((tIf-}F(J4yzU}yai0<4qlqF4dVnnBTRI+;m%>%ce zx4(?>mYzx-DT}z^gHJm5Cg}q{HT3~!Ag9$^?A`av-DT*_>aPYxr!Wqc@&k`nmVDMt z!)mj_Z)GP=_P*}Y2PI>~XJa%)3BD*9t}p8W+diA>&*0AwRBZk!JZ`kOko$Z(oq%if zEQ!i z>%!2YK>XN1I)17)dZ)L{dCBSW1KDltD{)kG4lH0xlR~f%hM1Q4964faDErN$)B9@0Q)~YYl(0)A9 z^(OsrW`g{lOXBjbQ*m+LmZ%HW^EB3ua54pJ4gPZmfV_g>rP_OH2bC5fq)5S$+zpr~ zDZd@m+d|yJ-|% z$^=@kft<8}%@dHOg|)#ofK9Ro6l)985t27n+_l57ils4IX(vH?~1yLO$w2?(Lpc$_WrL=awKHs-Q%jg{_a8(SYV)hOMxAZ_CNHF0vFyHe_Bc=aEDhf>$Vy!86-aa8Ep`ZW`6tUAJDh~A zsKt&vI+hV{4=MQ9Y3OA9`;`8N@2&OjnGS|P*9W0=$+8ul(ZU5GpE6)GrXX~6#-5f* z@nyWykEqqASFJ1b!hEpzr%qDaD7@PSq5GoNe}>2Y{rEDy{Pky8rT906^0VK@J`jGH z?m@L&2DM5yuJ4(J!RZcpdbO%))Z#e_XO!x;p>{Byrbj`|_p%?Rox@Wj}Y%z6w$CK*uNG$?=`R0csdX`ywfkh)&s`u-lK zFm*-9PADG(O6j+$cydmZ{OOg$wGsL2llwEytCk5N9SPZ~b1XiE>1AWI9gJnVvQ(E9uB#<7rw~+wMc&sI9^mBeTGwVb>$Iwu7U}9 z0RO~<#9K9@IrRk*YQ*#>&Nde|R1_Q1($dX~!twhG_TJ(?b>PDHi5gqrcVD?}rHyac zgh>EK(-V&t3u!w`g2o_pUU@hjAeO$It;!pDWaTtF9kAzzw`-s(_w)P8i^^XNcNxH% znGnHh9g;?USNFu_hq)n-Pwoy`;IlU8^#=Ce+StW@t&nQo}VP! z248`Yg=@by;8G!B=laxPI~~iX6GOvqh&FCtT6`?&;4W=)cFNfD`FzlOPDA3@zlu)Z`|a<(CAAu4@}Fyx~=3j-1Fac}4k-{DU~Al&TvYc(GEz$Kpx7Kpv=@h=8w&h<%MCb;+t zh^Oz^2Qm_M`U+XPVe|TFl(k^33qmWT;x?e73bVmP08s?Et6noOCg6$Q{mcCTO$3Om zaw~umz!LqJzcF3gba444Y!1u#-fPreBzba~v;z%VF|lOB96>W_E|FakF%UdMxnjim zJQGs#XG7#8ZN7_A?N{iQ-vydqJI$^-1&aVi7osK@wY|*BKjR*p#L-P9kBeFfqkGg96V7tTUG*ZpRR&G zTB^DRNQQ3Eh~DXWS~~SER3brF(~}8-|3b|+mDGL)4#-GmZzXJ<%FT$ght#hXAXYB2 z;sTg)^*mgsiv`AERwk3q;wl4Kv-fNVyy{^VkefgnSSVm<`YQ))EOmlAz76da?fIH^ z;NQdRr@!&jfnKa@##OnrK$K}+@t|j$6r2cq(c1iwv7NYqDFBsmkK!-eCUhlD-)L!o zcyv7Z6=v~iQjd4fZdQxVonFvz<@u*~M4Z8QyHXYOj$o-eIi4pqw6{=RQKx8rXs>=V z>K=#i6wsu=zCBCC(l^o=f z2Rv9#24tfXY)gOyeiuJMc@f*0NY_NsMK*qJ4R4e@B)AU+=c0|rm=FWKyV}Q z^{&%{JNFC65fr|n2KmXUlm@CEO@aPa*MDM6fO1?{lQ?rW9FAXj|FKP@baL*edR>o& z3*Mmhv9;Nu7>>oBw>|r($;Q~Kv6=kb#Y^E^?~Yc$0dv>}PudU%`}!UBlSm=T1b7Ho zp4jn3y(xk}%k@He&rz`>?=7l7yonR{lUF+8mmIR(WOq z{YM3-)blQA-@TKzaQ1+@f3^ zcEd!&+%ZFPnHa(Mgui4}A+ z+9%?1@IjICV4AQm@sgB9Y)Y5|$z8Px?H>xfLGRWY2~K7J((rngSbsAdw5!#3JkCBy zaS-jf<5{)RpyI@E!0fDF-tG9)HGH=_VP~sgnxS^`DQ;&5UpH`CF8$bX^gY`;v)u>@ zVlA4)(SU^Y%w%4@Dw{E}wEjdTdD`y1Zoc)d1Fq?a2TzZgFJ0h#Zn0qj!NeAQX6S6{i zw~p>l;>f-C@Zopehfhz-)+!NkG%;wS4S2{_LSG}Kt!~ig3nAR0SuONUbbB?bNI5& z#bOF7;I(7B8hl$VInv|1?vixXuuEIsiSs>s2Y{^9$D^dl|OMQ&35(j{9555 zJVCi`Xj-~(%$d;+l_|pv`i=`e)IUIxl`8U9Y#vlE`Q*vf^*Ea|``}Zf{haY_U)}5E z_Kzn$w71{vxAvs1_&N+Mg-6%659$nTmSbk}`skgrGQl;0SRRL9@(bwN0BW791iBU3&WMqX|5HBhi()Bt1sLw? z%1|(&wt%XJ#G!>5K(N93&8tMSNOb|9R{p7=iVV-N;3P3?LmMSK!?Pb>2FMj(nl5N+ zSu8)i$3Hn{{@%==8##qiPtdN^Qo5;{G#Dv8`bJqrPqiJsM(1i(Ot0Pb7>C%a(}8g( zPjc;?gj{{;EWc60-vBFDs3}I(8C72+BImm=zy;j&*}8SDeFKs%sAkVkZ!eFY4?ZDs zoU`(5&i?BrE>HFg6k4VpE{Us^2Q2kBD*)eSQD^Oog#!chrGs0!vx15X@J25;Kw{9mbxJKkXXipxIltjcN>>)gTTWXFEg>`d~#m%nzTXRTaHzShNhszU{k zfxr5Sw$|mpF7Jn~kHY9X&AH2ln2>j7Ie(h8J&nc5BNPtp@i!Ue)z_V2LEG#oLs9ZU z?DnH=K1w&4oVLP{${p7p5}t}T>}l57q1oxngy7EpX=?<3900U6g4L_LL~w_(p0h^P zdl_$sSB+M}uFu*F4sd@nIeItX*YLLZUD(;fQ8W>&OPRLxIE24wG+WmwZ#(L%bk7M* zhIV8*_69X6kSZU-mI4uwl_&Jx&EK*P2hUj-lSV2A=Uf@tD6*9!EbAHuH$9X;7sbdn zT2-H61R5KZYO1m5nT~sAAZ?EZZ8wFrL1A62B;OQtW?8R&8chM2`%ND=7NwTGo(=MR zVbEY=jab}#1M|#maP9Mx8gFdg6#zVw9yr*jsK>TueY0`Gc<~mVPj!D>)`>yV+!VV(|(k3=bcY z?8j9d!HQG|QuUldZtKiC*gP~PRul;=_PxSod@w$^AbZj3j*ZK8Ue1TVXgE^gU8E$7 zv`$y_9T0ht&89C5VkFy^?Hq6naA^dXdju+^qbXa6{>e*i$*h4_b4irF3EyzA5%2Y+ zQ}zSsHI@}}mhti$`zl0xu7|X5FP^&m#&T51q_LxFjjb zwHiIBTVoMeVKtBe4ffZggeayoV}i8!H+%2VR|S+9WfPr%h^~;u?=QS)Eyhnv{GUW@CA5e$(o!1(FuK?6jWSU z$Mz!N88JT6To8Hm{Lq}!E|=z4NWG&|;Jl(y`9I9?7GvU)$KZWX(|&8Q$nc6&#J@u0>Jz}f=VzArNWZKAeLkD^&bim8oT*gn zPsRBP#^0QYhv`_RcDU3zE4F+ku7*YGT05p$?l+cnP5t=B$qOnFOIliPARd9~JWn0= z_YX*Kn&FgjYY72y0Z>{P#6Anfif9(kC0xyLPBF>8>_UTXgDIYhR6T3{xHJD*K^tgOMHb5#x4}cHB^NLw(GMH|Z+Lz77(;ivhq-)hFLf~VAbwl+c_({G;OMrWyF!TX+J zA{91jo_amJtN>y2Oj|A)kFIsR zQmGVGaZxvUomX-dKOQT+=xE=2F1^D4tc>6p!6lH|C8aTN8G1`&VQ2ax5sG(f!$bw4 zt@yZO_6Y$#?tVP_PbO`1lP}Q5Sx#H}zEo4epD_(IJ(&o`2~tiS$UoIw`A(uZuYsIHaF?9d~e6 zN^OW!YtRdt{2PrI2&2{YgX;PPGw#o#Y92L)*ApuIMf3!(ZOZM~EDEffeQ>HX*;UBB z){*BTRa)wc#hZ{xr2zGYJ#uKG_tGHbx%{nU-RacM34vw)gT)-Ckt}n-absb2FLY9R z>#9g9pQfYzcJrdmFo7Dopd=IAebLPmyc)6VB$5h7w0tMYYO=wgr0|7_#@_i8`!>7$ z)%b5~V-eYDhl8zjNk0YYt{%AY4UA6J7n`{wkr6YbF!mnmUUG^ z-x}ONz9F8+G;Jd(*l{D)XQ{y(s~_ zq|}mlmgKkuC8QPL_wLqUMl=QWTzpu4d2@fHuG;H6zwH*&OA#J_dowBAx*6a&r*D6hcsk@1;?Z6BXX8v8W7DuqN(z7|SY4H?q2I9YAsQu5~ILI409 zeGD%}igcN*F$3>t)EJV~yaDfj_O#YJyKrO7>J);&{p3ZKnP@5~t+p@~yD=uw9bVruD8x~%o6hJF0By2Rc8 z6%A4Uf1)AIP4sc;-aMeUw$u!*1R&?FL?j`2OF)60^D&&3U==0uVxcIIX=&)=NJ6~p zPN9)^0*CD_A(_(6I3L!FE7O~ee55mEWB4GnBKC69VKE+?hrlSp@4gzM$fK zZBLA{fb*ck$3n^lM8krZ^UeOJbSWBrrq^}yc+l?tP(2@ z%?5W1CMQkcQt%c1AoK(T-ZS3SE zF8+3&QT<4E)_HwQCyED1bZMQF6@LegS56wX`NoNwgr(cQ#yOmL_j3R;(vZwFsSv#x zJ%9e~a#h+7INQ(GeUDDyNG5qO7@fqbKiNojP8gFWZ|~AWJ}F?xoO(jgAJA5UzkjFh z%fwH-;7@?8Nlrd?imPhP&KlLN zZ_h1iV~bNL8)Er$Ysf5(^SD*6gLCsZFV78N_$XTV!)*)^P2oJmZgrm=P=5dWolaM$ z{B#(SW}c}U3Zg>enY)~36eDs`a|P4_#4w=Wk^To%1tuz;r~}v?BnIMbvV+3uP3LZJ z9F5PjvJM{zf}ZyrG#wN@jDH|m+;V{9*`O5u0hwdg0DPArKzwBQzr6PL4@Ro9rKsBb zyW-d^>1r6FTU*wPmkdd8Z1Rx#r2SjW>iT?vKfv^Ljq~9B~2Rm^F zqFozfm{XEF1;f{qS6f!?Rfa+8#?8(AFE5P`VSfOH?RW>0u5!Z={AT>HQ4F8^U4Lj> zTWTdUN2yf;)|a5ED|GgT;z8*XYbL9F262V+NKgCi(G1HTQN}qAK%k=xm;}sKMlVS7 zOaRETAUn*f>rQpU2RvqrbC3J2EFLg_KaP~p>qn)y7r2IA{Fi|MiRE}Sd>T^~6}_1? ze`lrYm4Jiy`j+=1aBpuI z@AQ9;dPm9ST}yaR0d!LS>rS^LoDjnUt-wnU|Kp{gZZYnQj|49_Ii8j?IZG#wOIu4y z96`i`*Mm4Y&1(L}{3?cq@w$yt53RFI7fOqyM79h85>CY;uFh5yP7fJv zUb;ym2}3uf@>|QLYR(U%A4#azgB32UjTs#k!DtijB0@i&HbmG>UJ6ZDg_ci$Wn9F+YQ+Y013n}lvEiH!* zMfmG#G1u@4>^&b?4Q>ZdNpwK@D&0%rK=o=hN?Y{@B(@zhT>ul3cxlqae7M`sk9yxa zh3;jGU&jI{kH}{{_iMih2Piqim;UpZaT)~O2ohjp^05>0|83pNu+l%{hC<*RG5_t3 zZvNLZ{7=_H7nOXsuvv5*y>M4H{r$HmGTjRym+Ak3ZuoZz~sb=%kT*zsJR~|K$5m*Kh)0YXO5@`j^47 zj6ga7TR+{xngT0%-E<_^^|guH5pI)GILh zkp<)e`b{8Rq$1tKOwX|GUA0$H-L!zR$J|Tnb;u@^?CcJ$#I%k#R=jz75`5Ps+T!~x zQn;(9ma|uvB*gzQlKn1{TfWP4rHq)q8XY)1dda4~F~qVjEO!R>H=g{f4qf;_k5Txi34c`@VnKYM~BvOgjmp{h9x4uV;Ea}s4_X8};;SnJJkH&(~{Evw7^2+BULeD(V03R#dzJ6P1`}QI^lMjwd^guks{t>_|yF6{<$qL zL@N-vOhkf){>kK00QkiLDh2`wPvcF=*tp}Lj*O%&Auv9v_QG)B`Fk%+nPmsNKGNIX zq#P2}xZ#?qOhJt_lk15Ast@Bl@FycPj)(W3YrY+*trnaQ(0j*-y zPnDxyJC2q=a>Ozjc2^h|;=E4>RjKmpF^n|=egfD9(9+w41Z4hRJj1?mv-eWdC51VK z2TFX9G}U>0c>;M8pfW+vz?29|Z6@d7ePDV`UW)Lj4~!nrM-1x#+No_OT%>4|fvJjc zu8CPgqI<|LE=;jJ{?gM{kk*6N&!+G(i`-&6*!0jz>bvE+qHA^UZ+Tca+1ZJrdd7pc zcY2c7mlMYa7vnV!0>%-eg2ugTi3Eh)^je@XVnK3ApV)YSB6deZyf8<+_6#Z zTpna?+XM%_t^XHlvj;B{QP(O;JPu2a5Z)^{o%J|3d2`RPCrO8Arhk*m;#u-D3!pO! z_k(GY1Q{q7oQU5^C5zChDxB3wBO~kz;XWWeh>R4h%j^f5Ly}eDC{v70w%z>EOU7p9 zDTAa|1`hvpNo!qfvXOLOUPGA2nZnMD!ykLzJG(~c<4JJtlxu@qNt4T9=~n3?gL{aJ z?RoIsA_eEZKDZBc7GMN9&=N&S)+H3!U$d|WM?ue0FWO~$lZ}VHzc>J`wZQMP_ieGZ z+%n&HVPj^Wj2A`}$4z`mz&)oAB|Ri-QZAE}mV9Cr=fqyzAx##PY{yN(GktQH`1;k} z&!-9b$k)HJSulFN6n3VaTav@Qz1LG7Ik12Zo6H|uEB1P}oH~{%kEPOjdlG-RA44n} zzwec6Wo43ffOr^*dHhVYZHFNwnD~xlM2MbWLA6~h+*F5@gp?apB^uS%rtn*S+qIuD z@G5}elWF2)9)09=u->8tu1#*$ zVjRhm0G*%RY2&5Gys89qtr5Gwtfw0tO8z7saxi*B)pZ0Ilo{v>z5alv7^uwd3p+2N z6(Euc9@XrqNva|6vj~p_YJgi5@AcGj)x~uj9x8F_u+lfvTa-QG)u(;t?PWI?>~LU@ zO56D{8XI>xjQ=mTLVpnHMDaL-4ymq+hjL4{%lxHwoe6Zw}Ze_vQ~f24di+@qs_nG81F# z6>{x+^Jmmy22Wrc@0S~Fy42$CJacw2C}%e!Ls#Zb>YF{X9JcnhHkQMSanJr@1OVy% za$*N5JQVLnEFg^sF4`=R{6yQO%pIuXwXYsmO(ERempM5LQ-XEQMa|eVe@vDe0~UmM zsjGYeIEsYmcJ>#5f*Th;7g}o==5yIo^}N`Zo5_k3-rkQAf~zB^Zdp5*@L&9SOY=Yt z;-}!cbb5Gg;QSCgxYl8_Q`mLuYkhL~k>dv5r*e>Zn7v{3G&IGOGH0f#IJ<&pTjBxQ?tC_QKD;0qWRPl)&D}Iw}r}ZrUrFD7nb+jHPMYvb-_Tp{u%<>X&=J@Cw@7+IrF>$tEW}o)A z`)?&dCT7_PS$4X_RtkAI`D`-%du7p8UR+`T^ikMVF)N2S7J+_amF~m*)bC$;O+j7C zkPs_W6pXu=a%+66!YBGzq@dJeJg=lOHL7lA#`sp+m8b|9{W zA{nXI`12A;I;g~r6{~;}X7Ax-$8YJ%?UUs{Kc5g+U&_(U>fS56 zujXSpRg<%eAB{In9bn`2UTr<~vhsq>WN{5&=!aG{bZj+RzdgMt zvaRS8DD+8|cEZ=guun7mqG`^+eROqYO=VC_h--XqvZ(nhy<0R^bZ0H%mMvI= z(bt~^BxtGZ7aM7qYAd4OSMziVxhX3HWr|sySBET{-!M<%$hXiLy`TOe%ftSY%?!L7 zCktzL*@v+tA!wT#ii6s}x0dtGEAL2LvfEs!p2A_MYhrk&;WJwp; zVptVOW;*CBfyaakOe{~(@JhDQssq_y%1c(Kc;9Df%HrpE6bP0orp+*O2zo=BI(#rJG-`S*tk1bT$| zpu>Nj2l>*nzyAX|Xspc7g=vmbj6QiBW1{!H?DmX*nJJCzY<*i!!y4K0eDhNOn*WHk z>1&#x&;x6e1)oXnMMRqk`_u+M6Ul3-FTkKtSMiXjO20DO(8X$znkpzxauF0bU>N#h z`H($Ep99CU-Oo?3x}&rOD#Nh?X@KMBj9MA~oai6~T0Oiu90K=))bYzBo!#;y@e$c+kHJ%sGBibIw;PwmDO_12qdF2IP1mAjn z09loyO)}3zJO=bn!EqFo2loYPM&;FtuLbkR@Y{^)Yi5+{y79C<(OVk8G$>od>x8JG zu6)TWeZ9&yIa6oiR7Xd(zyyNcp1rx2AeKyTdniYXt^t{|aK7LXEhB1HI%xuZ*2w!L z>R-xhWm=-UyUc~-lgjoFYdJiUUa~3MeCHC24p5^6O}#M;KVlxqjwZI?^_#oXmeU5H z`?kdgt15p$L4ZtafAtS><*v#xi9NTz)iv?n;RBZ?1)Z?K<*BZw-LFPkIPwVJJM3@H z0E$TCgWZA7L;#-Esf0X>aYyk&J+>V_jtc*H$@#XdWzH-@l}&J9BxSC?$HLcMMc}~c z7unjKtV7GtiQxXRfLROql%U1ey{WlVEOitL-UMvae`1m%EEvNQ!@=7V5MlFK|hA1T^U_C0(w z|984|6?vRKnlkbIn&&7cZ#soB3l|#cmS(iuT_km`sTsIK zEc7Z~&2;VE+o8*N@Zkf<8dXf zJRlnsC-VDw{PfNZs(3O-+q;|R251_I;SpQfpX8(tk2)?-6+wtk*cKU5iVH?WVuH3${_i)jt7p*EBHDw zC@jO|V%pE%{VACQY=3cI!}IHP_9xp7s!MBTJxh?fN2ljQ)SqMLK0Xk9Uw%WGhb}@q zB8jTC7sY2CpjJN40tgG(jeJBWOZ*5yd}DHM%&td=R%QG-pvmYNlNc> zFEgA=9MISxg6)u0VWmp|+(ZrLM$nfhvs-DfSKiPyD6eV837w^(=zT8|gw(g`+!XzEnGG^PGF=fr({7{duPhXI z97A6EO>@x)B;y7;s~bXbUw*yhBXyp(>k<4x*hm(a?gd#~&6$K*Ps|X+DKYkV4tZuf z5nsHh)0eubuTlRi#Di$#79Zi_{O|(vTP-?Yo!jfWne_lpvBxiAb1&ldkIlFX-s=tU z#s-g@|IOU&=dO|z7Lg33{^?e#I3DwQAHe}tclY`-yH;*LH&b5KHG0*Vt$jMGX&JBb z4aFUzZHl*kjgm)Qc2CdLEOA|wC^jSqM=mmKyb<)}wf`_5@i_iY&sbQ(TB?teLrl+m z)_@9`qoUHmm$PSO>cUsS?FKAYXaJct{bo?O*pIGOA+O1Vf)ANx$t^a?uTQDWE6ojj zzg*;~B$biAR^fCRlWiS^ze88XaEbNYevykGa<+`tSDpXn&d$wqM*q#ej1g~P^O0&! z2@t#Zh=fN!o8}*IfWD-u(96X+L1s1Ue=$q~aTRlU)*Z6j8~wO2dn%EPnucB<+>(946AG@l}|~`LbQluh67D-p^H6 zj<2p|Hl72#=1zHCcDHrEB!6?yq5or2b;sA@4?yGceka((fE+t;h#J6l*5Ba*pMQdYAN7CpbRn)WkeUbwpP&gV@OS%!%&B zh6$UkwX!XDgq{HP=@NSm_hb4PyhYOUoj&-NaGUm)a_^a2Z=ahXr*t+TX=eQsQzT%%D5V%`;71ax+U@>Td*Dvr9_`nBwAy zUtitt?Y-9BNsB5_knO5Ft#6)#Lsvbf5wQYa(=NZ1?DyjC%_f-?Wzj<1(XcC2_Dang z(MZMtgt?I$D`VX9yc4(t6B|px}#|OE;*{yVl#rDTU!^ zqgQu#f1iP$*%7w+E=nulwmrU$c^xuG*3$LqH>4$zRURB2|K%r0UnO|RPS1v zxNtkG-tRGFj%wKzNpgXI%gv z!g(dUN38t=D67xXE-siLs64@9R`p)7V4G@WcG_BC)2@t%O~lX zjwny5)RnsA3n9+85~ArYaXnJj*g$gYkAE_I7o6<5W2M+SV&Tz}J1I|Hg+C2Jcc6&~ zypLNml9t53;#IFtNY}#STKlA8(vB*@*Two7M7;`Ye4bbXf!GPKuFq>E2;B7S?XN~K z?MXJj)x{U(+}#fo!pl1w83#4RNJ^&oowjUIGII&RI`^mN1V7GALwiDFXq<@yatX|hLuxZ*cG2_O8kfX-mWSyXrGiB zx+Ld>W7`K{E`9~H^YoB+^sMoXMpX4-3>I?Cg!-tb1yzFyry$zSKt51_;#5mv|IUB) z@sRfEK5qiG)`AZ9+y0^uq0*!nheq*Hy%P=0{zuw=6d<~u3OQGz$p9aMROmHH#{{(I zlg8Lzt0EKRZA3Jo#MPvt)Et$PV5h#_E(wv@X+xSEHqFJolZ{S<2WCQPL20X){~e&V z0ex9=kgccn)-ZoP?NH9f!!F?TjCxjGu)c*iP1W}FTQ*sm&$91?1Ivx22P^jXj3q`L z+^h2$`-BdSH^%zl;wJcgm^9^r9x>xrBMr6LQDZnTe<6iVi5sKierasdD=d# z`3bkaI=s&cT?pD1qDeYnZ$goT6Ptl<%VLG28a_P=rGVg@>bP1tuCDWK&NIErfEFYW z*6n=ugIatS?ZemoXZ(O}I%G1FeF{PRc9L0vq?!d18_1Z(L z-oL6IFr7RIK#FMt_CZbuFDCMO@)@TusPW`m);EmwfAS{8KF|^#y`Zb+8x$!km)T0n zz{7VIag_7c9ht~Y4FcATDefQFsh1p}dSjag@@b`SWVAcqTdqV+hzUHj zeUJV|`5R*HQs_>QjUvArZ{QhTc;m+FZty*y|}nzBUdb05)djGuO4Tm2g;DGOPI0t#M>`0yu!F4qcXvfaCUdh1eFIr`@MYl zTU1;5NsfR%%j(@eL4Om;w!N_r`H1A019#iC;rzz1$G5DeixK$^J|$%L;+aj#`T=%w z0sYuInwo{sa+JoA$A3`!rRrMI&cKk&i4vu+mpgujto0#;X5d5#m}_Zs&5W~%P$Oe3W0dJ=YkUojqhw$~btB$6QwvRl2GCz7<9-rx# z5==uGO>qL(YF~;W-yhhy@6$OD0cSZWgmbSuvXICN8|<7UH_Ln1B}E_Pyo}Dg2s6nFeii*+!+ z*kB2~HGf@o3?2ThH%}{4y-q7sJr>0L6CkUde!#}_qJa#sgqt-r&%wvwibLuq1Y}De zBxaxI=LOa6^dg5fzPxjnv9)B&4`p40)ZM#+GPGe2&U6Zyy{t(+FmtGY#Ru2bD;%JW zTupM+QTdr0Uso}`b3uCs4tAO@q_rSTQQ+Mj;9@#>#s(sKVPJCa-XKg%5t;nULy6nb zE2_Aw^wj+)y@i6l=HukX0pJrr2|F(;|2mfz-bNk=cY=GZbo8V0(Nn4)%Q3IPRd1>< zUL4qS7LMrhoq0ufoW6-6U!f?S#8J3|KT`XsJXQFuv`_xy=|e|DvkvQ=WkTJ40c!Q- zN}?BMwisw>V|I~$@&6YARI|xt%I$HA;a3t{nBf3dKiY2VOBTvQH7NUA*To?3Cneh) zOf-*ditfs|N;0_$YlSIS7lh>>78%{+|8Jn5TGWbtxbFUqNq}yRM!Wlt(F~^t% zy-iPi@w`tfmMcVW!Q}bVGvJmS#rhnw-JsJ8cy<_|&?cK$t|HTUQIA9H4VP0Bq=y+lkl5nuSa>6Hdl*;k3IEnf&%8IBuc9kk zuvu#-(fBJ)_)9v;yV8EcJ5{x0gxDL_J?UQmAvLFJZa{BnT8&(=8NcuwSZpf}lONm) z4C{kSNw-XS1g}Gp(PY^06wE%*LFc0=xpzO^HHNs zkkD@N-zF%$9-ve~aduXP8y2a0qv*pEY*N%Uao;#@9jCRdf126^y{%P@8*rQ>VeC1N z=4|VR$3gporW=1iiR?X%#p@1??Tr8uAD9)N5b~t?(1k zY$W@4?Z(;m(6TiObZv~nH+S;#x(;^p#k`2))B_Xp%H+Rf=eZ#soah#!9yQ1OXgv04 z25?>@Tj&-mw|{=|8t8G;^9PchRZ@uFglDBnimCpm5gRGi%gi;MKUqVToj#C}c+@y@ zYTXC`=Z?ojDEDXi%B_*BP+c{)pQdQv)|Kr&3!?@e!md!n8;f@}C|L{0A_xDzMj>C5 zi+AP|3*==^ulQo0J~$O}yqGO?{YSCBh{@dtACB?vOb^d`eJA9+I0AMC6Ag3N31etH zwq5ZVHli}#>qHVL= zX@g#z^PIX~lq-V#s$c4$uoBrF$Wi_35qXJ~iS>MhmHrFI%$T)i;s%M#Bc+M$tOJ)2+-K(>9F zG`a+SQ%cPe~2!oU#GM-+^%cp1VRA zX!D8UR~flFbd}V;U?0!ivuz%Mu71dj8~K*}R&G!B>#hy+t`8@oS+h|-#C|cBqzR4Y zm#Q62o3|I7TKm!K2~pX zk?-T~H3l>&9adR7+0yf*}EYE$;FI0a}cRB%T^+r{#= zmug^~1(-OFCNY-6Z1T%2CWq#r=gGzc(qFewaY~_gEzVChgn>M^%f301vdpSSU|OMp zh0wXKp_!SPuAyGFlr+~Mp>mFZWPJtGyk>^ro)8}Gx1Q5Y3ppGw-IcHJKMzBDedo(WWt&7 zBw${!e1s(*_?R!3VLOpU3d`8vDC!nm2R_Y#rYI=Ic9~bq=X)3NJUHHgHKTh0&sUUsN8d%lBQe^VaS6A6TC@6oJj-AXY@CJ6*VO54 zb!^&d@$(JCG3(QxP;U)X{3> zdD9KpiBhLIJ~5}b3yH6^(!e3AIl2tmH33g)XV?J$Q;D=?$>kA>i^g6yF1N)Z=1I+^f(rXjoXED}4TtqM{=H~%w zs89HGixl41OsZd09}r82&kn@lE+)vNSWwTyxW*tZ5R$NUM+0<;m=(N`g?)q0bWHg; z;c-u%8=Z4|)e0eu?|G>nC;M^hP1akBEKDV|X@HLcWQ&n7YOmfrP-v=~ES49z+kLO) z(@fF8S7HD8Hy2&E660rsK0H;xS!JtMm%0u|SH@tBt^tWr0LA!@0Vj%AZr$jmygQ|7S zs=bD(16I(pjh6r#n5L*ZmgWmV-BEgoDk_zPU~TA}X1wE-=I{lJ6WiUJh;uDQG%F&U zq37W}(6gnD>eTT}ot=n!F#gcEwz|s5COmD=ye>^N>Po^Se(B9cUfO{7quMT2NZLjS zsk{lGV<2PT@+9|fbAU2FUt-%z#`ZUp^sAx2rsckV@MTgyw&EEz8qI9U?|o*CZXMW? zpYB~m8{W4v_A=A&%&@OKa_RF#Ok>oJvVmf-ybW=wa)bTN1tgj!WD2*ygwNm1{5Gfj z%8$d~=Jax3ka|nd8~;Ls1SXm)K1vVb-HMI3w+asgx8WE|Fd>$ckc44F)nEV~0uDj7 z@xirYB^qv7Rl1s|x<;$9(Eduw+^bSMza{9qOsVM$vyr@1XjxhRv)baVn{kT-{z}4m9_UGVFY#E;C-tSY>Rr|JVN%GBu^2s zUt&m={ozRjO(L-Y|8UCJwOXaqQg=IaUhTsOEzmry+)L`@xf9E4#9D1d)Jum6CUD9TTfQP{KfE(;}M z`EnPfBSE~i*p;ae z>*bEFx2iuJ4!?jCEsq|%5W4{UVfV)%fTRb2M4}hn+5pCall~x82zHauSeK`n1n+Yy z+z3{(nod4-@5o=}e&lI3<#yP@0-zbf-r>U-a(H`eyHO-$z&iZ&iS)vcQH9>(I{ir| zdg1t)S5~@D1xtB$CB_i*(Z60}e6laS>JA5+Dg!__J%wGmJ*BB-3I2uZ2$PZF1pbsx z3uES)x4$u&pR$>6WETiO<_L62xn5Xt?5Xa*zP8J|v*r$e|chq%nd_-@c0p4Gbn;#Y5@ z;X!c3U5X*~%S-Zbra9j1-23LsW6if0w-Pc0`|eQlIUg1D?wxgVcxU8`(Bcbiuvs64O+nyQeY_q&v)4&Lhi zJ1F064kgf;Pb`QFs_ZQdDO4sZE28o+lB(O8&k$yub$=0ioXaitk!|0v;Le3i^D!{%0%>~9$rpR-Y(4l%Qd?{oS zez-Wo$3jsaoO+6H^*A+Js{dZbryQ2!ij{`6$JZ=z9ku`Wvvmwq)bxrcrBqQE4Z*D? z{^I;VJVk4v;rhlxX;QFMWqe21)FU_TD?A&OXWdSc9F1LgjZ5h1vg)utQO6&6Uia9% zzLs|~>9avwPFMgK@2H8^`TK~{-Xl_CBMj4l(>=|%LUc6xyVWun)oS1 z>uaO5tEDNpfSllL16M(}atWgw9Maq0cRORB}4zE`EM>dxC=Z!+oO zxei+E3&Cw35}ew>JP5DEsLX=)fpeZYq9f_;nRh({zdCjYUqwyls#)dI`3>EmsaQ$$8NO|e=dK{Kb%q_6>|Cf$z9?_6 z&gU^ci4AX*XM%erA<53O@!7{4w34F30@9Eh33Ro3T^OtAJBO{s`{0Ca|}8 zsZQB$Rh$^!3S+q((pD2#m72AD*~FHO<_Q;lbOyZp59s?Z((p$TrUL*_n=-T}MmvK1 zd`djfiY5WRQxVLhplmkL<4jsiwI48Ni5 z`PCx|4c3+wo`#-}mtNhpFcjYmUx_$kI$}{)z8GCj9YCCiE*@?|2|p0eH5u{fb}7fs zMK4^8eJdaJ{dkFD_EUy*b;Yjrz8ljb45Ca|BlJOYg1pve`uHqEM?ddulhNr?+sOtS zmfjQ_5ixg3n`*wdoVZV;DmcW3%y_fm?1vEhoKvTvmCCWpXP0nE6 z$j@pUg-Mwha#T&=SUNK}ImaKLU_@p zifsmD8|mwn!XNU-D#Bz!zd%V*UmiuOS;{$AxEwM(b)GRfypO^;RgJ3MSxTc1K<=GL z4E9P`7Ovm&uZ^`DRr+f5Wk~;U$IY#5GU{CcL*HN}NxIYC{b)wdd5ULiW|H|l4s3ci zzKQnnEo^(j3w(Yk{DBkejGK^o)i&)EZ!M)S*6r3rUP z96f$4G7p?P3P<<_=_!wcrKU5V`a%2P$7s~hpb~8+WjqFgMSj+FQ=qEt>tNKzFc8fA z_szZ~Fys3X$ad*>rcOu=s)4dO-VDK8yUK>3TJmk5Ths`!;SL=@Ma%+TJb}omHpJdB4$qtL%NFS+{6k;)hG@ zoyXSedZXuxB-pM7^!n?s=9*m;yJGr1qV5QizGVKhWbf41FiI|-Qd8($6_^eyd7cAW z+B**@)AY?;J`_{;7E5--M8YyNOmq&MCdA(q7J>Z!ukMPX*p7yL5H&a*2PtTq0Z=>o7G7 z`$k<56ZO`SX( z0z+@+uTRhGf8AbDq5JTGbAR={v$n_`hl13BInBue`RX%ulD*?B&6*9@ZuK)V`=6G% z$@J=BwaA^zpfzd;Y6i??n8*$wNX8YYmL&Ku!MC7R)^d&;01PA>J{@Ac4KgptAnMPD&hZ+G*ue@k2 z9omndBh-tD*?GKWQ2#`o+B1SR$oKU@l$VPY4-!a*1 zBG`&*x&QsYW~@R40!DwOk_~Zwmg@i3O17?|_8HZ+a_dpEz-x}@fLgMa`ZGHC zkF;$o5oKCtX)O?z7?U))7K}OZFv{qOYQ?Y zp8rojyOU&%=ER3PPZXgz8xfB&ykuSd!-B+PV0ZiazX7BSTYJyEAW!~)CMj)(-^Z@f zYtTB{mm>HP;>Xl~0Z5a`9#cBOGVX~8ZHz?7YE+{p zOcMBb3D8yzyCzO*$`b-!u9?ny`EJwUp_C1bLQ9!-i^UuHI=&Yubnme`cPa5h_Yw z-X)QeN!Fg`IlTG7uxr5Y*s3&}z+g8B6D%Ty>5K;!YtY(0#@-u#(2y*lwsg@|PTt_w z9m@zoUuD6o<*dE3Td&_;?sOWCJNUwIBeHK#?!mbngq@MtjvSy|NjZsrvhB3^O0EIc5XZ z$bNUSiVQJwVzv{qoEcN$KBjLG6SQ4=yQsxWMW`>Hy)$z=X^}+H`nx#5dmCm1nf?W#DS+YP0im7WITP^@4;m zVmS;s^hFi!-1=CPtTUbPA_78V9EZxNy|o3dSqR^YsXSkKr%qz#9;=6CZ_4oVRLK9w z-hW0lxovIZc&HIUuz-M+paH20f`uNiPz6Llni`rSARQDC2pvTr6zND{10o_#sTM*H zO?n6Ey@sAZ5`T-m&w0*1@Bj6T=fnHyKh6gn4$8`X&o$RI>zY>~!sKSSve1dj=H)H7 z{kykwYzEsTy@Y6CTdR7WPr8mv>PM<^$D(y_Lkcbha|*sEe)3t2sha2GnQ?D!7cyHq zT6`4V#39|$dnc>toQvz*AsSek5Y0Mh{?rfhzC5sJ4L5i?GmoeYtE%40n?(`?Isz|x zU%(rz?XW&+&v)6=_;@LpPXtrXhlub|o;RGS{ML8d-uTwyGw%>d4THG>7rP;B7e9y) z2WARaL*eDCQd4bC7#pQae(IYsSR)5yTe)-EA6PN0BjVU70kIp=H`Cjjb*9MlC3mv0gUfmip#1!czuM;c6 z8MJtb1krHkPW{&+AI&Z`%38S>cIjksJld2^jcsl}a{l|NiJVo`27K4OsG^Jjp9aJ2 zp0#hZ{;;!Cw13-9{|h2eqeOr>HabCmcn((HqJS(|vLB&8zjbw%n&VoJN@lF%31^Ajqla zxe}5v2$A&hEFt!8D0-46Aux0C9>eU2@t{Y{X8+hv7j1Zi0GJDsN;URvU;XyDvzlO) zss>Lvem)1vgD}CEYboo^-p|X9tD10nt$x`Jq%~Hj9mB<;qzfo^LP~>5Z!A?`sqwmZ z>W5j2x))>XX#_56Lsp!sHT=OI{ z*D`RwM>i4C_FQNhM)rd2!Up*he?jb6pleWiyKu7!mTlv&hD$T9zN;WtCxMzsq0m=s zh_AwI-j8IaJU9wXnyG2r(>qh(qh^i3pF+NSeUX*LmNXwWmlL7x7N)cAxTENJHO9UB z0Xs2)cC`0Q`1ry}zz1)OkW*Na!);yQ*CpLx+Y*fTy-DdB>A+#xX}U^f%BHJ~<`Hk5 z)j1*OqONXw)F@6EzNd`vo=&MjmZ((nY_h)AbAC?c_?3^38d_mCp6zMMm(1N_WbY6f zMn+vs&JE5MT5Z9?SBkptX48K?+s;fem6mRrh;2k1wMki7Vwa)mwU$}($d&IZyNQdn27J#i>*RVX^_QZK+d7`P zwfj?hU$eR8eXVfJ^&h25)tuF<#{L>bVydl8&?q09k8{ts47rL^qfiJFZQ+t(Mmtwz z4f2Hhc*vO$#p;ELelxJ1FmHby ziIbT;s%@&pKN$E&9w_sdade504#J8T7^>F?@^7o?CvZhdrOp&iYL(qr?F)aqC&Yip zQli+XBBI?zo5OYeHeFophY&$Qf|p^TZ_RDhRr3k*5Ui>~o|}cRlM-%-hD$h(@w7%% z(2!z(yZ}=rPQ9oe;1wWe+Pia{_)!o@)3#|g?V6{Ohq=qyL8AXg8n#V4`Z-~3s;ms4B_MMqXwi%c^mW7NzVv33YGV8RcN}!na27la5<4gmk1iR(n$?# z)BBnI%`-uP`=WOdh6f zZ?cp;dG|`IxeBDYn)72;O)1JzBiZnJY28a z&o12yUMu+Mxbj%@wP}UmrB+9gvYBWe-$#%5jw{n1KT?>9vMe0V)FL=fqR`i{>?ED{ z4O3`tkLyz%n%`4L@Bg$t6I`hb0&jbPJaidHXEGbB4DM2FhY>YOKV99Pa8r z(pIi+w@Z$sCCVoZ`?)QkPWAQ_{Y@j^cjeGdb7ZCMI~aZrLtlvd$}<2mv%{uS?6{!| zDF9fg=?&xv2Jc<hc;DaHa@U2v%aqg8{Foo{-aJH06L zynHNKs#;z31TdHRETOxrKC7c1;re8($V%rz7kP`!l;%Pu6LhE)QL#3;w_o zbL4sPiN_-(u1!jk@nqBRbp|yyT5;1RQAYvbqBhJV61(#OlOkrQ0S&vjnframU zH#B~&Qlf>>(FAK$)jY+x9C;o)+gLeicvS9a@l@eU3jf9&Cc9?(Ey}e2Y}bYUR;`e| zJMpt(d=M(uqboO`NMzbhFfohLG>11Gn4UZlU<%z_Ifk&knU}=i?S8CdGrO7RGFuD} z|I?0W|MFBC(5M^1^jeYTvtPvwUUm7p$jja4uWcRtcq1==wbw~l-!(&?>P8=hr4U)F zN(nV9ZnJV^K0@x=={7TW9t2aj7ALeV+94<_m!xM4YegA@Jg}NNwhTs`~`G!*BE>R44{J9RCVI z;fTe9*O#0Lf9&K(fJuZsSH@PAn* z&r&S>6y2n}0L>4ehmh;-r2Bj=o7er2SK_-C;EnkG5ANaWh}S%Nv|!tVhBAj2YveBF`s_L%#uX+4T2ibe6I(%MDtOD z&z4s)pAdfB&$=yj4rbygaqS?vsJZ$Bx1uwB+g+y^G3(=KI$o5Y`}vUgGh$rR7_t8D zF{Kn`g(-oRc8yGEx`KFL7<8K%c7W*;K8y!uSI0x~Fiqg@ZJ$M6Blgjqz6kje+^v0s z=>(F)cL-b5R>eOsyK${lw*^P}us*Bq+^&E}4#}Zz~Y^43~Y@ z{oNvzTOSN5&G)8%015Dqm&Ny?Kvd(@Rq^u32N!G#>$m%z^*-tnh0>V&yRPFhZMAT6 zt67acUU$X)cQUrF#^p+#^3(d5L^0SO0HyJ|>tJlG50;D0w&d?i2nWYtwo;|M42_|B`MyK-tGwaREs6;OA(EIo6rH) zo{0!MPeJuwyh^8H+dM4W7tkI4>(7w{FlLcV1ClZ8{;K=qrW7CX@1g&Aur3d{;j1HO zRI<|o$)|7oIEPt!h?`nyESf|qU^{1MV7CpIktES$j1+$W1$))mAT}`1Ky@mPQwXf6 z{2lCk_rW0QX$Mi4cmd{r>w|1_fO%J}Q^m)f0(7wkm2pq| z^VK#RjLYx0W2Yf_egDguM|U zmpx=qYQ8~MEhjjyjJea_4?oi#XWW^bt2LCLbSE{pSwmdkSDUc6`(neoE<$;AN8$9+ zBb8wRf2NE9BD&u2^4RhI3=4X6t{*u#MS`R)x-+haAH#e^HL3Iq`+hiP4GWPyA;0*i zTngXkG*rB75U#m4uJ2XcE+X(z4}G*#iz2zyjJB$?g;JDS|gMR1B?44 z$<8-3HoGKLk*J<_=f{$`hTw0`(+3~utPNi~OTNAnpi}iR$(rpH|_Eh|3H*V`&40QleB5z#0~om(4Q*~}KaIxCn9h-Q8? z)vW82mXNaPv2~#PqHsvI16Z@r`c5JA-4cO`H!Mloi0JLY0C{&jdjpE4^lEwEwq`Et zB|WhdNwjH{%nfR+aroEJA3q*1J!J1Gwb0J6V-5YOTxflv;}WOsOmON8MCWRq<&t@V zNZ&KWxzHfczT>#7@{azwnQ<}A2JZXKDwh7f*T-N6Vz}=mZxvYB_WOM~7E~$be=1$( z-^6Q}Pbu&J1;J>7TE;()c4&?4Xu<6-Dj9xKMJCO``_3I(S&npe=->x}caHU5Dv8a> z(JuWD7zSJRaU^b6?ZSWp-t^Ug(Jeckg{$`}Dq{#+v6wbJ?Bub2c=)y5tM6te;;t4r zp+v~w3g5rr0sA-AM*jm3Syq#NK|~M&$eJ@faYI?Qwp7h9>sXQyx_bXhi*ZTBZR@lP zR?r2H!hX!(Kuh!QI13s9OqWp|*?UElAlSGklXde-+y-R=))ys+SKENO{@#5uBhNZyK|)^t`XzNZA4k} zH@sQFZHP{?HVSX=%FQyowZA7_EIpiZ;ZRm&h#=#TcrZOx~ z$)m45y{aEf9!*9uyDn~DS@(6PSE>$~E6p_V@ci)RXI9yx>n=G0Lf>_XqSHG5V6p_R;^$yW8!yEq}-RRDR3M zk1Sgb8acX;i7;&$iu-=w-?!x7Ods+e7AB7T88M?elj$LN-&SeV@ zrfCk+kG7Pbp0YljL5uNeN^`uY(WTBkutLNmwF#UPj9Rd|ja4JVi}ML_9rr9pV=2xL z=HD*=iB44yUE|bc)PH_%d6W8fY!)k9iGB@Z5d+f>RF*aSr_?Pf!ZVm;=gJO|EXH0g zPdDKDOq?B8>0|3D+=pKh9JIh9 z9k-Y5wI$2D_yaq``)^~8xycwM^sH`CCJJ-vHtvapv)bO$>?my8v6<^L%jZub3SJA` z$>pKyzGA_i%BTu!a-WMP@f0*+H;?q{kqbXH8GlFfi0j7zv zAVK5Td{6eHb@xJt_~o#`oaVbo?>1*6iybv(WPSgWKlb;{zv-)~I`P)VD73p&4A=SE zu!by*08nPc^W|bzkQI}un$*7Gvd-Vk-fx|r6U6i0j33`nZAYlB?3B8uQdo)doF7Fd zFTd4PkbF8LNHknl{ok!4c!*jRsSR06R$g4{Qka$!Zw0({gYU)OljF)=?lhu!&Iv1J z%-w1x!=-VOD9;g8o8mZdn(p^}7n!C@U0)>U#G%pD2doDw)V$9M*o=8HH|Hu z9GUzf52{Q!N(<;TUfRQsFs6ui0)5Mf-&K(qy{fK&-GPl zXZ#=A`^QnbN-zoHSc&H-AO<`n5;+_v^!$om`yqD-IJl~BfBf@9z*HUAe?G@p>34j~ zgE7T!P;-Pe4P2NvRK|aJFn)X+yp|R=Bc0{bg}-Ro02_KitiT@NWfN=xL1Dsf=EBMS ztCqww2ahZ37B-~yy=rhk&Q*-?(N{BaDmdu^ka zxqE9-^^bow*f^Ii6D2hUetPq53ccE=zNW|L66CV2;_))@-!p`1+PQ(cry zCak}}x9*vy`2n0j1z#Ax?c#e;6V?|2*xGVYyBK^gxT*cfeV0!BLfLr(o|e?64er8?{BUOddRVvtku9AT6SEH?+Jb zr#maN?b{jx3tE;ow>=gxsUYWbJ$Zi2{>&~rPmgNHhsh3h z2v*m<^zd>;?@`S8VR3PV*H>A#VQ)Rx{i@hJ0;hOL&Wp)DKe9i=(q06O_)}VT1ee41 zdnR@2OpzgJXTsX6ANjRbF0GCxLzcXBZ?RI%j+Z)y%=K4sH(!bQ{5|DW5xqK10fK3u zRn&<`SuaXOMK0{1POoRW@2OS5>J1#70iEJ@R6sOrz#y+blT+?WaCP&$Eiu= z%PKfhl{YSD)Y$YAaqS|z1N1<2lWfeuuVHT(aqZ6p%Bl=|ui?n#< z(FCw`b|>Wxf`$^2M9x-t3l z;;KPAQ%|GiE#3-w%sVw*;@P$D)K$`S3KAR&YHS$$*r9b3XGLAo*Zr$=ks zb&HKgUYv4N&shMwqBni7jQi72#;)EA2qL54_3n8;Q%W<2rO(tu_VNYH`*sA=R1tO} zv->5=qJx`#!J-sdKc)oT0wWmXcNK2zY7$TaAL0zUGQ!cjQTCR^+`I#Ra%OMtr<JS&)tQvzT7nes^uv0AU6&Fk3?E>F*qVis@gT(&bV?m$ z^MnxV{wCXZ=v7I4$vPyW@}I?k|9;kgW%ys+`2UOZ1qvu{a?Z6d{eo18nuI|Ddb9!> zoNZ3>ZPTzRu->7%1-`Um1d^OZLU^~AglHtEYla{7#HY2NJ_Ma#kpCA*AUa_$tbOYZ zs4P1f9B5r-WE-(N$;TTAJ|6;HqQfsLlP&eKUUv4VtiaL7xiIR*n=?ayB2oVzev*j) zd4|Kp`~RR`=|VcwzmSjhZ>X2=B}4=N8}ez|PaeD4wP$K_JzOrBE&CSa3fw3J4q>qc z!{iSIKrPEa&rPkcthipA?6bA@r8KyCP5)lR{|l7mrRxUof&K@`(%D_$9ns83`U^A|p%B3BjkS0-U-aECd7K<#KUYeQ{zhG% z4wbztjoUMdN0QvaYQQbJco?D9k;}WrMeIweHCc8%YyoA#82W`A;|&>rdDxub+rOyq z>t{d)6t_!HYv_$8juP#5bHN{$c*~NLcMc*LZ$}<9P|lVJT)a@yuS}O2nR|KVSqOK) zd+xv*>OxeFKFWsY#_n@+V&NR#zHVq)cBMIc`2N|t5l$NRXde!h7<+{jXsNI0gO)uJ zlPQ(x8UC_0qty9)?=sJ~I#dEG==#2qRWOQ#v=>gOD$taklz8<*rC_ALH9GozW#wb+#he0_WFB9K&y&v@ea+}0O&$4E z;lYty(kw;Z7h7T+ln@dyFQ|@9(6cI#nr}ER>sM7>Xc$(ZCy3`|d_GhImGX zq&irU0WvoexNyqWq%2hwV&+LR=k5WUue0XUkvmz zpccg{!A8WU23GoKpD*)-#9Lo{#YmY1USaUnIQeEmbc|JqUq)e5!jTm zZ05~EX(ay)xPDIgD~(MD>K*FL?^ahuOz|afN_q=YLBSagO2Il3U4ctcQ^R}})sS-^ zTli`NO^PjSHy+|C`xbV6=V21U!3&N$x5E!_{pV2}vvOF@|cv+}lHd%lTIr9vm56T$FK zyIO|Hu#+xo+~ot8e=B1&$c{meT-IGfF!bT*1g1apO17yLc45b8So!Y~u+Lu_JW=?%2FlJAC3W zPr~hQ%ozL|*L~xGx#=U*v9nyrkx19>B(WNOA(rS^|3+v&Y?&TG@uh$*;{!uc{ z-D@`g1!=-$<@b%Uo7_}HC&REFW)_QglX zN~GI$`25kXYE9im5PSaT{O@_+q5sln6j(C~RcJg+- zgpI4J^SdIBq?>2YBE)MAIA+#1WFW4~yCS5qC@bGdOCrZ37gvIFcf3+pym}@-R>2hm zsAc}|d$$GlZmj}_&ou;(d`24AJ7f?DUV}!nUGWq%V#ylEi`|$-rZ8|k5@Y1I&d_U` zPZOSI+)}C4!bMc4>Qag~5$d_1Mqzi4$h5bgZSoD_WGv3VL^!4Arh;XG@~ z>x}2uWokq_?~0Axu;7%)507GCAx?DtP8iYv(Ox|(8xLw~`>wR1`U~RRgPr0F9i<{@ zU*k>pNa07#y!CaF#7RbN9@nvKR2>)yi?+O_6K&;$dUgmZ9#%fa9yrf1c*cH{yRrF;wd{ zfoyfRm|FNF|7020R%<)h)7_olF6{=6NOcd(cYK_RI*w$(y#Yo-X6PbF+$>^Ln%?K{ z=6CQ4&GS|q@c26ZIMcGy;b#J71A9e0Q8yr0wL^wB{Dtf9ly2g1yEvv1N1=*o z=YdRn073-%Wyf64oRol;d20=9elGm6c-}HKSV;A*Yub~t1RK~jIlmVCt^aWPR4I(V zAd&!SgTC>q$lpdGw?$r4&OtFY2>g5e3z{h)9|2_Qrg{lwwWUDih{D%{UZzXVl`rkT zS=;}IWkJ{rrTHQ(IH`DK8FLD?$3sJ5hPnXQtbMO!8pRSO=Y`o;6y0+DVWApt{OMAf zHVbMi*<1J3rLQgp-A4Q5Ba6S2!VC)UWK~cJS`IV-YE>SxDkOD|!MQ^tw27 z>=1|jd;s6`2faVfcja}`d7Z?)4Hd+0J68G`y;F7^%R_CJLIl~?z24<|4kQW(DctZu zb=dyaoUj8)#8KvJJ=#@JGd717@ZRBh`3e1j&tO>gpYjHQdYrFAerAJ6Ghe-k2j9#* zY<~G(%!6MLxm5$*J@lpmS?CwU=+ZC9)*c>Bg#O)tbHMOUa_a!98LC~IVfa{UngNRZ zk_pqylc*NyqYoSrbW+4cK!&Ln9L*xUc0 zC{POX2^7M@`@G@$n++9T?B?uE4Bja`%+R`4sihwH?X^1KqYQ`*mtS*`DcdsbRLi<& zjay67+158Vu_nKhvfAO<2;z?dR))WNId;k!m>Rb{u!Zz3Gjs%vEQ}5-YLCs=f&LES zIcOGk$0=^(Dwt-{qt*m@)Es<%D+GSvAQ^oC{?*Zx=n=|E2h?_0Di-hb^kWKk^6vXJ zRgwU=KS&H25WlILW$UNLMvVF$1NFf^`s=?gqHQm=UB2 z5WL@n4{j39u^cDC`&M`CWl?Y5v;Z2t;-*lhNJ(ik*}%>~WQQ&FM(nj8<2h}pj(i_B z-~@jsXYC;TFs0g|)^^Sko!?AdlJ8~O;%1{$S3~YwbH!i(wlBrB^)TMJ-r(nxp8Bs1 zUmrGK*>h724fWXL6w?=ad`$b4&BNx)W3Lvi27Kg6=#ent_$|hl1_PN)Jj4W-xCdzMDdCw^zkZ#(Z4yRxcdJS3@xL;8_{yj7Ia zjt)TtwF>h*ko9fZ|2`i4?uEUjv0L}Ych_%R@1A$f>mXYlYc9zBa@wSbnD=j4#&{Ou^y*MZ1Lr~ z4hoGvxF}om0QKa#E_RB`I-@c49fn+1m;&cDvEcJ0KFhh|b7|~d#hi}Z64$d%d^O-%PB<+h(QzULh_5}xu+;c z=MS!bGo2!YiUo33cb1IL?miv(!RT=D8h?zZ6>O4Qyv$}%{0;TV_j#M)uEZ|#>jZ%G zml60QhmNG&j!3HZ)WEyacA;2c=?pgzn#{hwsK_zX!!Qu_k!-B1~r0cPs z3o5VPF_B&E)dAO`C;5+?sB87teT>}{E>G;EaHZZqzg_1NP=Zn^O{LqISl=(`^yHWz zYyE!hWK<0j`{Z*l;)J&6%z`Yyh!NXp5HS{_N@V>^r$niG5QAP%pj%*fd9MSGu_E(c zruorcSB=TC^gFIGUhd>4ztx@3z9&#MPE`^Fc9UR=;MIs}9|_EOgF@D`YaH8=Mr;N; z2Tju>-+j|4EvQmV5V+qs9#ZUqo(yg!<L;&bf;qbIlxn=^Tal`F(CbBM7^mEMFr*5O4;y710abCm% z_~g?IPcJV|nq^4mE&gHSkY9RWv|n|4n&}a@z69Y*q}yEg*S>e#+6Ti2qvX0jQkVjs z#3cZP$=ihQ7V!(UI*CrP5QKC{r^VID3GN4lM@Vd+K5dAHUr-roF5rm>dGqs`+VPNh z<)3VCE_yxX`VAK9iqizZ8#bJ7_34&Sab`3D`A(hVOYg#!lUclz|P(K7>*FY*(j8vJV-gWsXVKMk}w3k9Q|$vOvt&}(Pu zNv8T8^q9)T)+Qy96=gGxnBT_Y1u5o~k23&p=)k+s)sfKIND3qDK&8PCjFQW0=Iq#I zPQXz#^`lWW7T70?@NrnZC$fq@FdI!S`{7+>ezK{n^?V)ZNo-Ky--IY#|A1$?Pqz8( z>N%zq##0AsH?zm5q|BIE7fh^wfaFH+5O$&%TN0$(*s;OsXE|`dc>56L^X8I{(4OFm zg0?7gQ`lGwKIF|wAb#?>k%AGwl@5{u<2+E$74wD5+}@F8jt3q_wXGf47%Qv|)1)u| zmuXJR^u{J=);^MO>K8-;+#+&8?Net1b)2NA_PhqNk0WPwwD|I;&TM)k z-k~-xXn@usWAR~Sr3)JZ#mnTtcMz1E2{BBa;jEJQ*G_AMiB-4c+xM)eni2EKe_Q$z zDo+MMraII`kPm<_Zh@s^$yrg3#I#^`IaI)4mk-MGd z&W8a=%j|d_n)IMe?yKWWA(By#YZi}kBX;Ku_U$6uFH(2lh8*YKJ zVbh)SR^huw6%zOk=8Jih4Z|CuhZS$O!A>$t%)VJLvG51?um;-BcHd?dyMNp$9=DaF z*?#1%(kgb2)F?#hX+(7_q9$}mb^o@*T37(+yXfoHBsFidx8sAd#)szbCU~hvO4r&4 zXuXU2(l~HOHV>|NcVn-zP0^M+si@BHToHW?ftfV?6C=)6B-i)F`J z5I6`TNWw+fjL&)0L@}zwbq4*4&N=mcr&}GmeK-?I5JRtW_Z%6RlB1WOE#Z*@4ZC&? z-tF}agI~`+b?3I+$TrlBSPqV@(x1QlA9i;T$qc4)BDlSw`B_!+eI+^^CiJ}arE_nO zRSGvgQ@1Ui{4x<$?RADMLw<>HEQC@BPqbgDG3cG8KjSDv3)eOvHx(Ma?zgOEGCng z00Rf!hIO~lP-Kcph4-W7Lx(#r#_xSwuiW%Dn4};RCk6HB)b;XNhiC6;|2$)2*EPII ze1f{sw|Q+9V_S|Y$5gvl)mC3D&*Tm6cQ->wVBY$eXCVu6-qp!_zq%tq%9}1E2#JpV z^c{v#Unq&WH+e;fSBl*2Xg+h`{q4YTF=~`z8;=|6)xD+E0R_93bn_AU70J3(lkMsS z93J%4n$A#+^9u*hFZ`t7#%P|c<~#+pWGi<{oaOFRfGBzhhFkWaQqF3sLyXaaXa(n& z2P=LS%lrC}k}za&7J0Kg6%eJJW8m6xHP}^O@-77jYSQn%_fdR5q7xJn|=WdbQ#B+rcrGma)W9IkV0L zYJ`-tS(xvGv9!Le`P$cFTDE>o+5SsXdsT7VHM`|Q)bnMkI{A|7CvOUzVq*5SY?tbf z(JbSrRU7rM;Eq(CS2`I=ebT$k=FUurc`>?3es59T4v_%&td-Q!R&IZR$yQvLz2>rt zYcb?@9>;n;bvq@by(w`f`)oEGokm-@^ zv-TU&T;bLV&atC+Xm0x7DdLcBwO5e4D~geL!}SuDFs;@!S*s|i#3hGu*baf@JdwBL zoLSxPgmivpYT^iRVFvjRUDB9C-!02XW>og=s7jia^9bcM(?PQBRdtT=i!3fIVu+4z zKW^;BDMK;V@Gs=?hf>-^MydcS`6#K#L5}x4Ojd6jQaEaO6f-yecy9GF3dU_ekGbtX z><5F#xgalWnT31TzYy1SeC;DX!l+dbx8=J}>` z_tK#ajOwR|8f}^J)r|D(j=g(}^Pl;w31tP_OYxpE{Tcqni zp%=tGJLNu7^`si->?7D!6&c)4!SXJeK=Z-(2aMwil9n*Hu2a=p63wV}CAJB#!T(C& zKKm_s23GF(Gq8N;FZ#t1+C%el26J~!dBbH7411AygLN8PuR;gaaSpiy6qg=p!za!+|y zV3X{B6cmL6;H&Bhn@r^GxFKYu=SJkTLsaU=+0R`d!8 z470DkX>AzR?@_BV$v1XA%{s>&g$gG+qBTRIQFdJo6GD3Kb~gylyV0eT(Z|y~FRln_ z<`b=a9{KXt^rU_;ey{5|oVSe6z5cT@Yg9hDa)aBYC0*K#V_O7Rw&fn{w z?MeSJ`G!m`6fW>Nk2v~Pwl^+qY$5}!Blvh|WqOlhuiHI#MR?5D-a4gVb0P$4{05o#Kn zK%49!LXk|~PAGeO!RsLdx*&Hu1!HU6f;(J0e!HAnHE9G2p|fF}h{$}dF#ym${ilgX z;4YpJfe60sQeWO#-S&xIPwd$Sf1Tf@S8O%hn=B^Ng-6{bwl^d~FO1y#YIpN(-_El2 z=HQ5At@)#nJdMi*AEYSAGO%Ry2M;H?9KM;;Kw%E(o_CH{`{pB18ZX~{5 z8S)dNXBRm`>d9FpcmgVY9o&3)5m^1Bj$7Y(?Fjs_na9JTgx zf9#f?fU#>CAMimZI>8^zhxkgBbIcQU zC2k0x^viOpe2T`ED!g^D51>9O?#sNcjUXGGqJDYQ;i(%BZt^~~ z^8{XMr$fW`*4$?O@$WT@t4gnPIQdeUl@!6P8Hno33<3XRjV`J^=#6(bD#BNWp-@K< zZYt}^yNJy2EMvZ=K}&DVA_QKGL?$jMJfXf-ee3RrFc+ig*q-wtqO)I3LudwQqojHi zD&8AtlnvHN%yTTgaNh=rXO*bZrjx=?!)H>rI%Iazq3YssUyt0+fjh#-1vk^-1;%wJ zNueWw+lsw?730E3T8ltp?3wF2S;U-clz!%;YRnUev4N#!+5Hn+t91T~1bGVUBE98( zmr&?hsx^9GEUuMyc;-~vVh^bSqFbg`8H zhxa^zKm*f=IHDe=G5+Gc0)j=u>t~sjx}pIbgF%o{{eJMuXgExc?Lxp20Y4Ig>^|iC zL)vi|R(*^SL>^&i9qE}=pLbFO!!rv#r^Q>+sx6aOfI&Rc1}ic2YdsaZaXR%oYHVmmZnI~kF6<70HcLCwhdzT&Q0`^12LyWqM1v1xH_CfOCUC^I z&&E!$hbV!VEGz)-KTbZggcZJ78ScLq_v#TGLOGAUhnV>8;)#ODOS&j2^1VD2zOieU zOv*WX)B!?QU9-N5TMQ#71R!RNunllL<~U-;UL0SqLg)9W#cZC|J8RzzFx=G5k-8;n zxGBDGzjQ0j-e(F7tW=v}S={frna`zh;Fanp3z#S7>m%dh>GT{X;-q216QFp$zZiRC z*FWHZ(e3Q_uX+zBXIm7n6~b)~=2>x)u|Yx*xJcdH;=pApInHxIndWK-1*gP(BwtYU zO+QAfX+X^*vzUa|fADvU9*c^Ik!X^iKxe#5Z=KbDTOXx}Plu9HG~>+Jd%33)`T5ZT zMh-N5X>Zn(sKm0>W~jPTcAY(`o;0#>wz|zPE1hZ(-mJP_q1VH`wXEAJ7HpLMkl~IB z9bA|%_@3SpGsE7x7Dv?T@JI!3<=(Q=G3MH{?bGG*6Z754G4zgcend})`N6PzL7rg@ zk1eFWa{G8@l%?s(Daov+y>Q0$`<=YZl%AJ+VKCfsvEzJVOYPkgLxxcv3sQRgjIzgY zF1yte`YxuMY%@^DHYy$=s(V@yB@&#_wRuc^vO!|7^5z6@)*fzAw-p+n^@pEQ`^1YE zXVfQM>GgBPB%s90kdFt6iD-dOQc)}e-=B?t=5s#K@Ss+;qLWw8kv#5<-hSUqU7=Db z&f9wtSJiomkk@|W6EbO<;DLl>axPH8F*OTv*iJ1o0`*wdn(}b6u;D5E-2~*m`vOXYwEh}3ewM;U zY@)ovqbWCcP|GXW?UzTYn=0?)#yMIrPmj7edyZcYmvvnw=vlbHIFH4~)ilAn14YHU zWgzpZ%*VVd_oF_o_$&Kw>Te$f9sx*y2k8fI{B6)R-iOUZqWzu|za$?ho z-OWAWg^S57m~sXh69G{_ji0$y@|h=#rqKtLVC!VL^~!)c9HO6Uy{OhGWGY08bR|zO zN6tm}R4_>meL}#zAYQdp=Aw;>3r6uwK8htX5lOXeT@@Yo%>uVSEQj1x8daaLT-PsH zxuC)*M3WW-LuEtM&y|>#dnR#6^PfomaFHQ;?_IUb(`!iEc$?F=#j@VZ^IpQ#rtU5Q zYILdz=W5adHA0xJu>l?)->zCn(61Q&=DmQErwQ8Kd-v+-yJw*_3pyM-9ffR?*u-zt zMltl-H&7T2$PFP{Gd`J#PpR|EzaahZ5J{i;_&@=3yFm@Gp1NKNU}#p)Um3u0scoh)IS_l?jsAD_S|^6v8By$(MBaBvyOy$*&xf&N27)}B zs9HZnHY_-X)0-;$b80O0F9;ZZ<2(487FM26ZR0>c_u>^C-m~|*2n?dp+BfV1b`&v_ z21q+=P*H`6SUX1bLhMA=IGts}>qq`p*LCRnZIVJ~a*^eAu7p<@|VgmmZQ5X#|gscvxco#jHeAl*VW>q zC@h}Tn9k%Oaw(;N~=J7%BeQD7m4e} z`c`pwZ%{PaP)A8G-6ISw{y+BKE2_z@-TMwjDIy4hfRvzsH0g*m2}QaPiV6Y}l_nrv z=_C}TLns1Di%1s{=^#kxp-2;?_bMe4dLU)Jx9fSv-fQpuy2p3+oxBH(kueC9WZrXL z^*?{JyM-~li1V=gCvu5B6syXIf3jsbX8YiAgGL;O9d`_|kn|C;@Y+TcCmHKjPG+1g z%*`L@e3i$o!mmgvJA|~23mEVAykut1CK&bp6V~C&Y2Lns%3_?6y{W>sfPaQ{Wz4+x zluPrGOK{U*+>^IF10xYOuO{sFw{&|oq-KyKT!78fKXd}XIH(w*07M&4vF$sqMN!1= zrVF_f#wzI9*cuQPrmNtmeO5W>a1S*(fj-%nB%b*#GejPp1^!Si6@sHfB&~Sq-}f?G zyMET==992*ZXV}A?LzcY3Y`I?=!%=2j4J4}u#_&ndVJrT~)SA?aG!E*7_IaeUU)uq_emHQ!EN{)G z2e}KuW*dYKzd;qZaPk=_qHADHAluMg{bxHkhj%jmXDyoD5onzwA4zgh-(MgK#0q$V zvxr1_7pQj&l6BtnB-MSB=4nr%cmfo5>^|y z(-WZhsF_Dl29B<%+5=_)y~ni8FhUL$MJ%uYRr9`F)3o^}uA40ELf*jUhGeS;#M6h_ zCDy7bbkPFCmv5Wx8mfbFkO~0R+};D|TO1Ls-i+Mdh7nKF z$-pMBvjGQ@z06io4f1WcazQ+tyGOy7D}UrYopW3XQOst=urT*|XmWgbm9 z>*t5y-yde**4l;kwc^}zIcfM=vQ7B?6}3Q}1iFtomRvbp-)2KS!b&RnYm|*K!@fhd7u-}z`aE*ND{*d zR6sTOojwXrjqctX34P1yWu6Rb;lJh7`Ff{4dqRk6M{?+(+ypj(1foVHt#gd-reI__ z>DUN5k++n#Ducgi%4fG?z=$|df>c!?_SazebHAI|E&Y(6EJb7r$vu@a*6Kyp2#x`Z z;9oh}z;zm2t@F6M(0H43xbtbR3h;$=xg+A_9$SCULaV`G`wPa6ERGtpXK%`{Z46Rz zJCR~lMJ4p{k|ymQI+>Sr$hV776GclYpJ`g_7A~d`y3y7*^{3LnQtgE$8qS1CJsyiY zjVdjAgXgtBa(&;Fg(WMx$AWoO?(Ob$4dcU?#>zcEx|mpXKCSc8;=XQrsvOR~ohAb$oKsiSH>ocxv|=EbPJiFHW);8ijv>5@ ze$Ch+f1V%3DvUu|*Y(rE&nXi=)n_2-6w&zlidOCmVo%|KMIXvlWgNBQ9Nf9u1%)ja z{RL`gBO31w1aTERsw^%6T?@>nP$WiwrrI8?+w<_iz5hAZ#}-DFc`x>*l*?R0Iu+?ToFu*$J!TNNZtnDCzBB8-EF7?j6JUJa;Wfp< zegTWq;L{B71ZF8&7|8dOO=w2GMFAK75r2H~JL$_Q6EVc@XdBH%ROX`YzqS!#y8qrv zq|M7cBMql3t>4_<=Zxt=xy;@jwy*3($- z$8f)hc_KU#u9zTWENrWHp*0NZ!hWe5-z4h2)f?8@(UtyWqhHk+%7au1N3X7!}6B^EGg^$r9PJ z$D6>nf3g#!aUBvaxz{8i5Lwi0*#O+(_#Zo#f8d{6_9L5LWb$sY%0f=jM$EG!kURew z4T`qj;AC$G}%o@`VAbH%3az{@b2+6X`5 z=0#x%CVzBqYa*9BXiaKp#0J@}?zL#G#&;z9groMyzG^@x2AA^GtMOvSii&)Cj7(&R z2@0^a;T3@GGT|>`(aH)4KK+yJ`dZs?@|J=ogl1J>o53ODqd-@UTg=7 z6hK4*C9ntGn`;f?EP2KsXTSu;lWqWy4HolEI|y8o70^RVhW;@cNqe&!M%$ujti!*% zqprQL5jB9*(OEA4{`KB(55W8m6MiVuUY~X)=_foun-l{V<BQIWV6cPSM z|10zMTm$ViJtc=E|2}c^{V%IRizy8dS;FI%*qF|?`7RV96#jw(^DY@^)mI%J9~Yz? ziQo(5>HQ!kaVw6;N#2Ji{ePT^J7qPk*JYHXPDkuv)mNxPypxg<+{`xl^A$9mnuEkE zQ?Xg==LH~=BkLtlV1bx$Jy*Rj8WBi$l?z%o_{X_OvEt+GD=|xLS%$29@81hEcr&8d zYQ5mwvV*cbG$Ak(@5ZIUXg2TYu5exfntnv%za73Y9T8lj`0Eak4eUPuQ#AQpIF?g- zA^GxtpIHKDB?SAu?DpziX*T`d&fKl*3 z-&|U#Qyxg3UdozkbxHj`M-%(!V5cwrnaOPKwtO0< zr`l7}ju7KJ(a_ksBEFIRF4*vypE8+lf7hxrBmaK%VqdJFcSQ2q-Mw)#pz6>k2?B|U zKTv8`euj3iI{PC?uXZ2SWU_8#&ZYCP81l*+pF^tHw105zYK`B(NA4%tvj@`!$o$0| zCd^XB>&+!61+!SgeX*Oa&r-&12>e?-S7k4yQ`X&66YU4Na_|(F4-L*i!_f;(#jqm; zZoxSJFOa*2|1F58C+zhe=$qP0?#24`l7oIYa4TUzApx>|ytvk?FrK^MOX}=|n{sj% z-k*^I^5d{TDp(~>hZxI_&xf-u(GcTNc-zw`&K7q?TAMuQ{gW5@iPs;8?6X7WNKV`5 z!X7YkEGx8A927=#zLCZ9d8w-${B+qGj1trT_#KYbrDjOU(OJ~BCH*>@uF6V=3NWSu z$xBeZSshiZI`Ois9sb<*yN5~S^FxQ1QW01rb zqUz-5DY_4!uWw%L;R>{^0U53);xR_~zDI?ki*U7`x&*7DRm0Sbr$;47p+Z`I-h-&j zm8*-)nYmZIF*TqY@-jhLdlq}%r*KwM9IKponr%oujT}Bv0M&RB#nHn7iI8N>{%c^TMYbxJLTo%d6tGJVGgi#N3jE1Zl8Vqxtp%V3X zLv##LJ)rg*@E(L0jcn-(&Z%4D0+xAh-8wI?Cr32ze46Z>#{djgO(KShElLHBmAWqJ51vP=DiaRf%2Su5&5!g zi{w@8^wKRA34hG#9r)q@tvvV7lH3nN8nW8a{NXo*XdP@I@{n$~j(7=oi4=R7D4*;m zt_0N0k;SFEZg*I8UeoalffqAK?|_xPWVizF{L=oSvmeEa-Y_v=8h)FfWTk*Hr6sxS zHv@rG5E5^`&VMS_20gj><1bKoB_NRE11pHHY2OQctgW+vD7aBu=o4+ukB@-p2ihOA zMA9T^(}MNg-+XIVXgO3_o@=%y>6QsQc&>`91TW9;E%2PR`ki8#JHh) z-}`m*MQHI5hNz>@u23>(5$sH>o6Qm@&jgqrYvSlcBke>Z^Kx)WpMM{^GQ zJ%snu$M9Z9ffpwg#Ggs^wx_7Wf z4|8LBeM`O00xO0~MQ`nFqWm~yp2odK*DNSd*Ep|YVVAfmBSn`ZrKjw_lW=(b{;Mb_ z?Up8neV{gY_0N8dm58J7Bfm)EBkhDA{rF2$k7URtN)LYT_e}O*iboUExvriU(tdDaCf zzjxFL;@{t?e`d50>AJPCsKJ7VhzvkIw=!JVpU8M%a5Q^GpH&#rp4mqNU-$w-_Lsyh z>G@H_;fF`J8G>4Vd1vP@3yq(^?{Vpeq(pOho(X^Cc*`4_n1`i!$bqBGK|>K`lq{zA zr5tr}&{^9-6`T`rWU%4U3dP{@XQt&7vpeFVc9-^z^!Iy1M|S32b;WsCKO(HhINQTsPQ0@tR`=OGFurcMp9@;qGgMLzX$^}M$fBf~1Mm?{zIX4$ z7od{a!_Eea82jhj`p~Uf#5oe31(kcwSG#S65Atm48eC08D;&c90^I{4^ydFjT1);5 zT#Y*#fbX0r}6D4O$?eknkTP|G)q8uetkw zGxq=g8hiTO#lYvA{I1C1x%+BBb@qJ>NErCR-z1+K7VRY5@(bz%%4HWP)NF^LNuE9B zy^;`dZL20u1gAqS$R@THMihB(gd{6Up~ttL#K@74m5qHoAM0fvgdaza4l3xxI_QpS5Pm? z%jsPrMW$yr=5aOrIjExVtHm;4;2)dRRHQwej<)s+t%Rag%pc&CTYbqX4R_KUiGs~_qBvxi_1TXzu?TRha*vP zDNcgxy@NEd{nC_#y8#SIr)I-*S`JCIuQ{d^m&cmF?qb3KDL!)Yxbr42(=HGuv%;^s zC|R9cF09D!cXxMW-P-$Nl_&Fyz6IBb$*b`|*8rst*Y`nUc>l%0Xjqkblv~gP9Hujw zlrgrpbcN?A-HXa$YUAEr79UmGd#e`A#}Dv7*X3OF>AFnJ@OI1gLc39b;XvHP~|Tld_=`@n3cJ%W9g8$~Tvu zLX)Vj$uFafUA6#w>wpeH(W4z85xnxGd`Yq-w1jxO_Dl8^+_Dqaog&QmC0o5(Upof* zw$jUQ;l5)hc#?e)hD6wt5KHdcwo7Q%O}d4R$IuHuRfWRNG}k6L(k7JCf3QvVxEVq5 zx#iOcY+8=>#Up;4aTZLZzdY`q>j+C}=&PK$dtFFZaLcy!E-+RsSXeAZK`CFHSO(oL?Wpo_cR zAyEHBicy`|0$ecScn3ZVV+x~0Eai{%2m!HAJ_fUFtw(=tpHGl7;T?AH7Nhq=^!Bi@ z`;>Bvdieg5p)w~wa52%RXYPcrP#n5@s|E4Z6j+l8IfSMX6EPHv-g-m6=l0<#WRIry zFVH93lY3vt&mqOoILJc%$aP3X#7FzC`Rd6-EIEY@E}j|E@mzFPHZItI4GkQPYS2V% z+kX%d)U=*rK%Sl?pf8nuG@aAwXes5TF)ff*1q418zzT?A(3m5<1M^iaN)j=KKID&t9S^ZQt zA3;&}y;KW>x zKH_f?q~L=#g1hD6a+&1`<2LfRseVT%f%!>Or(_%2efBrKu_BS)65GPh9C=Ec9|SEL zOf_KAZN8csmOnIE_zU!rwYlmLYHNl6HCo5weUlE!<#Jxm&d4RIr2u@e)#4Pi}k)eqSa8f(vfS-`xYEsj*7i=O}g)# ze^vz2>G~TQ<>v4keKv8pLqUC)yHh7cj`*B3DzJ`BE`t`0Uyq2yQSz5B8@VcIG%Q1# zr)4YV72K(^)3S)r+7oAP@&j84Y#Zh)4IT|xAMuv2mMw&+OI61 z+mSZ3=zHRPgtKaL_asjx4i@==Ib}B zvR2;bpFCN$n@OG?kknkEHFi@xqsOtAeP8n@JT1g!GFM|aF8&G7hKu=YV{FfPCK&#^@%FX zy}p%KMU=B6=@qE9Y#x$xPX=x!%+8YnqP1Gq$>^PqO)j=+q|5gst-wJn2IwUtIQV;C{*Br?bO32^9# zbjG>IH1ICv$ZvFD%N&JXMX`O!TyCT_5*olJux;TulHJ@Da)t5+vVwuGUukZci}HOj zj}b!s#I*X#Ijl!86{9+kR6qAtx|%pmpP;S4eb^5&6iHY!ZcVi+rlNAav0~h@Gh6o| zE5kkWi{^1S@5dHiL|1&N7+5$&T@mCcl=WLfNq$XcMfBYI4(LXJ;ODoVW2&}}1wI1- zSq|%+B>^YlGOhxrB9tFGDbzwa{R@b=ZbJzeLA3Qa z1WzR|0eDX0}6=nZ~^lcyaDI$ljAXYsE*)-R3QKV z7eY$rUkIu7>FpOM?c!B#yatS|JrLo)K#Zex7n$>^Evb6VN<72LtS!);q*& zus1*lcQEd6qRqEWqwyqKliq`#(-B8anXBEjlS2W3U=;WWe_(#V@CxdEi)5DKt-nCB z+K8h8phplMo^K6+F5)ns|3>GSuhS;>P7Dl(?(Ob_w+xdnV0NAfCAWCN8~zQm8T=od zoUq@+<{>@tP!9fLch*N_@XzM}>qk{1k1Wo|psl7VgaPAeU|GVtHolJ`fEMMWC{4EA zl_x#x_y(GZe>0BO{|DpfHh|0c7zd2OE(F;J>VU^QK&PU$b&qPW?Jh5-lbfv3i@wQY z8;^hZG4SBj%<;AGbcA@ahZ4ze>*SBDps%<{^103hDBG6QRL~<_SJlEn*22S1sZrPW z$B7>VLJ(i#VXk;cm!)|J)A`9QUiwk-8-@~O=^I~vRKK?<)SR{Oa5=$*5`TrBYycEu zr4*PGqLmx+jK^S6r>oRGa!#-zl_YGc5)#mow#$H16wG`9400`b0C< zqJ+^$=kX5MeEM z1&h*7->AD5X%i#s6R{dP9t{#Y9))NImB&kE2AF`uU**eOgm{Cyqig=Z9JA~C#436O z(d`Fp`;&8Cdt0XY~C*Z+p$|kB_EMzZH6~>S!$Je%0*`2|eR3JOYv5-#SD(=R; zP$Fck`QGkt*cTj7yYTPd#5|Zr?ED+O6#Ux`^swPnS-QMrAWOyTyI|V_1YSXU8PbHm z6Jp17a#_az2*4wG^Z|6a$1YQ(X z?D9}CMx4+WAjyn$$yzjIHW{StQjjfhW8l_4T!2|y#_OF2480`!6g%B_mZg$moqCVr zk4&ehh}Kq?L|I(M^+ZOh)CyUOhSVEvk}I{y8t2{NYdd8*KnGbioUcc=?Lmssha0 z!omhS1)L>MdRxWhZ>CP0fK07y^`oGsAk68A-Aif0G~LQ)Zqz5>EB$S0_WwIwh%X%& z_UZBr{9+gFCfDC&x!+(XrbNIt#p+TqCo)Cv0{FJ^b$S-|>|=JFQ$m zltI#2gmg_KBFO>`NlnsAV~^c`+lH_7`d|LG4Y_}|4Mx9h!(%6rMiGG&Lu{avV{I>H z>j!I0>nQWkz5&buUJth1Wtu7?)6?L#j&$R!h-#xk&Eo=48F79i^&69B!&xksZm520 zS6Se`H#l8%lm?r0Jn|oFGI++HVs`h^)N^QeU^L@s_b+zk?q96qi-@?U2PJp{?CY3{ zJ;JlZIU}q8*0=rI6G0zE0n`x1bRno5HL#zaZka9U|MkUB1j^i#&r)Z#gP$_M1R@A%VQ@RiWfgn@*o^DHeFH=`=tXuN8R)?zw*xX!h|WBj zks%32wRqi;pPww6fM7mSGXL$(cx4HLFT2kIE;lJp2<2WezRpnFU+;fi830h`5tU76 zGzdYTTclPiP5?64zxLa219auT@BoKV_$a+u#4wp9FUygtlLpZAf3WzyG2RLoBNoks zk5q*K0HqQ7=8`(At&k|q83OrgVZvMu)LT-~uI3AHZ1caR@^hkVl zh%_e%kK#rw02V&?ivR3OvLyL)G4G4SSFu8jQU(~p8b}Sk z4Fcxt`TlQQRyPxb&NvXv>V0xflsNMu;pU=G#m>lvVUBU08%M2P%hus?`TD;{{qF?M z&G9xUUJ?>Ygnn#y+Kp_>7<~Bzh#FcwZixAPU73pJ1OLhcI}-w1;qu>Aui~E!TH@sM zoIY$=zID9RAZfJh+xQ zb@YAEH5EDjMT9N9m_N6myb5Bi3asm}U5TB^X{}|*t`ZRJX+dErKmy(322znaslo)1 zfOQeJUpqh9rzMaC)adIKX~=I40ZsL7skC@a1S8Plg;n5y(mMpZehQB8dj)uEcY+V3 zIIe(l$F(u@S9tvVvSFG`>6^Ai4-k20aW3=vd&Mw$b%?L8z;af?QhtJUtw(MGsOM8+R4&H9Qp+Y)^T^wRSaE>;V;4D7Qe}!mz7>m0{q%x$>aNRZb)uNzE9r$ zAYXJPe3)QLl;yI+5CttQtdXw~1sFVV`@=%pH^@RcAdA1KvkG%m>K2$coY zArY=(WwJ+yqhy&NMuSG_YsK!aWi`S-EG;ahxf2J9x8Eu4nAJpsRxYUVuX_hIe^RZ^ zJzt=o@BSUz)^j?Ex|i(m+G|F|(aikvL6O@h>3b661>^mBEx%YSic+wiJ!@V((S2uk zPyvL%BV`K=@glS{uj@Pji3#21zrA<)iN;xiVS1Kvg7@m-^nh6QZcz-7Ricn{{0+N^ zSY*deq-AY^(9{ia_B(Z9Yr{qE8QQgpd9Dnd%{cX+F$$l!j?kpa=aSKArY1$)$dMcF zaPTFW18-{POKqOOOSt<*v}MLR^$7*nJUwUguE4VM`;Pl%8KQUDIMquuOkE#nY3mye zVsE;L!2%nZm?Cpi^=k!}_!a7nr1j=Zy<=mVeB;Y~`=@$WQTXc&-mFlz^zu~~w*C4CHAljv zX_F3?j&SEGj2&W+4$oo0_16|=6t(xcYD}AEEb?19P5JY`*yFTw;GoTm6gcSkZ;T2o?;~?$RoVLaG{sckrRh(j~uujf+GQ3|~ zPkuY&$3wAC%P_B6`@Tz%HV;Uu;yF(Jtn4OA1^%s*?_D2O{GH=K>wMuxwD+`qZ?nfG z(y|@s^v283s#-*QhVO-G-#Rs;&hzs<89G&kE^ipcH;tWS)j{NEq%5Cz-t&Da5U~}v zUO;(yY)j^|Ilte6W76R#^pRtnCPBxK26Q1vuju^57CDt;VVo~c^U|4ETN<%xl^Ec; zoeTX7be?^IV@i0OENUpXs;6*m6XM47y`cjA>k!fgSetSR^1cDlgg8v1|M`z5LCHJd zOaSjRxdFL)f9qt3oU00)0SQ~#CvZ8d#jUN40A(Tm^3EC$)-VtV*Pa5a2IC%bs-P#v zO%?e`5<_<2Q@;c>$L*-c;+G@%8w4D2MD5 zR|dbWg`tSpy|` z4(PxfBZge}2Tdvx6;LlCp+%-1mKhu;BwB;hr z#DWp`3D<3`ea*c$j+gYLH}CP=c(=u^H4BlNff_Fp(CpY?k5%QJ+Pt48{j^reRtH{@ zpJONO>P79g>=wYi&ZD+rQ?-c33p<9(A*N{-5FK3cVx2Tvc$bA(*!fKlfeW`rkEJbV zHTvC}J#>&S+Aa)qdvL9CQytvh*MH%8&(X5r`^PNzO5~2jxV@Xz@em$*=q(>yvc+(thUMnR5?;;0DNEVa!chyE?`-q*_%4_&~E9{=t%8QSI3C z8@u9Z;(7MhRkSR;{ZR>@{Ngs57T-@0fq%;p`LesyYRI(&iBr)}>?cLP!zY}3T(Du< z`;tnT>Wgt`Ot}m1w5}{b25H+ z!u_Pgt5wy?X2Y;%8wF`zb+uY+bjH{dSn)1P;P&zmAoh^knK;F?XE2m5y)C8Je&fE+D)Z$2s+EHzeD3JWU<`U8!&0JXcOC<$z?UtNs4!wh?MqDO zAL{sBFI%lmni?~R8osHjAuBQ5f>ac}+?2A&j=hIVSvua1x5uR)wYziv)M=kO>_Qhg zH?v33MA%9vR(q?>i!Kaa8;TAAwc2QI5zR;+fHUTwP7^ftLr{ls8fo*%h(E~?AteNy%6oi7K?g&V!^U6L<*zp(zKr`>a{OfYzQ^H-lA zw`D(nR2t8|Xn%ufV7o<$Qi5UikIa{*CYEx^*?ZRH!CE&m2ZxS9xpA2fXy|y%ATo1$DWs3g}v}7xUws)2vT0tvE$`8lK za>&XSw@nPZlG|BFL=$rClA5vy`+IJ=NMay0?As)QGv2%1avuANro;UlQ3v-c{ZeZ2 zyq_1BKbEM@>Oa+Ckey6gPA)}Cg$+<*m(lL%X`RJ&?0KByVtP2l@h{Lhmz+x@&AeO_ zEa&!FqgNE8AA4R^zLc7Fb&pcPkx!PiIVjyh(C5hC5)tW@pu6?HFuUx?mFrsdboaPW z@9cG>he6zVmYJxU;_p>%StD*R_YAj^!am8;GOhP9mYaN5^06 z(f}D>#jogHb8GZ&1bVmBrm^lvQQE$KO;vS-SPAvEjnwvsHW@D&9xEQ&8;hvV<`^va z$ddFiNMw1CciK69%IM{|xaXNLj9?#~tNkkN4T{xB(4oR$R*=RntE%koSY7F4 z^rOhT==#P4nX^ATl4V0$c$@YU4%;e*^IqlAcF81r2b4|`)Aq&&1Gj@O2?>?P_iv89 z5TaGOyX+^|kdbFAI6Zw$yl@Z zO;L^ff>y9R#X6B-UP_)p@jORQnIC=JO;1pva4&w~6hP`Qv(kbmVZ36}cDsB(x@|Jr zs+?6}wlSksm}S*W^iszFyxr#eRi-7^8mo3Hoy~I77dP(SfBl$x+~IwSMl_2W+(BT! znm3DF!)G7scb|DZnS*L@bkwu)Eo(}&QUasSl2eb+lox2Ke~7t}XW+a;fL7w=H7W5B zJ_bjAl|#yR@`XAS$5poBjo_SMQ4>YA5+Q02w1gJF3?{y``UrE_3DT}yzh?MRIoSgW zE>K|>fJtyLCo7>^E^8%mhxO(Ol~^+XU0Q);KE6`1h;B>)rI?}L6YsVQm{kt2e(leP z@)h*zt7@B~G>PKq9@_4cfW3x;t7)@G*Bl--R^Ck&K&_6%oJHuv{?WZl2K4`UY6zeJ zEsYoe8&_&3pe1sF(!^xx7W5T(5BeN^x`6IB??cp;WyKQQf+%uSZ)a39hsG_tZd0Rr zfbfvioU^{mTC3XiK1TGcpD&R$dBu|4X>-$-Xfh>4It&DnYZ?g`=Jkr+G zAB;+{rkV;kU%X!42Nf2R*5=Fk8cGay*@pw?EP~-tM6M3V3AX`J`ttB6^(Y!+FAwbn zNE*U2K>K^oYmV+gp62HIrKn6F>eypw;W@?$Il&f9J}(WC6K|4Oiz>&1t1fnD?>U%_ zqrM&#ub!_aB}(XkY&i=1u6tb(e)GtCpLcRg_c%^|Q9vcM!AM7rLio{@XI=fG+=(5} zY_UnGw&Xc?2~#23U`1{qH4-_7Y{oKWe^xcESJ)ay2Yg*bGdRy(Z%C7*bE-Sd>$<5l zIaNInJ0c(~#7i{O>zTaLCE=bXy8Z4drN&~H-b&nE2QByJ)^;xd*I1xG_AMDOe5GQn zPbcY{10KbBAn0ps7tdRn5C6KsLt}()tOOKm4?WLUH5orbaE09S!&tI-O?bY{-%iWF z5{f*IF;Wn!l@7&^vP<&PC0Sqx=TuD4Pnge%2<$0^o;+tO`sAl&0f{vT=xOdW#Y!*kPd4L>mp>o?~pRKrZgwAvK^KgTY5IQm%W@l?AJ> z`UGfoMRol}*cX-QwNQbeH^XYigDqWZn^4Q2eZ|1g6gd=y5`&E>f^98jQc%QkTg*tjhFIk4xj~QBH_CszYZOr0#(u=Jc}Nb zd|z~>*-rt3c*izH{$^gKNzlVnU{$)m+3=5aFBjjGKD<@m?-4K4dFigG^oo7O;K)~B zNR?FuDVIo1(Z|H%1e8--iueDC-vR%P-{E@SkfK-TuxU&E<3mX8k%)iVyl9T&$x1I$pkZwGp(d>9<&2b8z?{SguTmN&YkL7R+5v@R)6|ii+8!y29d3j6`IU>Dsr$Ry-Y`%D2eGXbH=_>t50ckD{f}JBS zzb>=yb#xop2zatF$(!<*<{ZYJ5%WaimT7jLE0Ak^#@kMtP6fUce9A;zOXXqj%ICePyyw71ss)H0=vBiLO&av*)ewWi+x}5Yt0u_YTJzd6d?lKyul@tQ>3$b z*Rqm_IlC9leWW_9=pFLUi_b^yK2X1ws}Wb#9${h_L91v3bE%xNXrx^jL(0^5i2@eiP+UjvX8t zb#TAZN*Je9`_{NR0dC7YQmPv9$uTxOdbxu|Dg~lcko%kPS+r*R^{W+&G3aCyd-PFJVn!uOWWF~ z2lkP+v4O~~7~*GNCPr(PkGd*AQ|VBXe6E(DdKT|OC9stQi~tuZ@16grQ)vFTQ@98? z1uirWbNK(!E8Hk>Tr{-V(rox4{=Cfe;kB8>aTjN-J1-NYiR$V4ToZNX1U{_kUaLqu+zTrGAwnnQc=x1s`g@go{p1sTAJWJjY7I!(=&7w=eJ}AJp(fjUFWp zuxUo_e*p_58%;@5tLa)R^r$4o#C4Y)Pbj#lQ?DPC@h^%S2Fc&J|NW36uR`RgtL8;$ zf+tdzD`58_CKBP$ILHF;DOPDL93nE&h?`2p} z*?8~;_CY@PWm#0Zpu+54gU|7ktjzIBL$YN~5Czk0Xh8~(-qgD+FU4avIz?svGweck zpT4blls0lak@3lSO{3~yw)UtA3GK@ExA(MtJ_PH+8FEhGy6L|p{m@leD}Ug}ZaymK z|AI$SfArJytw(Jx#n^nmM~Cx#rloN)EbfoHSW;FE%>J-_N|tJpMoB2IZB7C1WF>Em zhUdw6F}eRQP^DWPL4&B(jKhw8$2%_#YBr4DuJdv0S`vOOb{uf<*l^-XWbiyD@ampU-ixQ?*^I z>BpgP+4I1_(&Wu>=Kp<5 z$^%=H{hwR1_Fr4_$A8(9auE+D&boaJA*VY37wPfeJUF0*6oy0ee0kb&H1-ZdB4nVi z2?%n#^$5jfkeq?v{ki~g6c_SrAy0&>qBd8zU@1n87nG#V&kNBjU^jqv$xUJ`;y>FZ zFoGAP!UIh%q#6*iP?_-QhW4~_BL_3C*1Lqi6fJF?IuBCa zZR$Seqw$eVIY#spXUJ=RE4)k3IW z=aw)iO?)7slE$`mdYUNW%T3wMHX6L-kNI2(;(uholOLD1LK1Pa`=*!}cQHr79!zou zJ%6Bc#+*BAC3sWi3Gi%{M7j5_*>b7GH@y5^vp&K4~q-JD&lp}>Lc{SCFQ zb7fWX_kb4OrMt|?;(W)sx3};2*?Es|n9zA&kAGIgvCe@tiW6gcOKY3J1w!_QG7&g* zWKbm+v_R^2|X2A4}?(-kpXp3N+A9j@50|HIyU#>4rx?V=+@2_c9sMvX)b z5uG84770PLXo(UndUR&=&L}}57`+D3yNT!o(WCd?X4JvVWZn5c`+eVM{eJIWYwb^a zf7l;DKD~$A3BSm?^tZXDUa&~{lCXPhkMC~m$6$^Z4ednf zc*8u`QOz&`kZep6qC12CTJBr(+aE}{eWE}-5hD7Agq4y%&Vc3qr7EZjv?FOgw~Dos zz0SV2&zsS6H^cQRdw{N8PUM(Cft=~yQpsw1(wMvO40ogm6KRaA@&l@ivjUzUbt3$( zD!OaXGiEH%*tPgoxlA3hKx&6Fa}(3UypsMI(`Y;FwB*?lDTtS@GIAjI>?AgjDW~a zVn5kPPKE|{c`EjeMwjq9=tyM9mO3`=pg*a3j2E)1_OLo*NR;K*61<`eq*CJ@?rKS? z@e6=l=6yxV2H=*_ov?oF5o;b7Xuo}v0Df8+ev~2}Q#i$S3f$son_#h5$cjYGu#_kIt9hq`>PNkffaE%APo_+GBCMhGNB{UUmv^^jrl`*Ks%E4P{p zAYVz62p^QeYG(b|;FdgU#tr^{Tw5|h%Ou^>ee2<_0y*=6Ig>^ET8!Hza0YhcXY3^^ z;$mgX@+jz_6p3k%(_6mHe4yg&WBKx$(*P$4mo@K(6y#Z=xIPQ<96>y& zh_cK4WiewPw>4NtyGYkRj^6(!uST^Bf2B_{<-Y-l^d4C$XkOr*S416DsQoq ztfv74r91Wf0l(mFGQ&BWt?_RN&z8^3L1z&lp0|;RSFy&K%Z^L;AmUC#NT;xWt`3lY zuMWJy`|A!)o>%N%r|x1@jAQCWav7G&PcV`?7+s*Z^WfAh!~%9r5+s9?Rq@{u+JR!MZiL;ip$POjvb7j-7`CLewAl{0$X`q8TJGf(7jiU+n(_6X^In`&T7s9!_( zBfY7z&(hRn)8alCO8u-B16!6vzW?Osw!FydrLF;2^S4lpV_KOkA-}w5OpH~2S zsArK#s(V(|gf3M6db><~WvX=`X9L-~v$8+ApfZLU5=vp3(oT$3Q@U3#q)}W`khJdL zK6+MrDwo@X-pb^{RUqG0+%~aaq}G2$MsCQ7%)-FZEU)ebU6y#;c~lltDR zdQ42Ft%qB) zZ3hFHbF+uLGr)E2A*mk&E(_0(eTPDXe|^2Gh!PBsI?1@ZvPeHE9ebGG=9C(sc+;Wb zguNdF3WVRqg&`dv%=pPapgWpCAa~}=%X)NANDIut-2q6ZO(#2JN@VzaHy}soM}YuH znuhUhz@wgR80yvaNu(W^0h7Cu8V1%zk;K(hF3+oUpn7Fz{pAP@T2f`)I1dsklZpB< z{71>vsN=IZ%=Ihw;jdn$XRm93ZeC7o3$N8}b0s1<>Y~OTiwaGCyzsJiW{e}46K#Ci z6{pp$Y^;FJDhOJ8G^qJqd` z?UO4v{4XEKzQmRC0;c|Z-AqQoXLnm$$M_xU?xe#oqS#1-`6-rlq=}gEw8(<1uuX+PHi&a+zyp*|O#>xvRabm4t(DTqzYY}r-iBw9;e?(}lZldH;^|M_+6l`*PaVF0xv?b*HEo5ksf;#POt&lIa{NF# zGVq9#y?Tr2Pe*d45w=9DqN?A834c#HT|Ii(2k85eTlfWczJ|I4Fyad2?foRs**nOG z6~cc&KKb~2cpH4siSPxX5o}6CZ>IoAJ7TwYy4>KKhc>}pA+E#Py|@hJNipvwd6~y8 zK@b0c1l|EDq*LpqIefPb841SXrcW!z7coNPIp84qJJynf2JnBl@S*;C!oPE&XXoNS zmq!>Nq2(_Z;`3a3zi!%cOl4d2Tnv99gi z*;0ZO$hWQ=?X<}L3hpG%Fga0Gq9t&URSfl2sNQ?a%q7qL$yQfQc#|S7lwsL*#%|M; z?V&uEJzVfQVtNpfP!0Qx{5d})ZUOGf%* zM@!9@JnFKRRy`uVGWy!S^w%Z-SyaP#+g<29o(My-0yOI&!9GCMHQQSiY|%gW`!ewE zJ+54hm;x?Je^K?!J4V#(=eq%1E|BzC1g3%BfsV~Az)@AZnj=`crFmr&`mqlC!p8!I zb@j0Oxu2gAcLq}3Q2yoI&}|=z7T#aAT7`#!Dcyx>40n*ICV6_ZPO*KbfjD&_NEsWP z=NV^dNL~!`pCqABf2Z7|k0xJb*sDO-uh9A_V^VYdo{#z|!Z;Up@QmM#Jim=QdI{;7 zKOvp3ZdhkLdR#1f2{v$gX7B}Kvwj~^OP@R7K9w@6Avd2`d2)J87pa>c*v04eB_!9g zca(UfI&Fq4e)%0 zQjHz*j#;?(&&~<<%i8@Wbj|Cr{Z14(`mK!?KLVVz7xxCyb&v=^Nw4NG>h)Qv?2(#7 z!F-2Zyp8$;P8G8ZziwUYSJ!{PIdTiX^N3e{_hd)IjxYIjdS5Fn@@Lt?m05oI$@uJp zWLD+--MXs`H~Jk~g&A(xZM$R4nrbKREbf&qMPjd`JXc9N!J)6~gJd6}33bqAo8e+O zr!EPXnVD_+ou}|Mv50;vm`I!U1CL^<8?QRhLaW-C;Hx`+3Zszsh$u4>KhN^5$qqeK z=-KCr*TW@>E^Mz2uH|qz?_?{0k{W^$sZJ4oOt`9+n=Z?Uh)fVJ?}OPbGe0@>P_0m- zm0N-L6P*#qX}qBp>%Nr2=e5;OkIYKLWIH5YkGHzq5^F5^M9TAb&-e zcE+gGpq<51#U@JhtA^{W;ze~se72-~wfYVpwSDUJy`y=oaWTYWM&5Ve%O*7Z*&r%& z2vth=g0H2ouiX0n3!ofm5+UmHOn}bx&ys(K zP~&f4++J3W_&r+w-6H3oy>Q|3_1D2CSrM`K-*di3)<%FuDawhdEcusFn5bGFtw+*x zJ2TVJv%$0KbiWfH2Pj?S_aCj#t?Vk3rLMr9-eUPAVyg}UNlm^dP4a;#hAyYbnZj=I z7R&`Y9LVHuW7*ZNZ7T*cSJWK1Yva0(D4c^q0=;<_Zhn{!R#x~BWJc!43?!&c!VCEv z<5Hwlv?VUx`cvAyt7cdBp%EEXYHjzE*antBsctv37Z|6N!o6G+VnqOPtA#2Xt1?+@ z@6C4j0+pG6y=wc+lju(N+5lLPtRFi{9iZx`-?t!v{^E7m?NeS|(qU~cU+XQn+u=YO zM#`)rq$kG87vxNm?=6*VrF}bReyy?MP)bJLh?lo*Fn`R%y|SmXVaxnMKTR>ya7N!F z3Gw9GiTwUA^^NOQyHV>AZ1#lluB4l{%Y^5NP_2>Mr+JB-!!^$(S(>3W37sM}D_ohR zckKJ*xg%x+#p!-oVq1NnvhaK$CXp6=^~8&`z!OYuJMGxRAhPDGPcur^ZJ7{YN>W)q zd*)!BbQX?c>%Jg~_<&sniCjJRo5VP+KAC`8o0{QI|CMY;Yy&>J4g{M1sYox*g7wl* z{VUh(bnG$@1HqFwG7q4@9Sd)O1?Va0A!2S2_s}ebGNMS!@(qcGjP)c^7qZlpND3vi zdA*NuReb~tAhwb*A%@i8H*X` zYgC#a9Ba|`RpYIm=qWoagFhcR(Y)@b1SA_NV6S21inl!R%;<%*%)6+pvGUx^{wdw4 z+sVtJxjfEBV7_#|$NF)}Yi6W-;4@2rdtJPGI@99qHEI29CP+d*{2GZpyY%Bp*-jivfSb#+siB)8G$JX@i=_i3wQd#sfqZgMZ)RW`UQ z>7{lbYAnuev|?Mkw=a!!s;SeLc2uY%LlR40jKBJt_TrU~SZ4ptA=?kG&w8f8;16In zEYbJ}Fafj|b{l#ND~v*hd}XJyE#CF0o5{>}?Pod=T1{cNnkJ%*P3(~(u=Vno?O+B} zkLs6@QGRkI7#3}`d~3EHS6B41!(;vdNPU;pJ@2+B$;UvT_*UQakSaHZAr@w97J#f{ z^Fr_Hs8Zf&?^H{OPzVq)c~Ew00p?!`Sa`OmWR^>d$%GG+*+&SvIv^61EHFBx5^hC={2J*4oO?V_K_ zSV+w=lbiS{t_qhaMQmeS2d?+H8EDp z6#=QvUamXm?P;ckB|FZBPtRY6AM`8H$`s3RQ8xk#e+gs37pLydQuZ%5(|YxP z-`Ml%N`d9%oE($IkQ#qL{N8L3Dvhr;7XHar8jd10U+QP|&znq4%+_-}Mg0tyuY_lT z22`ng$E%2_NsnKc3S)Et3Krqy;D8^-RojIkd>uf<)070JgsMvpAig8BnknqOGRR`2PRUL)s)XZ9u0kHL4R92{IeGi2B56Eg5j-*lP zG>ev2=^UgrYx&STDJxY_R#V5E+#iS>_!z%z93%46@<>73)tAqFRSQ|F_tNh?Y4*!p z&_->oalcdQ)vVqA?&MFoue|Cvqheg>^9OZ4cWI`GYCrRBmS9-x zLQMEdamCHUP+=!F?&|uudkfQK^}p#Kyi&FTT<$=oUOxjUv_WZofkc?fV}{GTHdV&I zCiR%!g5ALQ^!ITkh&4>%UjO{r?{T#EGrR4bq_KI+?in#I2P< zT7Kf&Q>FWGHgAjgRJ+6DMu7Ja85cL`op*@!>yOUI>xBc_{byRP8Tu?|wvv}Dnh~}- zJjzS_Etg--5r=ILpAqo&8zTl14&&k?_6&a%F&2!I)cur6rYjy7t{>?*lE_ehIY zc{>p`W6p)?tt;7vKHXSn2ABSClsZ6RLVZ0}=#I>p-dGKCW}sunI`(EkRXs2*a-x@H z*+KM=%j|YN+Sy^nPS{mi7C z@AHO8eK+d!=T?E;()ZYNo!(2V4DZvSa+eSH63YBIamlIOX)VzE6K}^)<;*&-Noot< z%jGlbV(M0lB;ZjYI$FGEjAo1&Z*S<&!Dv_c)^hKyocXqWn7}(QY4_x(4#oOCb5JgE z&^XZc8|0s8c4u1YZo+IM#`Rx z8=Fe4%T4z5cWR8+mwcJ`fg+P`Z-@wiFpuaI5f zLGUlrVBpm13!GYkU~fsJ;7nm|f4Lt#tJh2Uyvil*j%gp4(Yr=k~Q{HDpT>v!dR zyJ-hoEB|Q^5cX|Gz8jR0tF@te4(tw+FW5PbDVGC-6A&p#^ChPXdY}|*_ylqjO@&uR zo~^;e)o%Y3*`#R(LLe}qk4ZE~%Tu94io9YgZLewBMJ4fU!AHYluakwk^_;U#WMlq- zq_4P^m4`pPjUeHE+embFs4bA!cNIWOh-sLS+io+K;ag>2 z-O!C~>8o=yd7GbJ`S20k_VMMSk%l4*!G#yU`2GR}}hO7OQh$sNTk(up5|>mfXD zeNw}Y1!+fN3NM?QJ?<2-5J=&ETLd;(qfgJXG%LeDC%T+RTy<t6YCJ< z(cNM|IM)i;w|-BQGIqJop}4eKvHWyBFNvZs81X56bdNM|;5cDK@jKpc)F}Q4EY?)C zBcuNlTtxP0>ZCnR#}Pxd?F4lSLNotsXql zxU>m(dIog9=r_0~%_e<=qfzO7+g#jtYHUNHaj@Inm9M3JYw=NVii;xb0&R&0J-sWjRO>;bTqrusoqKhZuim__nho#Q5UaWsR z7X8h56W)q>NmSQv8PQDJh>oY?y@M;U7Whd++rFLYvVXXcYZL^sq7F>=UjU+rrk{>7 zcB>EWZ*qaaW_F+ihadDZYCZ2y&kHoNE#46*$fl=n&SVH(MKbi;bWpAm-FR=qP1Lk> z&LK4j5_v32Z<2NLofTZBx*nn+w3NO?31em;5{bD_QsIZc-IX*H??~V*$&GKwBBh&o zQad2DAgV%wrsK*{4%N^g?Io#L*ZeU5Y0Z)Z)AkZZeKGc0u7v!(+uV5^n!-7{g*VKELL1>AVdRyw(Ir|KZm+A#u>~yhdfvc>Ign%I?o~!_0Oj>RHo$x-SBzA z?f66K2|_X89+9sE2CCtw0d~5_ipp(==dK&p(rD;v6d1Y zp)7E#F$?r!**GKw@wN?KcDNuBzV8Az|b zPBxY`0Yskes1&{7e61vkI2-lKfT7o~)c_|<{$Tej9xs9n59-{`Pk^2oKca^TYuDBX zvAF>HF*cez;z=;x{VA%o5z_&8U~c#Dmip_dpRy7f*50g1@S-Z_4l(zr_O_5U@I74V zRzgO-GDLjlx!dg`PcE0?mk)PD`B8sBooytOegrEAKHv^tq2GkPD#p@ z6)OT)V#HQWAC(={I;BDA(7eK>nk*Dnt$j-TXLgtVGv$|O_n&S&)*5Fw^>Ky<*Rn@O z%!InCl#`z2CmlM?UE55QCLESO8AvY)s$!7&CSFcbDOHgQ5og{phgzD8q+Cc6veg8# z*^pUtAIJMbA0k}I8tl!F5gg#sWNKGX>U@q9`L zk>u-mt+6|Z!~@cXtLP%^9Eas5ukFpn?N^(;bo3|sRj0N1EB;HNt}C@8Uzs+eg?ZtH z`7T;KT3@u9O*}mvysN?8x&DbO1tKmvdwQB>2|8F8`99}$emNRl3rl$t6SMTK!`Yke zu6a!#c_qc;)e0WB{e@3i{MRrJtA~`=MKUX z?@b2bp9pK>q@&^#Md^7dRY3Q_nDhMCdbT;!PBnF|8pPMdS6+TEsgrSr7~?+>5Hh)X zhQ6m{7{}|*_ZX^9rfM3qli__{e5Eer(q~H z@HDL!CJ7xj+`Yh2V^i~jE_(W5_O%V|8wbX5x{9*r?=7;+vDG(a_3qvZ+WB&%de-18 zT>5$Awyn1Qd6H9=2C#!Oc@Lk8C68sBg&hCXZL(_NB&BA^iP70T)w#66sNl&f-Z

2KUY7yz-7_`p(lc`HgEPC5(QDJ#Lr#t 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 Y>c{6t4Sw{%j~@8Z1FJo-=6lco0p?d?5&!@I literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/favicon.ico b/3rd/libuv-1.19.2/docs/src/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2c40694cd282ff3d0db2c495c23f3beca40c17fa GIT binary patch literal 15086 zcmeI3J!oE47{^bE(6L>dlR?3;f?AMDoTP|gC(+GON^N!X18j$O66~NjsaQd=(xSMC zL)z#dI2x#nOSZwR!m3x7+NM_xVsKV)SFb<|EpaeeASlj(+q}%U2&yoPD*;Lm&Ey_UhK~ z_4og5Xr+DRP_sk!#l?%;Y8ZWV*^pfGuZHnl8XJu9Yiq#y(Ek|pp24Oo_K^744vEX% z&VG-&+OikQSk~Z?A1-gL|EIsK{O26#L%+nJ84qMmd3jchtG#hWC&Nw%vpc1cK(nJjju2B;@Lx= zdb$)`edHiu4|NQ8|RdXF;=Y~_aQds zM-KRv4+sy(@ZfC92gKI6;H2E;6K(qX-UX~%j0>mIj{8FYL$I_j$2@PzKi(Uqj$`zO z#4L5N(?>*Nx>uvT*8k+fg{fl8rQ8qrD`mB~$cC=BvHB2S^BB zo_6@a7e4Xb##oy-YQyg-4(0Y@Zd<>ncpwkI?I z#(nm2&Rk}dLs#8nOwJ%bGaw_^Z@yn{`_@$KJMZd%`rc^{L%16&qPZZ8yy&yXqHe8E zp4v^DL$+J0`R4$#?Y4)|~%PII2w6MbC!=E%c&^QfI|YuvXc=!{*1Y4?qsL2`h* z$o-C7&RrON*x$_I{LppiJ7@Zwgz&bZi%;^2d%G)#^1eckdtnIwS=8R#;7=cfx8p9} zQLZlb%I^mM$iuvbtO1gd?cjn{}^(OGIzMtu55|%vU*fmf#WDj|cBmZ3E&ULE z^DEBxoq?V3_c`Snao@w)J2O5Htv$MtTiLJ8Ps<-ZzF*?kddj;CIdjfw6M5D+I$xWc zhQGY!fnWQebuQ(MwWVLXOObWGTVP`@;#mIJ;fE&YSX18%)QRXmF?Jtf*EjFnSpH>g zJddJ&XMw)QMPI~mOn)r@Xj{7voZk&B*MxEA-}y5>b8-Dk``zH!=QGwGJ^1uJznGg9 z|1$TION}?{8}*_O`a|A9*KPP*J_HMHIpwG&wQL$C-RQE%*QsQ_U2XFL*_t?GB)|p zoTFdrz*D)r%G#KV^AR(r&U;7R5&a!b^kMysGZx8@XQ0nP@+p19c=pHC-WnK_JFI=lYsh%FxQ85$b^U(; zyvsXi2xoM5o45Q$;<>lsOiqr6az+ok?5p#43dY+lgu~eV!XCTR_3p~Qe5cL4mf+UW zmb(1x$@eO7H!864g(1E`#3$lv{^Anj&Bm9F=&$E59)YX*%ShmI{=yP?CV$TeB#Hb_ z`=8LKQ_5!f8%mqFnE#H7@%+D--L>Nu^WRyOxXOI~8?33Y;%}S(z@z1r`L%pA%3o~Y ik^kAsb9poGOsuT~U&vzKIyJc*jGI?B>sZ!zWBd=1T7Db= literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/logo.png b/3rd/libuv-1.19.2/docs/src/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf1eee577b6774c345d5e21be51130a23b16627 GIT binary patch literal 33545 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 W3*P8um*8Y!7&$3rXpMwP!2bZAf*ghb literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png b/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png new file mode 100644 index 0000000000000000000000000000000000000000..e769cf338b4456ea688b0abf888b646a4253e0eb GIT binary patch literal 80528 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 literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/img/logos.svg b/3rd/libuv-1.19.2/img/logos.svg new file mode 100644 index 00000000..d6185f8b --- /dev/null +++ b/3rd/libuv-1.19.2/img/logos.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3rd/libuv-1.19.2/include/android-ifaddrs.h b/3rd/libuv-1.19.2/include/android-ifaddrs.h new file mode 100644 index 00000000..9cd19fec --- /dev/null +++ b/3rd/libuv-1.19.2/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 . Note that if 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 + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/3rd/libuv-1.19.2/include/pthread-barrier.h b/3rd/libuv-1.19.2/include/pthread-barrier.h new file mode 100644 index 00000000..07db9b8a --- /dev/null +++ b/3rd/libuv-1.19.2/include/pthread-barrier.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#if !defined(__MVS__) +#include /* sem_t */ +#endif + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 +#define UV__PTHREAD_BARRIER_FALLBACK 1 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#else +# define UV_BARRIER_STRUCT_PADDING 0 +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} 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 /* _UV_PTHREAD_BARRIER_ */ diff --git a/3rd/libuv-1.19.2/include/stdint-msvc2008.h b/3rd/libuv-1.19.2/include/stdint-msvc2008.h new file mode 100644 index 00000000..d02608a5 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap 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 +#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 +#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/3rd/libuv-1.19.2/include/tree.h b/3rd/libuv-1.19.2/include/tree.h new file mode 100644 index 00000000..f936416e --- /dev/null +++ b/3rd/libuv-1.19.2/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * 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/3rd/libuv-1.19.2/include/uv-aix.h b/3rd/libuv-1.19.2/include/uv-aix.h new file mode 100644 index 00000000..7dc992fa --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-bsd.h b/3rd/libuv-1.19.2/include/uv-bsd.h new file mode 100644 index 00000000..2d72b3d7 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-darwin.h b/3rd/libuv-1.19.2/include/uv-darwin.h new file mode 100644 index 00000000..d2264158 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +# include +# include +# include +# 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/3rd/libuv-1.19.2/include/uv-errno.h b/3rd/libuv-1.19.2/include/uv-errno.h new file mode 100644 index 00000000..aa4d4509 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-errno.h @@ -0,0 +1,437 @@ +/* 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 +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + +#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 UV__ERR(E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES UV__ERR(EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE UV__ERR(EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN UV__ERR(EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY UV__ERR(EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF UV__ERR(EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY UV__ERR(EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED UV__ERR(ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET UV__ERR(ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED UV__ERR(ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET UV__ERR(ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST UV__ERR(EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT UV__ERR(EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR UV__ERR(EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL UV__ERR(EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO UV__ERR(EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN UV__ERR(EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR UV__ERR(EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP UV__ERR(ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE UV__ERR(EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE UV__ERR(EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN UV__ERR(ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH UV__ERR(ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE UV__ERR(ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS UV__ERR(ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV UV__ERR(ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT UV__ERR(ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM UV__ERR(ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET UV__ERR(ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC UV__ERR(ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS UV__ERR(ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN UV__ERR(ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR UV__ERR(ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK UV__ERR(ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP UV__ERR(ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM UV__ERR(EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE UV__ERR(EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO UV__ERR(EPROTO) +#else +# define UV__EPROTO UV__ERR(4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS UV__ERR(EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE UV__ERR(ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH UV__ERR(ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY UV__ERR(ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV UV__ERR(EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG UV__ERR(EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE UV__ERR(ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO UV__ERR(ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + +#if defined(EMLINK) && !defined(_WIN32) +# define UV__EMLINK UV__ERR(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 UV__ERR(EHOSTDOWN) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) +# define UV__EHOSTDOWN (-64) +#else +# define UV__EHOSTDOWN (-4031) +#endif + +#if defined(EREMOTEIO) && !defined(_WIN32) +# define UV__EREMOTEIO UV__ERR(EREMOTEIO) +#else +# define UV__EREMOTEIO (-4030) +#endif + +#if defined(ENOTTY) && !defined(_WIN32) +# define UV__ENOTTY UV__ERR(ENOTTY) +#else +# define UV__ENOTTY (-4029) +#endif + + +#endif /* UV_ERRNO_H_ */ diff --git a/3rd/libuv-1.19.2/include/uv-linux.h b/3rd/libuv-1.19.2/include/uv-linux.h new file mode 100644 index 00000000..9b38405a --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-os390.h b/3rd/libuv-1.19.2/include/uv-os390.h new file mode 100644 index 00000000..39e7384d --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-os390.h @@ -0,0 +1,33 @@ +/* Copyright 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. + */ + +#ifndef UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#define UV_PLATFORM_LOOP_FIELDS \ + void* ep; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + char rfis_rftok[8]; \ + +#endif /* UV_MVS_H */ diff --git a/3rd/libuv-1.19.2/include/uv-posix.h b/3rd/libuv-1.19.2/include/uv-posix.h new file mode 100644 index 00000000..9a96634d --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-posix.h @@ -0,0 +1,31 @@ +/* Copyright 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. + */ + +#ifndef UV_POSIX_H +#define UV_POSIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + struct pollfd* poll_fds; \ + size_t poll_fds_used; \ + size_t poll_fds_size; \ + unsigned char poll_fds_iterating; \ + +#endif /* UV_POSIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-sunos.h b/3rd/libuv-1.19.2/include/uv-sunos.h new file mode 100644 index 00000000..04216642 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/include/uv-threadpool.h b/3rd/libuv-1.19.2/include/uv-threadpool.h new file mode 100644 index 00000000..9708ebdd --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-unix.h b/3rd/libuv-1.19.2/include/uv-unix.h new file mode 100644 index 00000000..da32f86e --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-unix.h @@ -0,0 +1,464 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(__MVS__) +#include +#endif +#include +#include + +#include "uv-threadpool.h" + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined (__MVS__) +# include "uv-os390.h" +#elif defined(_PASE) +# include "uv-posix.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(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#elif defined(__CYGWIN__) || defined(__MSYS__) +# include "uv-posix.h" +#endif + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.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_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 +}; + +#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; +typedef pid_t uv_pid_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; +typedef pthread_barrier_t uv_barrier_t; + + +/* 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]; \ + void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ + uv__io_t async_io_watcher; \ + int async_wfd; \ + 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 \ + +/* fs open() flags supported on this platform: */ +#if defined(O_APPEND) +# define UV_FS_O_APPEND O_APPEND +#else +# define UV_FS_O_APPEND 0 +#endif +#if defined(O_CREAT) +# define UV_FS_O_CREAT O_CREAT +#else +# define UV_FS_O_CREAT 0 +#endif +#if defined(O_DIRECT) +# define UV_FS_O_DIRECT O_DIRECT +#else +# define UV_FS_O_DIRECT 0 +#endif +#if defined(O_DIRECTORY) +# define UV_FS_O_DIRECTORY O_DIRECTORY +#else +# define UV_FS_O_DIRECTORY 0 +#endif +#if defined(O_DSYNC) +# define UV_FS_O_DSYNC O_DSYNC +#else +# define UV_FS_O_DSYNC 0 +#endif +#if defined(O_EXCL) +# define UV_FS_O_EXCL O_EXCL +#else +# define UV_FS_O_EXCL 0 +#endif +#if defined(O_EXLOCK) +# define UV_FS_O_EXLOCK O_EXLOCK +#else +# define UV_FS_O_EXLOCK 0 +#endif +#if defined(O_NOATIME) +# define UV_FS_O_NOATIME O_NOATIME +#else +# define UV_FS_O_NOATIME 0 +#endif +#if defined(O_NOCTTY) +# define UV_FS_O_NOCTTY O_NOCTTY +#else +# define UV_FS_O_NOCTTY 0 +#endif +#if defined(O_NOFOLLOW) +# define UV_FS_O_NOFOLLOW O_NOFOLLOW +#else +# define UV_FS_O_NOFOLLOW 0 +#endif +#if defined(O_NONBLOCK) +# define UV_FS_O_NONBLOCK O_NONBLOCK +#else +# define UV_FS_O_NONBLOCK 0 +#endif +#if defined(O_RDONLY) +# define UV_FS_O_RDONLY O_RDONLY +#else +# define UV_FS_O_RDONLY 0 +#endif +#if defined(O_RDWR) +# define UV_FS_O_RDWR O_RDWR +#else +# define UV_FS_O_RDWR 0 +#endif +#if defined(O_SYMLINK) +# define UV_FS_O_SYMLINK O_SYMLINK +#else +# define UV_FS_O_SYMLINK 0 +#endif +#if defined(O_SYNC) +# define UV_FS_O_SYNC O_SYNC +#else +# define UV_FS_O_SYNC 0 +#endif +#if defined(O_TRUNC) +# define UV_FS_O_TRUNC O_TRUNC +#else +# define UV_FS_O_TRUNC 0 +#endif +#if defined(O_WRONLY) +# define UV_FS_O_WRONLY O_WRONLY +#else +# define UV_FS_O_WRONLY 0 +#endif + +/* fs open() flags supported on other platforms: */ +#define UV_FS_O_RANDOM 0 +#define UV_FS_O_SHORT_LIVED 0 +#define UV_FS_O_SEQUENTIAL 0 +#define UV_FS_O_TEMPORARY 0 + +#endif /* UV_UNIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-version.h b/3rd/libuv-1.19.2/include/uv-version.h new file mode 100644 index 00000000..c2753d51 --- /dev/null +++ b/3rd/libuv-1.19.2/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 19 +#define UV_VERSION_PATCH 2 +#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/3rd/libuv-1.19.2/include/uv-win.h b/3rd/libuv-1.19.2/include/uv-win.h new file mode 100644 index 00000000..4c6c50a2 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-win.h @@ -0,0 +1,676 @@ +/* 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 0x0600 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include + +#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 +#include +#include + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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 int uv_pid_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 */ \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + 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; + +#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 + +/* fs open() flags supported on this platform: */ +#define UV_FS_O_APPEND _O_APPEND +#define UV_FS_O_CREAT _O_CREAT +#define UV_FS_O_EXCL _O_EXCL +#define UV_FS_O_RANDOM _O_RANDOM +#define UV_FS_O_RDONLY _O_RDONLY +#define UV_FS_O_RDWR _O_RDWR +#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL +#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED +#define UV_FS_O_TEMPORARY _O_TEMPORARY +#define UV_FS_O_TRUNC _O_TRUNC +#define UV_FS_O_WRONLY _O_WRONLY + +/* fs open() flags supported on other platforms (or mapped on this platform): */ +#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECTORY 0 +#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ +#define UV_FS_O_NOATIME 0 +#define UV_FS_O_NOCTTY 0 +#define UV_FS_O_NOFOLLOW 0 +#define UV_FS_O_NONBLOCK 0 +#define UV_FS_O_SYMLINK 0 +#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/3rd/libuv-1.19.2/include/uv.h b/3rd/libuv-1.19.2/include/uv.h new file mode 100644 index 00000000..9794d996 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv.h @@ -0,0 +1,1567 @@ +/* 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 +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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") \ + XX(EREMOTEIO, "remote I/O error") \ + XX(ENOTTY, "inappropriate ioctl for device") \ + +#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 struct uv_passwd_s uv_passwd_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_loop_fork(uv_loop_t* loop); + +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 int uv_translate_sys_error(int sys_errno); + +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 uv_handle_type uv_handle_get_type(const uv_handle_t* handle); +UV_EXTERN const char* uv_handle_type_name(uv_handle_type type); +UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle); +UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle); +UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data); + +UV_EXTERN size_t uv_req_size(uv_req_type type); +UV_EXTERN void* uv_req_get_data(const uv_req_t* req); +UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data); +UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req); +UV_EXTERN const char* uv_req_type_name(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 size_t uv_stream_get_write_queue_size(const uv_stream_t* stream); + +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_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); +UV_EXTERN size_t uv_udp_get_send_queue_count(const 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(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); +UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); + + +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_DISCONNECT = 4, + UV_PRIORITIZED = 8 +}; + +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_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*); + + +/* + * 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; +}; + +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + +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); +UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); + +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_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); +UV_EXTERN uv_pid_t uv_os_getpid(void); +UV_EXTERN uv_pid_t uv_os_getppid(void); + +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); + +UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); +UV_EXTERN int uv_os_setenv(const char* name, const char* value); +UV_EXTERN int uv_os_unsetenv(const char* name); + +UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); + + +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_COPYFILE +} 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 uv_fs_type uv_fs_get_type(const uv_fs_t*); +UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); +UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); +UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); +UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); + +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); +/* + * This flag can be used with uv_fs_copyfile() to return an error if the + * destination already exists. + */ +#define UV_FS_COPYFILE_EXCL 0x0001 + +UV_EXTERN int uv_fs_copyfile(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_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_start_oneshot(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); + +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE (IFNAMSIZ + 1) +#else +# define UV_IF_NAMESIZE (16 + 1) +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, + char* buffer, + size_t* size); +UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, + char* buffer, + size_t* size); + +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 int uv_mutex_init_recursive(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 +}; + +UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); +UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); + +/* 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 +#undef UV__ERR + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/3rd/libuv-1.19.2/libuv.pc.in b/3rd/libuv-1.19.2/libuv.pc.in new file mode 100644 index 00000000..55c4b65d --- /dev/null +++ b/3rd/libuv-1.19.2/libuv.pc.in @@ -0,0 +1,12 @@ +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. +URL: http://libuv.org/ + +Libs: -L${libdir} -luv @LIBS@ +Cflags: -I${includedir} diff --git a/3rd/libuv-1.19.2/m4/.gitignore b/3rd/libuv-1.19.2/m4/.gitignore new file mode 100644 index 00000000..c44e4c29 --- /dev/null +++ b/3rd/libuv-1.19.2/m4/.gitignore @@ -0,0 +1,4 @@ +# Ignore libtoolize-generated files. +*.m4 +!as_case.m4 +!libuv-check-flags.m4 diff --git a/3rd/libuv-1.19.2/m4/as_case.m4 b/3rd/libuv-1.19.2/m4/as_case.m4 new file mode 100644 index 00000000..c7ae0f0f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 b/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 new file mode 100644 index 00000000..59c30635 --- /dev/null +++ b/3rd/libuv-1.19.2/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à +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/3rd/libuv-1.19.2/samples/.gitignore b/3rd/libuv-1.19.2/samples/.gitignore new file mode 100644 index 00000000..f868091b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore b/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore new file mode 100644 index 00000000..c177f374 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE b/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE new file mode 100644 index 00000000..63c1447f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp b/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp new file mode 100644 index 00000000..771a1e14 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/client.c b/3rd/libuv-1.19.2/samples/socks5-proxy/client.c new file mode 100644 index 00000000..aa2a91c9 --- /dev/null +++ b/3rd/libuv-1.19.2/samples/socks5-proxy/client.c @@ -0,0 +1,736 @@ +/* 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 +#include +#include + +/* 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); +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) { + conn *c; + + 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/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h b/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h new file mode 100644 index 00000000..99ee8160 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* sockaddr_in, sockaddr_in6 */ +#include /* size_t, ssize_t */ +#include +#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c b/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c new file mode 100644 index 00000000..8481b226 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +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/3rd/libuv-1.19.2/samples/socks5-proxy/main.c b/3rd/libuv-1.19.2/samples/socks5-proxy/main.c new file mode 100644 index 00000000..04020cbd --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#if HAVE_UNISTD_H +#include /* 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

[-h] [-p ]\n" + "\n" + "Options:\n" + "\n" + " -b Bind to this address or hostname.\n" + " Default: \"127.0.0.1\"\n" + " -h Show this help message.\n" + " -p Bind to this port number. Default: 1080\n" + "", + progname); + exit(1); +} diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c new file mode 100644 index 00000000..4f08e345 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include /* abort() */ +#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h new file mode 100644 index 00000000..715f3222 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/samples/socks5-proxy/server.c b/3rd/libuv-1.19.2/samples/socks5-proxy/server.c new file mode 100644 index 00000000..3f1ba42c --- /dev/null +++ b/3rd/libuv-1.19.2/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 /* INET6_ADDRSTRLEN */ +#include +#include + +#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/3rd/libuv-1.19.2/samples/socks5-proxy/util.c b/3rd/libuv-1.19.2/samples/socks5-proxy/util.c new file mode 100644 index 00000000..af34f055 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/src/fs-poll.c b/3rd/libuv-1.19.2/src/fs-poll.c new file mode 100644 index 00000000..ee73d5a2 --- /dev/null +++ b/3rd/libuv-1.19.2/src/fs-poll.c @@ -0,0 +1,256 @@ +/* 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 +#include +#include + +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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ctx->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + 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/3rd/libuv-1.19.2/src/heap-inl.h b/3rd/libuv-1.19.2/src/heap-inl.h new file mode 100644 index 00000000..1e2ed60e --- /dev/null +++ b/3rd/libuv-1.19.2/src/heap-inl.h @@ -0,0 +1,245 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 /* 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/3rd/libuv-1.19.2/src/inet.c b/3rd/libuv-1.19.2/src/inet.c new file mode 100644 index 00000000..da63a688 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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/3rd/libuv-1.19.2/src/queue.h b/3rd/libuv-1.19.2/src/queue.h new file mode 100644 index 00000000..ff3540a0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/queue.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 + +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/3rd/libuv-1.19.2/src/threadpool.c b/3rd/libuv-1.19.2/src/threadpool.c new file mode 100644 index 00000000..413d1c20 --- /dev/null +++ b/3rd/libuv-1.19.2/src/threadpool.c @@ -0,0 +1,318 @@ +/* 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" +#endif + +#include + +#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 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; + + uv_sem_post((uv_sem_t*) arg); + arg = NULL; + + 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 (nthreads == 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; +} +#endif + + +static void init_threads(void) { + unsigned int i; + const char* val; + uv_sem_t sem; + + 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); + + if (uv_sem_init(&sem, 0)) + abort(); + + for (i = 0; i < nthreads; i++) + if (uv_thread_create(threads + i, worker, &sem)) + abort(); + + for (i = 0; i < nthreads; i++) + uv_sem_wait(&sem); + + uv_sem_destroy(&sem); +} + + +#ifndef _WIN32 +static void reset_once(void) { + uv_once_t child_once = UV_ONCE_INIT; + memcpy(&once, &child_once, sizeof(child_once)); +} +#endif + + +static void init_once(void) { +#ifndef _WIN32 + /* Re-initialize the threadpool after fork. + * Note that this discards the global mutex and condition as well + * as the work queue. + */ + if (pthread_atfork(NULL, NULL, &reset_once)) + abort(); +#endif + init_threads(); +} + + +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/3rd/libuv-1.19.2/src/unix/aix-common.c b/3rd/libuv-1.19.2/src/unix/aix-common.c new file mode 100644 index 00000000..e17e4494 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/aix-common.c @@ -0,0 +1,292 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +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 UV_EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return UV_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 UV__ERR(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 UV_EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return UV_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 UV_EINVAL; + } +} + +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, inet6, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return UV__ERR(errno); + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(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) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return UV_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; + + inet6 = (p->ifr_addr.sa_family == AF_INET6); + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return UV_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 (inet6) + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return UV_ENOSYS; + } + + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); + + 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); +} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/aix.c b/3rd/libuv-1.19.2/src/unix/aix.c new file mode 100644 index 00000000..92de8148 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/aix.c @@ -0,0 +1,1041 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +#include +#endif + +#include +#include +#include +#include +#include + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static void* args_mem = NULL; +static char** process_argv = NULL; +static int process_argc = 0; +static char* process_title_ptr = NULL; + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +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; + } +} + + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + + return uv__platform_loop_init(loop); +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return UV__ERR(errno); + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + +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 have_signals; + 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; + } + + have_signals = 0; + 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; + } + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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_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 UV__ERR(errno); + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return UV__ERR(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 UV__ERR(errno); + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return UV__ERR(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 && errno != EEXIST) + 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 UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* 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"); + + /* In file / directory move cases, AIX Event infrastructure + * produces a second event with no data. + * Ignore it and return gracefully. + */ + if(bytes == 0) + return; + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* Unrecoverable error */ + if (rc == -1) + return; + + /* 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; + } else { + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else + p++; + } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; + + handle->cb(handle, 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 UV_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, str_offset = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char readlink_cwd[PATH_MAX]; + + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + } else { + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); + } + + 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(filename); + handle->cb = cb; + handle->dir_filename = NULL; + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +#else + return UV_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 UV_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) { + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Save the original pointer to argv. + * AIX uses argv to read the process name. + * (Not the memory pointed to by argv[0..n] as on Linux.) + */ + process_argv = argv; + process_argc = argc; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + /* 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) { + char* new_title; + + /* We cannot free this pointer when libuv shuts down, + * the process may still be using it. + */ + new_title = uv__strdup(title); + if (new_title == NULL) + return UV_ENOMEM; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + /* If this is the first time this is set, + * don't free and set argv[1] to NULL. + */ + if (process_title_ptr != NULL) + uv__free(process_title_ptr); + + process_title_ptr = new_title; + + process_argv[0] = process_title_ptr; + if (process_argc > 1) + process_argv[1] = NULL; + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + len = strlen(process_argv[0]); + if (buffer == NULL || size == 0) + return UV_EINVAL; + else if (size <= len) + return UV_ENOBUFS; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + memcpy(buffer, process_argv[0], len + 1); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} + + +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 UV__ERR(errno); + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = UV_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; + + boot_time = 0; + 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 UV_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 UV_ENOSYS; + } + + ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); + if (result == -1) { + return UV_ENOSYS; + } + + ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); + if (!ps_cpus) { + return UV_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 UV_ENOSYS; + } + + *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + uv__free(ps_cpus); + return UV_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__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/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c new file mode 100644 index 00000000..bf30b141 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c @@ -0,0 +1,710 @@ +/* +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 +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(pid_t *p_pid) +{ + struct sockaddr_nl l_addr; + socklen_t l_len; + + 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; + } + + l_len = sizeof(l_addr); + if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) + { + close(l_socket); + return -1; + } + *p_pid = l_addr.nl_pid; + + 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, pid_t p_pid, 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) + { + 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 != p_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, pid_t p_pid) +{ + 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, p_pid, &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 = IFA_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_rtaDataSize + 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 = IFA_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); + unsigned 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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +{ + + int l_numLinks = 0; + 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 != p_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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +{ + 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 != p_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; + pid_t l_pid; + NetlinkList *l_linkResults; + NetlinkList *l_addrResults; + + if(!ifap) + { + return -1; + } + *ifap = NULL; + + l_socket = netlink_socket(&l_pid); + if(l_socket < 0) + { + return -1; + } + + l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + l_result = 0; + l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, 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/3rd/libuv-1.19.2/src/unix/async.c b/3rd/libuv-1.19.2/src/unix/async.c new file mode 100644 index 00000000..0b450ae0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/async.c @@ -0,0 +1,269 @@ +/* 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 +#include /* snprintf() */ +#include +#include +#include +#include + +static void uv__async_send(uv_loop_t* loop); +static int uv__async_start(uv_loop_t* loop); +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); + 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); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + char buf[1024]; + ssize_t r; + QUEUE queue; + QUEUE* q; + uv_async_t* h; + + assert(w == &loop->async_io_watcher); + + for (;;) { + r = read(w->fd, buf, sizeof(buf)); + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + 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_send(uv_loop_t* loop) { + const void* buf; + ssize_t len; + int fd; + int r; + + buf = ""; + len = 1; + fd = loop->async_wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = loop->async_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(); +} + + +static int uv__async_start(uv_loop_t* loop) { + int pipefd[2]; + int err; + + if (loop->async_io_watcher.fd != -1) + return 0; + + err = uv__async_eventfd(); + if (err >= 0) { + pipefd[0] = err; + pipefd[1] = -1; + } + else if (err == UV_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(&loop->async_io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &loop->async_io_watcher, POLLIN); + loop->async_wfd = pipefd[1]; + + return 0; +} + + +int uv__async_fork(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) /* never started */ + return 0; + + uv__async_stop(loop); + + return uv__async_start(loop); +} + + +void uv__async_stop(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) + return; + + if (loop->async_wfd != -1) { + if (loop->async_wfd != loop->async_io_watcher.fd) + uv__close(loop->async_wfd); + loop->async_wfd = -1; + } + + uv__io_stop(loop, &loop->async_io_watcher, POLLIN); + uv__close(loop->async_io_watcher.fd); + loop->async_io_watcher.fd = -1; +} + + +static int uv__async_eventfd(void) { +#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 UV__ERR(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 UV__ERR(errno); + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return UV_ENOSYS; +} diff --git a/3rd/libuv-1.19.2/src/unix/atomic-ops.h b/3rd/libuv-1.19.2/src/unix/atomic-ops.h new file mode 100644 index 00000000..7cac1f98 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/atomic-ops.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 +#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; +#elif defined(__MVS__) + unsigned int op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) + return oldval; + else + return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_uint(ptr, oldval, newval); +#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; +#elif defined (__MVS__) +#ifdef _LP64 + unsigned long long op4; + if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, + (unsigned long long*) ptr, *ptr, &op4)) +#else + unsigned long op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) +#endif + return oldval; + else + return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_ulong(ptr, oldval, newval); +#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/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c new file mode 100644 index 00000000..0d021544 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c @@ -0,0 +1,152 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +#include +#include +#if !defined(__CYGWIN__) && !defined(__MSYS__) +#include +#endif + +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; +#if !defined(__CYGWIN__) && !defined(__MSYS__) + /* + * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` + * equals to `AF_LINK` or not. Otherwise, the result depends on the operation + * system with `AF_LINK` or `PF_INET`. + */ + if (exclude_type == UV__EXCLUDE_IFPHYS) + return (ent->ifa_addr->sa_family != AF_LINK); +#endif +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + /* + * On BSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + return 1; +#elif defined(__NetBSD__) + if (ent->ifa_addr->sa_family != PF_INET && + ent->ifa_addr->sa_family != PF_INET6) + return 1; +#elif defined(__OpenBSD__) + if (ent->ifa_addr->sa_family != PF_INET) + return 1; +#endif + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs* addrs; + struct ifaddrs* ent; + uv_interface_address_t* address; + int i; + + if (getifaddrs(&addrs) != 0) + return UV__ERR(errno); + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + continue; + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (*addresses == NULL) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) + continue; + + address = *addresses; + + for (i = 0; i < *count; i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { +#if defined(__CYGWIN__) || defined(__MSYS__) + memset(address->phys_addr, 0, sizeof(address->phys_addr)); +#else + struct sockaddr_dl* sa_addr; + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); +#endif + } + 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/3rd/libuv-1.19.2/src/unix/core.c b/3rd/libuv-1.19.2/src/unix/core.c new file mode 100644 index 00000000..3741c1d0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/core.c @@ -0,0 +1,1355 @@ +/* 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 /* NULL */ +#include /* printf */ +#include +#include /* strerror */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* INT_MAX, PATH_MAX, IOV_MAX */ +#include /* writev */ +#include /* getrusage */ +#include + +#ifdef __sun +# include /* MAXHOSTNAMELEN on Solaris */ +# include +# include +# include +#endif + +#ifdef __APPLE__ +# include /* _NSGetExecutablePath */ +# include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif +#endif + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) +# include +# include +# include +# define UV__O_CLOEXEC O_CLOEXEC +# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# define uv__accept4 accept4 +# endif +# if defined(__NetBSD__) +# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) +# endif +# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) +# 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 + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + +#if defined(__MVS__) +#include +#endif + +#if !defined(__MVS__) +#include /* MAXHOSTNAMELEN on Linux and the BSDs */ +#endif + +/* Fallback for the maximum hostname length */ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#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(!uv__is_closing(handle)); + + 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 UV_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 UV_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 UV__ERR(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 UV__ERR(errno); +#endif + + sockfd = socket(domain, type, protocol); + if (sockfd == -1) + return UV__ERR(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; +} + +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + + +int uv__accept(int sockfd) { + int peerfd; + int err; + + assert(sockfd >= 0); + + while (1) { +#if defined(__linux__) || \ + (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ + defined(__NetBSD__) + 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 UV__ERR(errno); + + no_accept4 = 1; +skip: +#endif + + peerfd = accept(sockfd, NULL, NULL); + if (peerfd == -1) { + if (errno == EINTR) + continue; + return UV__ERR(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_nocheckstdio(int fd) { + int saved_errno; + int rc; + + assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ + + saved_errno = errno; + rc = close(fd); + if (rc == -1) { + rc = UV__ERR(errno); + if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) + rc = 0; /* The close is in progress, not an error. */ + errno = saved_errno; + } + + return rc; +} + + +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ +#if defined(__MVS__) + epoll_file_close(fd); +#endif + return uv__close_nocheckstdio(fd); +} + + +int uv__nonblock_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, FIONBIO, &set); + while (r == -1 && errno == EINTR); + + if (r) + return UV__ERR(errno); + + return 0; +} + + +#if !defined(__CYGWIN__) && !defined(__MSYS__) +int uv__cloexec_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, set ? FIOCLEX : FIONCLEX); + while (r == -1 && errno == EINTR); + + if (r) + return UV__ERR(errno); + + return 0; +} +#endif + + +int uv__nonblock_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFL); + while (r == -1 && errno == EINTR); + + if (r == -1) + return UV__ERR(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 UV__ERR(errno); + + return 0; +} + + +int uv__cloexec_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFD); + while (r == -1 && errno == EINTR); + + if (r == -1) + return UV__ERR(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 UV__ERR(errno); + + return 0; +} + + +/* 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 UV__ERR(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 UV__ERR(errno); + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return UV__ERR(errno); + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return UV__ERR(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 UV_EINVAL; + + if (getcwd(buffer, *size) == NULL) + return UV__ERR(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 UV__ERR(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 UV_EINVAL; + } + + if (uv__is_closing(handle) || fd_out == -1) + return UV_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, 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + 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) + 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + 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, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + assert(0 != events); + return 0 != (w->pevents & events); +} + + +int uv_getrusage(uv_rusage_t* rusage) { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + return UV__ERR(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; + +#if !defined(__MVS__) + 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; +#endif + + return 0; +} + + +int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(UV__O_CLOEXEC) + static int no_cloexec; + + if (!no_cloexec) { + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return UV__ERR(errno); + + /* O_CLOEXEC not supported. */ + no_cloexec = 1; + } +#endif + + fd = open(path, flags); + if (fd == -1) + return UV__ERR(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) || defined(__NetBSD__) + r = dup3(oldfd, newfd, O_CLOEXEC); + if (r == -1) + return UV__ERR(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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + + err = uv__cloexec(newfd, 1); + if (err) { + uv__close(newfd); + return err; + } + + return r; + } +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + char* buf; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Check if the HOME environment variable is set first */ + buf = getenv("HOME"); + + if (buf != NULL) { + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + + return 0; + } + + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return UV_ENOSYS; +#endif + + if (pwd == NULL) + return UV_EINVAL; + + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); + + if (initsize <= 0) + bufsize = 4096; + else + bufsize = (size_t) initsize; + + uid = geteuid(); + buf = NULL; + + for (;;) { + uv__free(buf); + buf = uv__malloc(bufsize); + + if (buf == NULL) + return UV_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 UV_ENOENT; + } + + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); + + if (pwd->username == NULL) { + uv__free(buf); + return UV_ENOMEM; + } + + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + + uv__free(buf); + + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} + + +int uv_translate_sys_error(int sys_errno) { + /* If < 0 then it's already a libuv error. */ + return sys_errno <= 0 ? sys_errno : -sys_errno; +} + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + char* var; + size_t len; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + var = getenv(name); + + if (var == NULL) + return UV_ENOENT; + + len = strlen(var); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, var, len + 1); + *size = len; + + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + if (name == NULL || value == NULL) + return UV_EINVAL; + + if (setenv(name, value, 1) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + if (name == NULL) + return UV_EINVAL; + + if (unsetenv(name) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_gethostname(char* buffer, size_t* size) { + /* + On some platforms, if the input buffer is not large enough, gethostname() + succeeds, but truncates the result. libuv can detect this and return ENOBUFS + instead by creating a large enough buffer and comparing the hostname length + to the size input. + */ + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (gethostname(buf, sizeof(buf)) != 0) + return UV__ERR(errno); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return fd; +} + + +uv_pid_t uv_os_getpid(void) { + return getpid(); +} + + +uv_pid_t uv_os_getppid(void) { + return getppid(); +} diff --git a/3rd/libuv-1.19.2/src/unix/cygwin.c b/3rd/libuv-1.19.2/src/unix/cygwin.c new file mode 100644 index 00000000..9fe4093e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/cygwin.c @@ -0,0 +1,54 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +int uv_uptime(double* uptime) { + struct sysinfo info; + + if (sysinfo(&info) < 0) + return UV__ERR(errno); + + *uptime = info.uptime; + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + /* FIXME: read /proc/meminfo? */ + *rss = 0; + return UV_ENOSYS; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + /* FIXME: read /proc/stat? */ + *cpu_infos = NULL; + *count = 0; + return UV_ENOSYS; +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + (void)cpu_infos; + (void)count; +} diff --git a/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c b/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c new file mode 100644 index 00000000..dabde223 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c @@ -0,0 +1,209 @@ +/* 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 +#include +#include +#include + +#include + +#if !TARGET_OS_IPHONE +# include +# include +#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 UV_ENOSYS; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + err = dynamic_pthread_setname_np(namebuf); + if (err) + return UV__ERR(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 = UV_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 = UV_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 = UV_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/3rd/libuv-1.19.2/src/unix/darwin.c b/3rd/libuv-1.19.2/src/unix/darwin.c new file mode 100644 index 00000000..31ad8a9e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/darwin.c @@ -0,0 +1,231 @@ +/* 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 +#include +#include + +#include +#include +#include /* _NSGetExecutablePath */ +#include +#include +#include /* sysconf */ + + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->cf_state = NULL; + + if (uv__kqueue_init(loop)) + return UV__ERR(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 UV_EINVAL; + + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return UV_EIO; + + if (realpath(exepath, abspath) != abspath) + return UV__ERR(errno); + + abspath_size = strlen(abspath); + if (abspath_size == 0) + return UV_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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + } + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) + return UV__ERR(errno); + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, + (processor_info_array_t*)&info, + &msg_type) != KERN_SUCCESS) { + return UV_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 UV_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); +} diff --git a/3rd/libuv-1.19.2/src/unix/dl.c b/3rd/libuv-1.19.2/src/unix/dl.c new file mode 100644 index 00000000..fc1c052b --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +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/3rd/libuv-1.19.2/src/unix/freebsd.c b/3rd/libuv-1.19.2/src/unix/freebsd.c new file mode 100644 index 00000000..70ccb130 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/freebsd.c @@ -0,0 +1,375 @@ +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include /* VM_LOADAVG */ +#include +#include +#include /* sysconf */ +#include + +#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 uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +#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 UV_EINVAL; + + abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); + if (abspath_size < 0) + return UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(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]; + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_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); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\0'; + + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + struct kinfo_proc kinfo; + size_t page_size; + size_t kinfo_size; + int mib[4]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + kinfo_size = sizeof(kinfo); + + if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) + return UV__ERR(errno); + + page_size = getpagesize(); + +#ifdef __DragonFly__ + *rss = kinfo.kp_vm_rssize * page_size; +#else + *rss = kinfo.ki_rssize * page_size; +#endif + + return 0; +} + + +int uv_uptime(double* uptime) { + int r; + struct timespec sp; + r = clock_gettime(CLOCK_MONOTONIC, &sp); + if (r) + return UV__ERR(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; + const char* model_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 + +#if defined(__arm__) || defined(__aarch64__) + /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ + model_key = "hw.machine"; + cpuspeed = 0; +#else + model_key = "hw.model"; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) + return -errno; +#endif + + size = sizeof(model); + if (sysctlbyname(model_key, &model, &size, NULL, 0)) + return UV__ERR(errno); + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return UV_ENOMEM; + + *count = numcpus; + + /* 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)) { + uv__free(*cpu_infos); + return UV__ERR(errno); + } + + size = maxcpus * CPUSTATES * sizeof(long); + + cp_times = uv__malloc(size); + if (cp_times == NULL) { + uv__free(*cpu_infos); + return UV_ENOMEM; + } + + if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return UV__ERR(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); +} diff --git a/3rd/libuv-1.19.2/src/unix/fs.c b/3rd/libuv-1.19.2/src/unix/fs.c new file mode 100644 index 00000000..92e2d255 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/fs.c @@ -0,0 +1,1513 @@ +/* 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 +#include +#include +#include +#include /* PATH_MAX */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_PREADV 1 +#else +# define HAVE_PREADV 0 +#endif + +#if defined(__linux__) || defined(__sun) +# include +#endif + +#if defined(__APPLE__) +# include +#endif + +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + UV_REQ_INIT(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->bufs = 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) \ + return UV_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) \ + return UV_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__req_register(loop, req); \ + 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_fsync(uv_fs_t* req) { +#if defined(__APPLE__) + /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache + * to the drive platters. This is in contrast to Linux's fdatasync and fsync + * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we should fall back to fsync(). This is the + * same approach taken by sqlite. + */ + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0 && errno == ENOTTY) + r = fsync(req->file); + return r; +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); +#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 = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(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 = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(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(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__sun) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; +# if defined(__sun) + return futimesat(req->file, NULL, tv); +# else + return futimes(req->file, tv); +# endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); +#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) + 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(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) +#define UV_CONST_DIRENT uv__dirent_t +#else +#define UV_CONST_DIRENT const uv__dirent_t +#endif + + +static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) { + return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; +} + + +static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { + return strcmp((*a)->d_name, (*b)->d_name); +} + + +static ssize_t uv__fs_scandir(uv_fs_t* req) { + uv__dirent_t **dents; + int n; + + dents = NULL; + n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort); + + /* NOTE: We will use nbufs as an index field */ + req->nbufs = 0; + + if (n == 0) { + /* OS X still needs to deallocate some memory. + * Memory was allocated using the system allocator, so use free() here. + */ + free(dents); + dents = NULL; + } else if (n == -1) { + return n; + } + + req->ptr = dents; + + 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 +#error "PATH_MAX undefined in the current platform" +#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; + } + +#if defined(__MVS__) + len = os390_readlink(req->path, buf, len); +#else + len = readlink(req->path, buf, len); +#endif + + + 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(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) + { + 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); +#elif defined(__FreeBSD_kernel__) + len = 0; + r = bsd_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 ssize_t uv__fs_copyfile(uv_fs_t* req) { +#if defined(__APPLE__) && !TARGET_OS_IPHONE + /* On macOS, use the native copyfile(3). */ + copyfile_flags_t flags; + + flags = COPYFILE_ALL; + + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + + return copyfile(req->path, req->new_path, NULL, flags); +#else + uv_fs_t fs_req; + uv_file srcfd; + uv_file dstfd; + struct stat statsbuf; + int dst_flags; + int result; + int err; + size_t bytes_to_send; + int64_t in_offset; + + dstfd = -1; + err = 0; + + /* Open the source file. */ + srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); + uv_fs_req_cleanup(&fs_req); + + if (srcfd < 0) + return srcfd; + + /* Get the source file's mode. */ + if (fstat(srcfd, &statsbuf)) { + err = UV__ERR(errno); + goto out; + } + + dst_flags = O_WRONLY | O_CREAT | O_TRUNC; + + if (req->flags & UV_FS_COPYFILE_EXCL) + dst_flags |= O_EXCL; + + /* Open the destination file. */ + dstfd = uv_fs_open(NULL, + &fs_req, + req->new_path, + dst_flags, + statsbuf.st_mode, + NULL); + uv_fs_req_cleanup(&fs_req); + + if (dstfd < 0) { + err = dstfd; + goto out; + } + + if (fchmod(dstfd, statsbuf.st_mode) == -1) { + err = UV__ERR(errno); + goto out; + } + + bytes_to_send = statsbuf.st_size; + in_offset = 0; + while (bytes_to_send != 0) { + err = uv_fs_sendfile(NULL, + &fs_req, + dstfd, + srcfd, + in_offset, + bytes_to_send, + NULL); + uv_fs_req_cleanup(&fs_req); + if (err < 0) + break; + bytes_to_send -= fs_req.result; + in_offset += fs_req.result; + } + +out: + if (err < 0) + result = err; + else + result = 0; + + /* Close the source file. */ + err = uv__close_nocheckstdio(srcfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Close the destination file if it is open. */ + if (dstfd >= 0) { + err = uv__close_nocheckstdio(dstfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Remove the destination file if something went wrong. */ + if (result != 0) { + uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); + /* Ignore the unlink return value, as an error already happened. */ + uv_fs_req_cleanup(&fs_req); + } + } + + return result; +#endif +} + +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_atimensec; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = src->st_mtimensec; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = src->st_ctimensec; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = src->st_ctimensec; + dst->st_flags = 0; + dst->st_gen = 0; +#elif !defined(_AIX) && ( \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + 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(__FreeBSD__) || \ + 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); + if (ret == 0) + 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); + if (ret == 0) + 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); + if (ret == 0) + 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 (errno == EINTR && total == -1) + return total; + + if (bufs != req->bufsml) + uv__free(bufs); + + req->bufs = NULL; + req->nbufs = 0; + + 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(COPYFILE, uv__fs_copyfile(req)); + 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, uv__fs_fsync(req)); + 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 = UV__ERR(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 == UV_ECANCELED) { + assert(req->result == 0); + req->result = UV_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) + return UV_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) { + INIT(READ); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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) + return UV_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) { + INIT(WRITE); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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) + return UV_ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + + /* 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->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + + if (req->ptr != &req->statbuf) + uv__free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + + PATH2; + req->flags = flags; + POST; +} diff --git a/3rd/libuv-1.19.2/src/unix/fsevents.c b/3rd/libuv-1.19.2/src/unix/fsevents.c new file mode 100644 index 00000000..47d8024b --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/fsevents.c @@ -0,0 +1,919 @@ +/* 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 +#include +#include +#include + +#include +#include + +/* 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; + FSEventStreamEventFlags flags; + 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++) { + flags = eventFlags[i]; + + /* Ignore system events */ + if (flags & 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; +#else + if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) + 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); + event->events = UV_RENAME; + +#ifdef MAC_OS_X_VERSION_10_7 + if (0 != (flags & kFSEventsModified) && + 0 == (flags & kFSEventsRenamed)) { + event->events = UV_CHANGE; + } +#else + if (0 != (flags & kFSEventsModified) && + 0 != (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { + event->events = UV_CHANGE; + } + if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { + event->events = UV_CHANGE; + } +#endif /* MAC_OS_X_VERSION_10_7 */ + + 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 UV_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; + + /* 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 = UV_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 = UV_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 = UV_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 = UV_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 UV_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 = UV_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 = UV__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 UV_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 UV__ERR(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 = UV_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 UV_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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/getaddrinfo.c b/3rd/libuv-1.19.2/src/unix/getaddrinfo.c new file mode 100644 index 00000000..10e8afd7 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/getaddrinfo.c @@ -0,0 +1,232 @@ +/* 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 +#include /* NULL */ +#include +#include +#include /* if_indextoname() */ + +/* EAI_* constants. */ +#include + + +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 UV__ERR(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 == UV_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 UV_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 UV_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); +} + + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + char ifname_buf[UV_IF_NAMESIZE]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (if_indextoname(ifindex, ifname_buf) == NULL) + return UV__ERR(errno); + + len = strnlen(ifname_buf, sizeof(ifname_buf)); + + if (*size <= len) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ifname_buf, len); + buffer[len] = '\0'; + *size = len; + + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + return uv_if_indextoname(ifindex, buffer, size); +} diff --git a/3rd/libuv-1.19.2/src/unix/getnameinfo.c b/3rd/libuv-1.19.2/src/unix/getnameinfo.c new file mode 100644 index 00000000..9a436722 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +#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 == 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_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/3rd/libuv-1.19.2/src/unix/ibmi.c b/3rd/libuv-1.19.2/src/unix/ibmi.c new file mode 100644 index 00000000..c50a4e76 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/ibmi.c @@ -0,0 +1,112 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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]) { + avg[0] = avg[1] = avg[2] = 0; + return; +} + + +int uv_resident_set_memory(size_t* rss) { + return UV_ENOSYS; +} + + +int uv_uptime(double* uptime) { + return UV_ENOSYS; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus, idx = 0; + uv_cpu_info_t* cpu_info; + + *cpu_infos = NULL; + *count = 0; + + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + + *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + return UV_ENOMEM; + } + + cpu_info = *cpu_infos; + for (idx = 0; idx < numcpus; idx++) { + cpu_info->speed = 0; + cpu_info->model = uv__strdup("unknown"); + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + cpu_info++; + } + *count = numcpus; + + return 0; +} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/internal.h b/3rd/libuv-1.19.2/src/unix/internal.h new file mode 100644 index 00000000..2bb3773c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/internal.h @@ -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. + */ + +#ifndef UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "uv-common.h" + +#include +#include /* abort */ +#include /* strrchr */ +#include /* O_CLOEXEC, may be */ +#include +#include + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__MVS__) +# include "os390-syscalls.h" +#endif /* __MVS__ */ + +#if defined(__sun) +# include +# include +#endif /* __sun */ + +#if defined(_AIX) +# define reqevents events +# define rtnevents revents +# include +#else +# include +#endif /* _AIX */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +#endif + +#if defined(__ANDROID__) +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 + +#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 + +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 +#endif + +#ifdef POLLPRI +# define UV__POLLPRI POLLPRI +#else +# define UV__POLLPRI 0 +#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. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ +}; + +/* loop flags */ +enum { + UV_LOOP_BLOCK_SIGPROF = 1 +}; + +/* flags of excluding ifaddr */ +enum { + UV__EXCLUDE_IFPHYS, + UV__EXCLUDE_IFADDR +}; + +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]; +}; + + +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + +/* core */ +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(int fd, int set); +int uv__nonblock_ioctl(int fd, int set); +int uv__nonblock_fcntl(int fd, int set); +int uv__close(int fd); +int uv__close_nocheckstdio(int fd); +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); +int uv__io_check_fd(uv_loop_t* loop, int fd); +void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ +int uv__io_fork(uv_loop_t* loop); + +/* async */ +void uv__async_stop(uv_loop_t* loop); +int uv__async_fork(uv_loop_t* loop); + + +/* 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); +int uv__signal_loop_fork(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); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + + +#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__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; +} + +#if defined(__linux__) +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); +#endif + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/kqueue.c b/3rd/libuv-1.19.2/src/unix/kqueue.c new file mode 100644 index 00000000..a30fd730 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/kqueue.c @@ -0,0 +1,533 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Required on + * - Until at least FreeBSD 11.0 + * - Older versions of Mac OS X + * + * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp + */ +#ifndef EV_OOBAND +#define EV_OOBAND EV_FLAG1 +#endif + +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 UV__ERR(errno); + + uv__cloexec(loop->backend_fd, 1); + + return 0; +} + + +#if defined(__APPLE__) +static int uv__has_forked_with_cfrunloop; +#endif + +int uv__io_fork(uv_loop_t* loop) { + int err; + loop->backend_fd = -1; + err = uv__kqueue_init(loop); + if (err) + return err; + +#if defined(__APPLE__) + if (loop->cf_state != NULL) { + /* We cannot start another CFRunloop and/or thread in the child + process; CF aborts if you try or if you try to touch the thread + at all to kill it. So the best we can do is ignore it from now + on. This means we can't watch directories in the same way + anymore (like other BSDs). It also means we cannot properly + clean up the allocated resources; calling + uv__fsevents_loop_delete from uv_loop_close will crash the + process. So we sidestep the issue by pretending like we never + started it in the first place. + */ + uv__has_forked_with_cfrunloop = 1; + uv__free(loop->cf_state); + loop->cf_state = NULL; + } +#endif + return err; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = UV__ERR(errno); + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + +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 have_signals; + 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 & POLLIN) == 0 && (w->pevents & 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 & POLLOUT) == 0 && (w->pevents & 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; + } + } + + if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { + EV_SET(events + nevents, w->fd, EV_OOBAND, 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; + } + + have_signals = 0; + 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 == POLLIN); + assert(w->pevents == POLLIN); + w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + nevents++; + continue; + } + + revents = 0; + + if (ev->filter == EVFILT_READ) { + if (w->pevents & POLLIN) { + revents |= 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 == EV_OOBAND) { + if (w->pevents & UV__POLLPRI) { + revents |= UV__POLLPRI; + 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 & POLLOUT) { + revents |= 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 |= POLLERR; + + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + + if (revents == 0) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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 UV_EINVAL; + + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return UV__ERR(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__) + if (uv__has_forked_with_cfrunloop) + goto fallback; + + /* 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, 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__has_forked_with_cfrunloop || 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/3rd/libuv-1.19.2/src/unix/linux-core.c b/3rd/libuv-1.19.2/src/unix/linux-core.c new file mode 100644 index 00000000..b63c25f3 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-core.c @@ -0,0 +1,951 @@ +/* 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. + */ + +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +# endif +# include +# include +# include +#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 but we can't + * include that file because it conflicts with . 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(FILE* statfile_fp, + 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 UV__ERR(errno); + + return 0; +} + + +int uv__io_fork(uv_loop_t* loop) { + int err; + void* old_watchers; + + old_watchers = loop->inotify_watchers; + + uv__close(loop->backend_fd); + loop->backend_fd = -1; + uv__platform_loop_delete(loop); + + err = uv__platform_loop_init(loop); + if (err) + return err; + + return uv__inotify_fork(loop, old_watchers); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher, 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); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = POLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = UV__ERR(errno); + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +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 have_signals; + 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); + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + 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; + } + + have_signals = 0; + 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 | POLLERR | 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 == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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; +} + + +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 UV__ERR(errno); + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + uv__close(fd); + if (n == -1) + return UV__ERR(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 UV_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 UV__ERR(errno); + + *uptime = now.tv_sec; + return 0; +} + + +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + return UV_EIO; + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + if (num == 0) + return UV_EIO; + + *numcpus = num; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus; + uv_cpu_info_t* ci; + int err; + FILE* statfile_fp; + + *cpu_infos = NULL; + *count = 0; + + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return UV__ERR(errno); + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + goto out; + + err = UV_ENOMEM; + ci = uv__calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + goto out; + + err = read_models(numcpus, ci); + if (err == 0) + err = read_times(statfile_fp, numcpus, ci); + + if (err) { + uv_free_cpu_info(ci, numcpus); + goto out; + } + + /* 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; + err = 0; + +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; +} + + +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 = uv__open_file("/proc/cpuinfo"); + if (fp == NULL) + return UV__ERR(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 UV_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 UV_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 UV_ENOMEM; + ci[model_idx++].model = model; + } + + return 0; +} + + +static int read_times(FILE* statfile_fp, + 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]; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + rewind(statfile_fp); + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " 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; + } + 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 = uv__open_file(buf); + 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); +} + +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + /* + * 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) + return exclude_type; + return !exclude_type; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { +#ifndef HAVE_IFADDRS_H + return UV_ENOSYS; +#else + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; + + if (getifaddrs(&addrs)) + return UV__ERR(errno); + + *count = 0; + *addresses = NULL; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + continue; + + (*count)++; + } + + if (*count == 0) + return 0; + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) + 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/3rd/libuv-1.19.2/src/unix/linux-inotify.c b/3rd/libuv-1.19.2/src/unix/linux-inotify.c new file mode 100644 index 00000000..bcad630f --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-inotify.c @@ -0,0 +1,352 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include + +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 void maybe_free_watcher_list(struct watcher_list* w, + uv_loop_t* loop); + +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 UV__ERR(errno); + + fd = uv__inotify_init(); + if (fd == -1) + return UV__ERR(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, POLLIN); + + return 0; +} + + +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { + /* Open the inotify_fd, and re-arm all the inotify watchers. */ + int err; + struct watcher_list* tmp_watcher_list_iter; + struct watcher_list* watcher_list; + struct watcher_list tmp_watcher_list; + QUEUE queue; + QUEUE* q; + uv_fs_event_t* handle; + char* tmp_path; + + if (old_watchers != NULL) { + /* We must restore the old watcher list to be able to close items + * out of it. + */ + loop->inotify_watchers = old_watchers; + + QUEUE_INIT(&tmp_watcher_list.watchers); + /* Note that the queue we use is shared with the start and stop() + * functions, making QUEUE_FOREACH unsafe to use. So we use the + * QUEUE_MOVE trick to safely iterate. Also don't free the watcher + * list until we're done iterating. c.f. uv__inotify_read. + */ + RB_FOREACH_SAFE(watcher_list, watcher_root, + CAST(&old_watchers), tmp_watcher_list_iter) { + watcher_list->iterating = 1; + QUEUE_MOVE(&watcher_list->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + /* It's critical to keep a copy of path here, because it + * will be set to NULL by stop() and then deallocated by + * maybe_free_watcher_list + */ + tmp_path = uv__strdup(handle->path); + assert(tmp_path != NULL); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&watcher_list->watchers, q); + uv_fs_event_stop(handle); + + QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); + handle->path = tmp_path; + } + watcher_list->iterating = 0; + maybe_free_watcher_list(watcher_list, loop); + } + + QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + QUEUE_REMOVE(q); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + tmp_path = handle->path; + handle->path = NULL; + err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); + uv__free(tmp_path); + if (err) + return err; + } + } + + 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 UV_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 UV__ERR(errno); + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + w = uv__malloc(sizeof(*w) + strlen(path) + 1); + if (w == NULL) + return UV_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/3rd/libuv-1.19.2/src/unix/linux-syscalls.c b/3rd/libuv-1.19.2/src/unix/linux-syscalls.c new file mode 100644 index 00000000..89998ded --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include +#include + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define MSAN_ACTIVE 1 +# include +# 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/3rd/libuv-1.19.2/src/unix/linux-syscalls.h b/3rd/libuv-1.19.2/src/unix/linux-syscalls.h new file mode 100644 index 00000000..4c095e9b --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-syscalls.h @@ -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. + */ + +#ifndef UV_LINUX_SYSCALL_H_ +#define UV_LINUX_SYSCALL_H_ + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#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 + +/* 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/3rd/libuv-1.19.2/src/unix/loop-watcher.c b/3rd/libuv-1.19.2/src/unix/loop-watcher.c new file mode 100644 index 00000000..b8c1c2a7 --- /dev/null +++ b/3rd/libuv-1.19.2/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 UV_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/3rd/libuv-1.19.2/src/unix/loop.c b/3rd/libuv-1.19.2/src/unix/loop.c new file mode 100644 index 00000000..5b5b0e09 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/loop.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 "tree.h" +#include "internal.h" +#include "heap-inl.h" +#include +#include +#include + +int uv_loop_init(uv_loop_t* loop) { + void* saved_data; + int err; + + + saved_data = loop->data; + memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + + 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); + loop->async_io_watcher.fd = -1; + loop->async_wfd = -1; + 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; + + uv__signal_global_once_init(); + 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; +} + + +int uv_loop_fork(uv_loop_t* loop) { + int err; + unsigned int i; + uv__io_t* w; + + err = uv__io_fork(loop); + if (err) + return err; + + err = uv__async_fork(loop); + if (err) + return err; + + err = uv__signal_loop_fork(loop); + if (err) + return err; + + /* Rearm all the watchers that aren't re-queued by the above. */ + for (i = 0; i < loop->nwatchers; i++) { + w = loop->watchers[i]; + if (w == NULL) + continue; + + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) { + w->events = 0; /* Force re-registration in uv__io_poll. */ + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + } + + return 0; +} + + +void uv__loop_close(uv_loop_t* loop) { + uv__signal_loop_cleanup(loop); + uv__platform_loop_delete(loop); + uv__async_stop(loop); + + 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/3rd/libuv-1.19.2/src/unix/netbsd.c b/3rd/libuv-1.19.2/src/unix/netbsd.c new file mode 100644 index 00000000..2605c114 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/netbsd.c @@ -0,0 +1,309 @@ +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +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) { + /* Intermediate buffer, retrieving partial path name does not work + * As of NetBSD-8(beta), vnode->path translator does not handle files + * with longer names than 31 characters. + */ + char int_buf[PATH_MAX]; + size_t int_size; + int mib[4]; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = -1; + mib[3] = KERN_PROC_PATHNAME; + int_size = ARRAY_SIZE(int_buf); + + if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) + return UV__ERR(errno); + + /* Copy string from the intermediate buffer to outer one with appropriate + * length. + */ + strlcpy(buffer, int_buf, *size); + + /* Set new size. */ + *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 UV__ERR(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 UV__ERR(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) { + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\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 UV_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 UV__ERR(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 UV__ERR(errno); + } + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return UV__ERR(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 UV_ENOMEM; + + if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return UV_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); +} diff --git a/3rd/libuv-1.19.2/src/unix/no-fsevents.c b/3rd/libuv-1.19.2/src/unix/no-fsevents.c new file mode 100644 index 00000000..158643af --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/no-fsevents.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return UV_ENOSYS; +} + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return UV_ENOSYS; +} + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return UV_ENOSYS; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} diff --git a/3rd/libuv-1.19.2/src/unix/no-proctitle.c b/3rd/libuv-1.19.2/src/unix/no-proctitle.c new file mode 100644 index 00000000..165740ca --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/no-proctitle.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +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 (buffer == NULL || size == 0) + return UV_EINVAL; + + buffer[0] = '\0'; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/openbsd.c b/3rd/libuv-1.19.2/src/unix/openbsd.c new file mode 100644 index 00000000..ce937cd3 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/openbsd.c @@ -0,0 +1,313 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +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 UV_EINVAL; + + mypid = getpid(); + for (;;) { + err = UV_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 = UV__ERR(errno); + goto out; + } + argsbuf_size *= 2U; + } + + if (argsbuf[0] == NULL) { + err = UV_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 UV__ERR(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 UV__ERR(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) { + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return UV_ENOMEM; + + *count = numcpus; + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return UV__ERR(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)) { + uv__free(*cpu_infos); + return UV__ERR(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); +} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.c b/3rd/libuv-1.19.2/src/unix/os390-syscalls.c new file mode 100644 index 00000000..21558ea8 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390-syscalls.c @@ -0,0 +1,499 @@ +/* Copyright 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. + */ + + +#include "os390-syscalls.h" +#include +#include +#include +#include +#include +#include + +#define CW_CONDVAR 32 + +#pragma linkage(BPX4CTW, OS) +#pragma linkage(BPX1CTW, OS) + +static int number_of_epolls; +static QUEUE global_epoll_queue; +static uv_mutex_t global_epoll_lock; +static uv_once_t once = UV_ONCE_INIT; + +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent*), + int (*compar)(const struct dirent**, + const struct dirent **)) { + struct dirent** nl; + struct dirent* dirent; + unsigned count; + size_t allocated; + DIR* mdir; + + nl = NULL; + count = 0; + allocated = 0; + mdir = opendir(maindir); + if (!mdir) + return -1; + + while (1) { + dirent = readdir(mdir); + if (!dirent) + break; + if (!filter || filter(dirent)) { + struct dirent* copy; + copy = uv__malloc(sizeof(*copy)); + if (!copy) { + while (count) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; + } + memcpy(copy, dirent, sizeof(*copy)); + + nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); + nl[count++] = copy; + } + } + + qsort(nl, count, sizeof(struct dirent *), + (int (*)(const void *, const void *)) compar); + + closedir(mdir); + + *namelist = nl; + return count; +} + + +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__os390_epoll* lst, unsigned int len) { + unsigned int newsize; + unsigned int i; + struct pollfd* newlst; + struct pollfd event; + + if (len <= lst->size) + return; + + if (lst->size == 0) + event.fd = -1; + else { + /* Extract the message queue at the end. */ + event = lst->items[lst->size - 1]; + lst->items[lst->size - 1].fd = -1; + } + + newsize = next_power_of_two(len); + newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); + + if (newlst == NULL) + abort(); + for (i = lst->size; i < newsize; ++i) + newlst[i].fd = -1; + + /* Restore the message queue at the end */ + newlst[newsize - 1] = event; + + lst->items = newlst; + lst->size = newsize; +} + + +static void init_message_queue(uv__os390_epoll* lst) { + struct { + long int header; + char body; + } msg; + + /* initialize message queue */ + lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); + if (lst->msg_queue == -1) + abort(); + + /* + On z/OS, the message queue will be affiliated with the process only + when a send is performed on it. Once this is done, the system + can be queried for all message queues belonging to our process id. + */ + msg.header = 1; + if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) + abort(); + + /* Clean up the dummy message sent above */ + if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) + abort(); +} + + +static void before_fork(void) { + uv_mutex_lock(&global_epoll_lock); +} + + +static void after_fork(void) { + uv_mutex_unlock(&global_epoll_lock); +} + + +static void child_fork(void) { + QUEUE* q; + uv_once_t child_once = UV_ONCE_INIT; + + /* reset once */ + memcpy(&once, &child_once, sizeof(child_once)); + + /* reset epoll list */ + while (!QUEUE_EMPTY(&global_epoll_queue)) { + uv__os390_epoll* lst; + q = QUEUE_HEAD(&global_epoll_queue); + QUEUE_REMOVE(q); + lst = QUEUE_DATA(q, uv__os390_epoll, member); + uv__free(lst->items); + lst->items = NULL; + lst->size = 0; + } + + uv_mutex_unlock(&global_epoll_lock); + uv_mutex_destroy(&global_epoll_lock); +} + + +static void epoll_init(void) { + QUEUE_INIT(&global_epoll_queue); + if (uv_mutex_init(&global_epoll_lock)) + abort(); + + if (pthread_atfork(&before_fork, &after_fork, &child_fork)) + abort(); +} + + +uv__os390_epoll* epoll_create1(int flags) { + uv__os390_epoll* lst; + + lst = uv__malloc(sizeof(*lst)); + if (lst != NULL) { + /* initialize list */ + lst->size = 0; + lst->items = NULL; + init_message_queue(lst); + maybe_resize(lst, 1); + lst->items[lst->size - 1].fd = lst->msg_queue; + lst->items[lst->size - 1].events = POLLIN; + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + } + + return lst; +} + + +int epoll_ctl(uv__os390_epoll* lst, + int op, + int fd, + struct epoll_event *event) { + uv_mutex_lock(&global_epoll_lock); + + if (op == EPOLL_CTL_DEL) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = ENOENT; + return -1; + } + lst->items[fd].fd = -1; + } else if (op == EPOLL_CTL_ADD) { + + /* Resizing to 'fd + 1' would expand the list to contain at least + * 'fd'. But we need to guarantee that the last index on the list + * is reserved for the message queue. So specify 'fd + 2' instead. + */ + maybe_resize(lst, fd + 2); + if (lst->items[fd].fd != -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = EEXIST; + return -1; + } + lst->items[fd].fd = fd; + lst->items[fd].events = event->events; + } else if (op == EPOLL_CTL_MOD) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = ENOENT; + return -1; + } + lst->items[fd].events = event->events; + } else + abort(); + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + + +int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, + int maxevents, int timeout) { + nmsgsfds_t size; + struct pollfd* pfds; + int pollret; + int reventcount; + + size = _SET_FDS_MSGS(size, 1, lst->size - 1); + pfds = lst->items; + pollret = poll(pfds, size, timeout); + if (pollret <= 0) + return pollret; + + pollret = _NFDS(pollret) + _NMSGS(pollret); + + reventcount = 0; + for (int i = 0; + i < lst->size && i < maxevents && reventcount < pollret; ++i) { + struct epoll_event ev; + + if (pfds[i].fd == -1 || pfds[i].revents == 0) + continue; + + ev.fd = pfds[i].fd; + ev.events = pfds[i].revents; + events[reventcount++] = ev; + } + + return reventcount; +} + + +int epoll_file_close(int fd) { + QUEUE* q; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_FOREACH(q, &global_epoll_queue) { + uv__os390_epoll* lst; + + lst = QUEUE_DATA(q, uv__os390_epoll, member); + if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) + lst->items[fd].fd = -1; + } + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + +void epoll_queue_close(uv__os390_epoll* lst) { + /* Remove epoll instance from global queue */ + uv_mutex_lock(&global_epoll_lock); + QUEUE_REMOVE(&lst->member); + uv_mutex_unlock(&global_epoll_lock); + + /* Free resources */ + msgctl(lst->msg_queue, IPC_RMID, NULL); + lst->msg_queue = -1; + uv__free(lst->items); + lst->items = NULL; +} + + +int nanosleep(const struct timespec* req, struct timespec* rem) { + unsigned nano; + unsigned seconds; + unsigned events; + unsigned secrem; + unsigned nanorem; + int rv; + int rc; + int rsn; + + nano = (int)req->tv_nsec; + seconds = req->tv_sec; + events = CW_CONDVAR; + +#if defined(_LP64) + BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#else + BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#endif + + assert(rv == -1 && errno == EAGAIN); + + if(rem != NULL) { + rem->tv_nsec = nanorem; + rem->tv_sec = secrem; + } + + return 0; +} + + +char* mkdtemp(char* path) { + static const char* tempchars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + char *ep, *cp; + unsigned int tries, i; + size_t len; + uint64_t v; + int fd; + int retval; + int saved_errno; + + len = strlen(path); + ep = path + len; + if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { + errno = EINVAL; + return NULL; + } + + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + return NULL; + + tries = TMP_MAX; + retval = -1; + do { + if (read(fd, &v, sizeof(v)) != sizeof(v)) + break; + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (mkdir(path, S_IRWXU) == 0) { + retval = 0; + break; + } + else if (errno != EEXIST) + break; + } while (--tries); + + saved_errno = errno; + uv__close(fd); + if (tries == 0) { + errno = EEXIST; + return NULL; + } + + if (retval == -1) { + errno = saved_errno; + return NULL; + } + + return path; +} + + +ssize_t os390_readlink(const char* path, char* buf, size_t len) { + ssize_t rlen; + ssize_t vlen; + ssize_t plen; + char* delimiter; + char old_delim; + char* tmpbuf; + char realpathstr[PATH_MAX + 1]; + + tmpbuf = uv__malloc(len + 1); + if (tmpbuf == NULL) { + errno = ENOMEM; + return -1; + } + + rlen = readlink(path, tmpbuf, len); + if (rlen < 0) { + uv__free(tmpbuf); + return rlen; + } + + if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { + /* Straightforward readlink. */ + memcpy(buf, tmpbuf, rlen); + uv__free(tmpbuf); + return rlen; + } + + /* + * There is a parmlib variable at the beginning + * which needs interpretation. + */ + tmpbuf[rlen] = '\0'; + delimiter = strchr(tmpbuf + 2, '/'); + if (delimiter == NULL) + /* No slash at the end */ + delimiter = strchr(tmpbuf + 2, '\0'); + + /* Read real path of the variable. */ + old_delim = *delimiter; + *delimiter = '\0'; + if (realpath(tmpbuf, realpathstr) == NULL) { + uv__free(tmpbuf); + return -1; + } + + /* realpathstr is not guaranteed to end with null byte.*/ + realpathstr[PATH_MAX] = '\0'; + + /* Reset the delimiter and fill up the buffer. */ + *delimiter = old_delim; + plen = strlen(delimiter); + vlen = strlen(realpathstr); + rlen = plen + vlen; + if (rlen > len) { + uv__free(tmpbuf); + errno = ENAMETOOLONG; + return -1; + } + memcpy(buf, realpathstr, vlen); + memcpy(buf + vlen, delimiter, plen); + + /* Done using temporary buffer. */ + uv__free(tmpbuf); + + return rlen; +} + + +size_t strnlen(const char* str, size_t maxlen) { + void* p = memchr(str, 0, maxlen); + if (p == NULL) + return maxlen; + else + return p - str; +} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.h b/3rd/libuv-1.19.2/src/unix/os390-syscalls.h new file mode 100644 index 00000000..6e34a88c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390-syscalls.h @@ -0,0 +1,72 @@ +/* Copyright 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. + */ + + +#ifndef UV_OS390_SYSCALL_H_ +#define UV_OS390_SYSCALL_H_ + +#include "uv.h" +#include "internal.h" +#include +#include +#include + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 +#define MAX_EPOLL_INSTANCES 256 +#define MAX_ITEMS_PER_EPOLL 1024 + +#define UV__O_CLOEXEC 0x80000 +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD +#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL +#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD + +struct epoll_event { + int events; + int fd; +}; + +typedef struct { + QUEUE member; + struct pollfd* items; + unsigned long size; + int msg_queue; +} uv__os390_epoll; + +/* epoll api */ +uv__os390_epoll* epoll_create1(int flags); +int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event); +int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout); +int epoll_file_close(int fd); + +/* utility functions */ +int nanosleep(const struct timespec* req, struct timespec* rem); +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); +char *mkdtemp(char* path); +ssize_t os390_readlink(const char* path, char* buf, size_t len); +size_t strnlen(const char* str, size_t maxlen); + +#endif /* UV_OS390_SYSCALL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/os390.c b/3rd/libuv-1.19.2/src/unix/os390.c new file mode 100644 index 00000000..f766b393 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390.c @@ -0,0 +1,998 @@ +/* Copyright 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. + */ + +#include "internal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__clang__) +#include "csrsic.h" +#else +#include "//'SYS1.SAMPLIB(CSRSIC)'" +#endif + +#define CVT_PTR 0x10 +#define PSA_PTR 0x00 +#define CSD_OFFSET 0x294 + +/* + Long-term average CPU service used by this logical partition, + in millions of service units per hour. If this value is above + the partition's defined capacity, the partition will be capped. + It is calculated using the physical CPU adjustment factor + (RCTPCPUA) so it may not match other measures of service which + are based on the logical CPU adjustment factor. It is available + if the hardware supports LPAR cluster. +*/ +#define RCTLACS_OFFSET 0xC4 + +/* 32-bit count of alive CPUs. This includes both CPs and IFAs */ +#define CSD_NUMBER_ONLINE_CPUS 0xD4 + +/* Address of system resources manager (SRM) control table */ +#define CVTOPCTP_OFFSET 0x25C + +/* Address of the RCT table */ +#define RMCTRCT_OFFSET 0xE4 + +/* Address of the rsm control and enumeration area. */ +#define CVTRCEP_OFFSET 0x490 + +/* + Number of frames currently available to system. + Excluded are frames backing perm storage, frames offline, and bad frames. +*/ +#define RCEPOOL_OFFSET 0x004 + +/* Total number of frames currently on all available frame queues. */ +#define RCEAFC_OFFSET 0x088 + +/* CPC model length from the CSRSI Service. */ +#define CPCMODEL_LENGTH 16 + +/* Pointer to the home (current) ASCB. */ +#define PSAAOLD 0x224 + +/* Pointer to rsm address space block extension. */ +#define ASCBRSME 0x16C + +/* + NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. + It does not include 2G frames. +*/ +#define RAXFMCT 0x2C + +/* Thread Entry constants */ +#define PGTH_CURRENT 1 +#define PGTH_LEN 26 +#define PGTHAPATH 0x20 +#pragma linkage(BPX4GTH, OS) +#pragma linkage(BPX1GTH, OS) + +/* TOD Clock resolution in nanoseconds */ +#define TOD_RES 4.096 + +typedef unsigned data_area_ptr_assign_type; + +typedef union { + struct { +#if defined(_LP64) + data_area_ptr_assign_type lower; +#endif + data_area_ptr_assign_type assign; + }; + char* deref; +} data_area_ptr; + + +void uv_loadavg(double avg[3]) { + /* TODO: implement the following */ + avg[0] = 0; + avg[1] = 0; + avg[2] = 0; +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + uv__os390_epoll* ep; + + ep = epoll_create1(0); + loop->ep = ep; + if (ep == NULL) + return UV__ERR(errno); + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->ep != NULL) { + epoll_queue_close(loop->ep); + loop->ep = NULL; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + unsigned long long timestamp; + __stckf(×tamp); + /* Convert to nanoseconds */ + return timestamp / TOD_RES; +} + + +/* + Get the exe path using the thread entry information + in the address space. +*/ +static int getexe(const int pid, char* buf, size_t len) { + struct { + int pid; + int thid[2]; + char accesspid; + char accessthid; + char asid[2]; + char loginname[8]; + char flag; + char len; + } Input_data; + + union { + struct { + char gthb[4]; + int pid; + int thid[2]; + char accesspid; + char accessthid[3]; + int lenused; + int offsetProcess; + int offsetConTTY; + int offsetPath; + int offsetCommand; + int offsetFileData; + int offsetThread; + } Output_data; + char buf[2048]; + } Output_buf; + + struct Output_path_type { + char gthe[4]; + short int len; + char path[1024]; + }; + + int Input_length; + int Output_length; + void* Input_address; + void* Output_address; + struct Output_path_type* Output_path; + int rv; + int rc; + int rsn; + + Input_length = PGTH_LEN; + Output_length = sizeof(Output_buf); + Output_address = &Output_buf; + Input_address = &Input_data; + memset(&Input_data, 0, sizeof Input_data); + Input_data.flag |= PGTHAPATH; + Input_data.pid = pid; + Input_data.accesspid = PGTH_CURRENT; + +#ifdef _LP64 + BPX4GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#else + BPX1GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#endif + + if (rv == -1) { + errno = rc; + return -1; + } + + /* Check highest byte to ensure data availability */ + assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); + + /* Get the offset from the lowest 3 bytes */ + Output_path = (char*)(&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + + if (Output_path->len >= len) { + errno = ENOBUFS; + return -1; + } + + strncpy(buf, Output_path->path, len); + + return 0; +} + + +/* + * 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 zOS - 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; + int pid; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + pid = getpid(); + res = getexe(pid, args, sizeof(args)); + if (res < 0) + return UV_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 UV__ERR(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 UV_EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return UV_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 UV_EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + uint64_t freeram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; + return freeram; +} + + +uint64_t uv_get_total_memory(void) { + uint64_t totalram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4; + return totalram; +} + + +int uv_resident_set_memory(size_t* rss) { + char* psa; + char* ascb; + char* rax; + size_t nframes; + + psa = PSA_PTR; + ascb = *(char* __ptr32 *)(psa + PSAAOLD); + rax = *(char* __ptr32 *)(ascb + ASCBRSME); + nframes = *(unsigned int*)(rax + RAXFMCT); + + *rss = nframes * sysconf(_SC_PAGESIZE); + return 0; +} + + +int uv_uptime(double* uptime) { + struct utmpx u ; + struct utmpx *v; + time64_t t; + + u.ut_type = BOOT_TIME; + v = getutxid(&u); + if (v == NULL) + return -1; + *uptime = difftime64(time64(&t), v->ut_tv.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + int idx; + siv1v2 info; + data_area_ptr cvt = {0}; + data_area_ptr csd = {0}; + data_area_ptr rmctrct = {0}; + data_area_ptr cvtopctp = {0}; + int cpu_usage_avg; + + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + + csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET)); + cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET)); + rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET)); + + *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS)); + cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET)); + + *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) + return UV_ENOMEM; + + cpu_info = *cpu_infos; + idx = 0; + while (idx < *count) { + cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability); + cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1); + memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1); + memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH); + cpu_info->cpu_times.user = cpu_usage_avg; + /* TODO: implement the following */ + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + ++cpu_info; + ++idx; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + for (int i = 0; i < count; ++i) + uv__free(cpu_infos[i].model); + uv__free(cpu_infos); +} + + +static int uv__interface_addresses_v6(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + __net_ifconf6header_t ifc; + __net_ifconf6entry_t* ifr; + __net_ifconf6entry_t* p; + __net_ifconf6entry_t flg; + + *count = 0; + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) + return UV__ERR(errno); + + ifc.__nif6h_version = 1; + ifc.__nif6h_buflen = maxsize; + ifc.__nif6h_buffer = uv__calloc(1, maxsize);; + + if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + + *count = 0; + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + ++(*count); + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return UV_ENOMEM; + } + address = *addresses; + + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->__nif6e_name); + + if (p->__nif6e_addr.sin6_family == AF_INET6) + address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr); + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; + + address++; + } + + uv__close(sockfd); + return 0; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + struct ifconf ifc; + struct ifreq flg; + struct ifreq* ifr; + struct ifreq* p; + int count_v6; + + /* get the ipv6 addresses first */ + uv_interface_address_t* addresses_v6; + uv__interface_addresses_v6(&addresses_v6, &count_v6); + + /* now get the ipv4 addresses */ + *count = 0; + + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (0 > sockfd) + return UV__ERR(errno); + + ifc.ifc_req = uv__calloc(1, maxsize); + ifc.ifc_len = maxsize; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#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) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc((*count + count_v6) * + sizeof(uv_interface_address_t)); + + if (!(*addresses)) { + uv__close(sockfd); + return UV_ENOMEM; + } + address = *addresses; + + /* copy over the ipv6 addresses */ + memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); + address += count_v6; + *count += count_v6; + uv__free(addresses_v6); + + 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 UV_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); + } + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + address++; + } + +#undef ADDR_SIZE +#undef MAX + + 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 epoll_event* events; + struct epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct 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].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the epoll. */ + if (loop->ep != NULL) + epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + + +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* filename, unsigned int flags) { + uv__os390_epoll* ep; + _RFIS reg_struct; + char* path; + int rc; + + if (uv__is_active(handle)) + return UV_EINVAL; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_REG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); + + path = uv__strdup(filename); + if (path == NULL) + return UV_ENOMEM; + + rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0) + return UV__ERR(errno); + + uv__handle_start(handle); + handle->path = path; + handle->cb = cb; + memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, + sizeof(handle->rfis_rftok)); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + uv__os390_epoll* ep; + _RFIS reg_struct; + int rc; + + if (!uv__is_active(handle)) + return 0; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_UNREG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, + sizeof(handle->rfis_rftok)); + + /* + * This call will take "/" as the path argument in case we + * don't care to supply the correct path. The system will simply + * ignore it. + */ + rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0 && errno != EALREADY && errno != ENOENT) + abort(); + + uv__handle_stop(handle); + + return 0; +} + + +static int os390_message_queue_handler(uv__os390_epoll* ep) { + uv_fs_event_t* handle; + int msglen; + int events; + _RFIM msg; + + if (ep->msg_queue == -1) + return 0; + + msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT); + + if (msglen == -1 && errno == ENOMSG) + return 0; + + if (msglen == -1) + abort(); + + events = 0; + if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) + events = UV_CHANGE; + else if (msg.__rfim_event == _RFIM_RENAME) + events = UV_RENAME; + else + /* Some event that we are not interested in. */ + return 0; + + handle = *(uv_fs_event_t**)(msg.__rfim_utok); + handle->cb(handle, uv__basename_r(handle->path), events, 0); + return 1; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + static const int max_safe_timeout = 1789569; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + uv__os390_epoll* ep; + int real_timeout; + QUEUE* q; + uv__io_t* w; + uint64_t base; + 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)) { + uv_stream_t* stream; + + 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); + + stream= container_of(w, uv_stream_t, io_watcher); + + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.fd = 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 (epoll_ctl(loop->ep, 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 (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + int nevents = 0; + + nfds = 0; + for (;;) { + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + nfds = epoll_wait(loop->ep, 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. + */ + base = loop->time; + SAVE_ERRNO(uv__update_time(loop)); + if (nfds == 0) { + assert(timeout != -1); + + if (timeout > 0) { + timeout = real_timeout - timeout; + continue; + } + + 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; + } + + + 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->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + ep = loop->ep; + if (fd == ep->msg_queue) { + os390_message_queue_handler(ep); + 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. + */ + epoll_ctl(loop->ep, 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 | POLLERR | POLLHUP; + + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + 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; + } +} + +void uv__set_process_title(const char* title) { + /* do nothing */ +} + +int uv__io_fork(uv_loop_t* loop) { + /* + Nullify the msg queue but don't close it because + it is still being used by the parent. + */ + loop->ep = NULL; + + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} diff --git a/3rd/libuv-1.19.2/src/unix/pipe.c b/3rd/libuv-1.19.2/src/unix/pipe.c new file mode 100644 index 00000000..e640bf29 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/pipe.c @@ -0,0 +1,357 @@ +/* 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 +#include +#include +#include +#include +#include + + +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; + + /* Already bound? */ + if (uv__stream_fd(handle) >= 0) + return UV_EINVAL; + + /* Make a copy of the file name, it outlives this function's scope. */ + pipe_fname = uv__strdup(name); + if (pipe_fname == NULL) + return UV_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 = UV__ERR(errno); + /* Convert ENOENT to EACCES for compatibility with Windows. */ + if (err == UV_ENOENT) + err = UV_EACCES; + + uv__close(sockfd); + goto err_socket; + } + + /* Success. */ + handle->flags |= UV_HANDLE_BOUND; + handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->io_watcher.fd = sockfd; + return 0; + +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 UV_EINVAL; + +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + + if (listen(uv__stream_fd(handle), backlog)) + return UV__ERR(errno); + + handle->connection_cb = cb; + handle->io_watcher.cb = uv__server_io; + uv__io_start(handle->loop, &handle->io_watcher, 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 = UV__ERR(errno); +#if defined(__CYGWIN__) || defined(__MSYS__) + /* EBADF is supposed to mean that the socket fd is bad, but + Cygwin reports EBADF instead of ENOTSOCK when the file is + not a socket. We do not expect to see a bad fd here + (e.g. due to new_sock), so translate the error. */ + if (err == UV_EBADF) + err = UV_ENOTSOCK; +#endif + 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, POLLIN | 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); + +} + + +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 UV__ERR(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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, sa.sun_path, addrlen); + *size = addrlen; + + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + + 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); +} + + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + unsigned desired_mode; + struct stat pipe_stat; + char* name_buffer; + size_t name_len; + int r; + + if (handle == NULL || uv__stream_fd(handle) == -1) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) + return UV__ERR(errno); + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) + return 0; + + pipe_stat.st_mode |= desired_mode; + + /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ + name_len = 0; + r = uv_pipe_getsockname(handle, NULL, &name_len); + if (r != UV_ENOBUFS) + return r; + + name_buffer = uv__malloc(name_len); + if (name_buffer == NULL) + return UV_ENOMEM; + + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) { + uv__free(name_buffer); + return r; + } + + r = chmod(name_buffer, pipe_stat.st_mode); + uv__free(name_buffer); + + return r != -1 ? 0 : UV__ERR(errno); +} diff --git a/3rd/libuv-1.19.2/src/unix/poll.c b/3rd/libuv-1.19.2/src/unix/poll.c new file mode 100644 index 00000000..f3b0bf4e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/poll.c @@ -0,0 +1,147 @@ +/* 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 +#include +#include + + +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); + + /* + * As documented in the kernel source fs/kernfs/file.c #780 + * poll will return POLLERR|POLLPRI in case of sysfs + * polling. This does not happen in case of out-of-band + * TCP messages. + * + * The above is the case on (at least) FreeBSD and Linux. + * + * So to properly determine a POLLPRI or a POLLERR we need + * to check for both. + */ + if ((events & POLLERR) && !(events & UV__POLLPRI)) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + uv__handle_stop(handle); + handle->poll_cb(handle, UV_EBADF, 0); + return; + } + + pevents = 0; + if (events & POLLIN) + pevents |= UV_READABLE; + if (events & UV__POLLPRI) + pevents |= UV_PRIORITIZED; + if (events & POLLOUT) + pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; + + handle->poll_cb(handle, 0, pevents); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + int err; + + err = uv__io_check_fd(loop, fd); + if (err) + return err; + + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ + err = uv__nonblock(fd, 1); + if (err == UV_ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(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, + POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + uv__handle_stop(handle); + uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!uv__is_closing(handle)); + 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 | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); + assert(!uv__is_closing(handle)); + + uv__poll_stop(handle); + + if (pevents == 0) + return 0; + + events = 0; + if (pevents & UV_READABLE) + events |= POLLIN; + if (pevents & UV_PRIORITIZED) + events |= UV__POLLPRI; + if (pevents & UV_WRITABLE) + events |= POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; + + 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/3rd/libuv-1.19.2/src/unix/posix-hrtime.c b/3rd/libuv-1.19.2/src/unix/posix-hrtime.c new file mode 100644 index 00000000..323dfc20 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/posix-hrtime.c @@ -0,0 +1,35 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +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); +} diff --git a/3rd/libuv-1.19.2/src/unix/posix-poll.c b/3rd/libuv-1.19.2/src/unix/posix-poll.c new file mode 100644 index 00000000..f356e76c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/posix-poll.c @@ -0,0 +1,324 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +/* POSIX defines poll() as a portable way to wait on file descriptors. + * Here we maintain a dynamically sized array of file descriptors and + * events to pass as the first argument to poll(). + */ + +#include +#include +#include +#include +#include + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->poll_fds = NULL; + loop->poll_fds_used = 0; + loop->poll_fds_size = 0; + loop->poll_fds_iterating = 0; + return 0; +} + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__free(loop->poll_fds); + loop->poll_fds = NULL; +} + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + +/* Allocate or dynamically resize our poll fds array. */ +static void uv__pollfds_maybe_resize(uv_loop_t* loop) { + size_t i; + size_t n; + struct pollfd* p; + + if (loop->poll_fds_used < loop->poll_fds_size) + return; + + n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; + p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); + if (p == NULL) + abort(); + + loop->poll_fds = p; + for (i = loop->poll_fds_size; i < n; i++) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + loop->poll_fds_size = n; +} + +/* Primitive swap operation on poll fds array elements. */ +static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) { + struct pollfd pfd; + pfd = loop->poll_fds[l]; + loop->poll_fds[l] = loop->poll_fds[r]; + loop->poll_fds[r] = pfd; +} + +/* Add a watcher's fd to our poll fds array with its pending events. */ +static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { + size_t i; + struct pollfd* pe; + + /* If the fd is already in the set just update its events. */ + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == w->fd) { + loop->poll_fds[i].events = w->pevents; + return; + } + } + + /* Otherwise, allocate a new slot in the set for the fd. */ + uv__pollfds_maybe_resize(loop); + pe = &loop->poll_fds[loop->poll_fds_used++]; + pe->fd = w->fd; + pe->events = w->pevents; +} + +/* Remove a watcher's fd from our poll fds array. */ +static void uv__pollfds_del(uv_loop_t* loop, int fd) { + size_t i; + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == fd) { + /* swap to last position and remove */ + --loop->poll_fds_used; + uv__pollfds_swap(loop, i, loop->poll_fds_used); + loop->poll_fds[loop->poll_fds_used].fd = -1; + loop->poll_fds[loop->poll_fds_used].events = 0; + loop->poll_fds[loop->poll_fds_used].revents = 0; + return; + } + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + sigset_t* pset; + sigset_t set; + uint64_t time_base; + uint64_t time_diff; + QUEUE* q; + uv__io_t* w; + size_t i; + unsigned int nevents; + int nfds; + int have_signals; + struct pollfd* pe; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + /* Take queued watchers and add their fds to our poll fds array. */ + 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); + + uv__pollfds_add(loop, w); + + w->events = w->pevents; + } + + /* Prepare a set of signals to block around poll(), if any. */ + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + time_base = loop->time; + + /* Loop calls to poll() and processing of results. If we get some + * results from poll() but they turn out not to be interesting to + * our caller then we need to loop around and poll() again. + */ + for (;;) { + if (pset != NULL) + if (pthread_sigmask(SIG_BLOCK, pset, NULL)) + abort(); + nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); + if (pset != NULL) + if (pthread_sigmask(SIG_UNBLOCK, pset, 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); + 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; + } + + /* Tell uv__platform_invalidate_fd not to manipulate our array + * while we are iterating over it. + */ + loop->poll_fds_iterating = 1; + + /* Initialize a count of events that we care about. */ + nevents = 0; + have_signals = 0; + + /* Loop over the entire poll fds array looking for returned events. */ + for (i = 0; i < loop->poll_fds_used; i++) { + pe = loop->poll_fds + i; + fd = pe->fd; + + /* 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, ignore. */ + uv__platform_invalidate_fd(loop, fd); + continue; + } + + /* Filter out events that user has not requested us to watch + * (e.g. POLLNVAL). + */ + pe->revents &= w->pevents | POLLERR | POLLHUP; + + if (pe->revents != 0) { + /* Run signal watchers last. */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + w->cb(loop, w, pe->revents); + } + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->poll_fds_iterating = 0; + + /* Purge invalidated fds from our poll fds array. */ + uv__pollfds_del(loop, -1); + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) + return; + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + time_diff = loop->time - time_base; + if (time_diff >= (uint64_t) timeout) + return; + + timeout -= time_diff; + } +} + +/* Remove the given fd from our poll fds array because no one + * is interested in its events anymore. + */ +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + size_t i; + + if (loop->poll_fds_iterating) { + /* uv__io_poll is currently iterating. Just invalidate fd. */ + for (i = 0; i < loop->poll_fds_used; i++) + if (loop->poll_fds[i].fd == fd) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + } else { + /* uv__io_poll is not iterating. Delete fd from the set. */ + uv__pollfds_del(loop, fd); + } +} + +/* Check whether the given fd is supported by poll(). */ +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + if (rv == -1) + return UV__ERR(errno); + + if (p[0].revents & POLLNVAL) + return UV_EINVAL; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/process.c b/3rd/libuv-1.19.2/src/unix/process.c new file mode 100644 index 00000000..74113e3a --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/process.c @@ -0,0 +1,599 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +#if defined(__linux__) || defined(__GLIBC__) +# include +#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 UV__ERR(errno); + + no_cloexec = 1; + +skip: +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return UV__ERR(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 UV__ERR(errno); + + no_pipe2 = 1; + +skip: +#endif + + if (pipe(fds)) + return UV__ERR(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 UV_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 UV_EINVAL; + + fds[1] = fd; + return 0; + + default: + assert(0 && "Unexpected flags"); + return UV_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) + 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) { + sigset_t set; + int close_fd; + int use_fd; + int err; + int fd; + int n; + + 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, UV__ERR(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, UV__ERR(errno)); + _exit(127); + } + } + } + + if (fd == use_fd) + uv__cloexec_fcntl(use_fd, 0); + else + fd = dup2(use_fd, fd); + + if (fd == -1) { + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + if (fd <= 2) + uv__nonblock_fcntl(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, UV__ERR(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, UV__ERR(errno)); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + if (options->env != NULL) { + environ = options->env; + } + + /* Reset signal disposition. Use a hard-coded limit because NSIG + * is not fixed on Linux: it's either 32, 34 or 64, depending on + * whether RT signals are enabled. We are not allowed to touch + * RT signal handlers, glibc uses them internally. + */ + for (n = 1; n < 32; n += 1) { + if (n == SIGKILL || n == SIGSTOP) + continue; /* Can't be changed. */ + + if (SIG_ERR != signal(n, SIG_DFL)) + continue; + + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + /* Reset signal mask. */ + sigemptyset(&set); + err = pthread_sigmask(SIG_SETMASK, &set, NULL); + + if (err != 0) { + uv__write_int(error_fd, UV__ERR(err)); + _exit(127); + } + + execvp(options->file, options->args); + uv__write_int(error_fd, UV__ERR(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 UV_ENOSYS; +#else + int signal_pipe[2] = { -1, -1 }; + int pipes_storage[8][2]; + 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 = UV_ENOMEM; + pipes = pipes_storage; + if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) + 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 = UV__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_nocheckstdio(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; + + if (pipes != pipes_storage) + 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) + uv__close_nocheckstdio(pipes[i][0]); + if (pipes[i][1] != -1) + uv__close_nocheckstdio(pipes[i][1]); + } + + if (pipes != pipes_storage) + 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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/procfs-exepath.c b/3rd/libuv-1.19.2/src/unix/procfs-exepath.c new file mode 100644 index 00000000..00dc021f --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/procfs-exepath.c @@ -0,0 +1,45 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return UV__ERR(errno); + + buffer[n] = '\0'; + *size = n; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/proctitle.c b/3rd/libuv-1.19.2/src/unix/proctitle.c new file mode 100644 index 00000000..1a8c7a70 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/proctitle.c @@ -0,0 +1,132 @@ +/* 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 +#include + +extern void uv__set_process_title(const char* title); + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static void* args_mem; + +static struct { + char* str; + size_t len; +} process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +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; + +#if defined(__MVS__) + /* argv is not adjacent. So just use argv[0] */ + process_title.str = argv[0]; + process_title.len = strlen(argv[0]); +#else + 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. */ +#endif + + /* 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) { + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title.len != 0) { + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + } + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (size <= process_title.len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + if (process_title.len != 0) + memcpy(buffer, process_title.str, process_title.len + 1); + + buffer[process_title.len] = '\0'; + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} diff --git a/3rd/libuv-1.19.2/src/unix/pthread-fixes.c b/3rd/libuv-1.19.2/src/unix/pthread-fixes.c new file mode 100644 index 00000000..fb179958 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/pthread-fixes.c @@ -0,0 +1,56 @@ +/* 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. */ +#include +#include +#include + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + static int workaround; + int err; + + if (workaround) { + return sigprocmask(how, set, oset); + } else { + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } + } + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/signal.c b/3rd/libuv-1.19.2/src/unix/signal.c new file mode 100644 index 00000000..b9d0a560 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/signal.c @@ -0,0 +1,564 @@ +/* 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 +#include +#include +#include +#include +#include + +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +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 int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); +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 void uv__signal_unregister_handler(int signum); + + +static uv_once_t uv__signal_global_init_guard = UV_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_reinit(void); + +static void uv__signal_global_init(void) { + if (!uv__signal_lock_pipefd[0]) + /* pthread_atfork can register before and after handlers, one + * for each child. This only registers one for the child. That + * state is both persistent and cumulative, so if we keep doing + * it the handler functions will be called multiple times. Thus + * we only want to do it once. + */ + if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) + abort(); + + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); +} + + +static void uv__signal_global_reinit(void) { + /* We can only use signal-safe functions here. + * That includes read/write and close, fortunately. + * We do all of this directly here instead of resetting + * uv__signal_global_init_guard because + * uv__signal_global_once_init is only called from uv_loop_init + * and this needs to function in existing loops. + */ + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + uv__signal_global_init(); +} + + +void uv__signal_global_once_init(void) { + uv_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.flags = 0; + 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, int oneshot) { + /* 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; + sa.sa_flags = SA_RESTART; + if (oneshot) + sa.sa_flags |= SA_RESETHAND; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return UV__ERR(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, POLLIN); + + return 0; +} + + +int uv__signal_loop_fork(uv_loop_t* loop) { + uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); + uv__close(loop->signal_pipefd[0]); + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + return uv__signal_loop_once_init(loop); +} + + +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) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +static int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { + sigset_t saved_sigmask; + int err; + uv_signal_t* first_handle; + + assert(!uv__is_closing(handle)); + + /* 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 + * 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. + * Also in case there's only one-shot handlers and a regular handler comes in. + */ + first_handle = uv__signal_first_handle(signum); + if (first_handle == NULL || + (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + err = uv__signal_register_handler(signum, oneshot); + if (err) { + /* Registering the signal handler failed. Must be an invalid signal. */ + uv__signal_unlock_and_unblock(&saved_sigmask); + return err; + } + } + + handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + + 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 (handle->flags & UV__SIGNAL_ONE_SHOT) + uv__signal_stop(handle); + + /* 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) { + int f1; + int f2; + /* 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; + + /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first + * handler returned is a one-shot handler, the rest will be too. + */ + f1 = w1->flags & UV__SIGNAL_ONE_SHOT; + f2 = w2->flags & UV__SIGNAL_ONE_SHOT; + if (f1 < f2) return -1; + if (f1 > f2) 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(!uv__is_closing(handle)); + uv__signal_stop(handle); + return 0; +} + + +static void uv__signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + sigset_t saved_sigmask; + uv_signal_t* first_handle; + int rem_oneshot; + int first_oneshot; + int ret; + + /* 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. + */ + first_handle = uv__signal_first_handle(handle->signum); + if (first_handle == NULL) { + uv__signal_unregister_handler(handle->signum); + } else { + rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; + first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; + if (first_oneshot && !rem_oneshot) { + ret = uv__signal_register_handler(handle->signum, 1); + assert(ret == 0); + } + } + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signum = 0; + uv__handle_stop(handle); +} diff --git a/3rd/libuv-1.19.2/src/unix/spinlock.h b/3rd/libuv-1.19.2/src/unix/spinlock.h new file mode 100644 index 00000000..a20c83cc --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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/3rd/libuv-1.19.2/src/unix/stream.c b/3rd/libuv-1.19.2/src/unix/stream.c new file mode 100644 index 00000000..3e786abe --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/stream.c @@ -0,0 +1,1696 @@ +/* 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* IOV_MAX */ + +#if defined(__APPLE__) +# include +# include +# include + +/* 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; +}; +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ + (errno == EMSGSIZE && send_handle)) +#else +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) +#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, POLLIN)) + FD_SET(fd, s->sread); + if (uv__io_active(&stream->io_watcher, 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 |= POLLIN; + if (FD_ISSET(fd, s->swrite)) + events |= 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 & (POLLIN | POLLOUT))); + + /* Invoke callback on event-loop */ + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); + + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, 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 UV__ERR(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; + + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + + uv__close(kq); + + if (ret == -1) + return UV__ERR(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 UV__ERR(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 = UV_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 UV_EBUSY; + + assert(fd >= 0); + stream->flags |= flags; + + if (stream->type == UV_TCP) { + if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return UV__ERR(errno); + + /* TODO Use delay the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + return UV__ERR(errno); + } + +#if defined(__APPLE__) + enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && + errno != ENOTSOCK && + errno != EINVAL) { + return UV__ERR(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, POLLIN | 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, UV_ECANCELED); + stream->connect_req = NULL; + } + + uv__stream_flush_write_queue(stream, UV_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, UV_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 UV_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 == UV_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 & POLLIN); + assert(stream->accepted_fd == -1); + assert(!(stream->flags & UV_CLOSING)); + + uv__io_start(stream->loop, &stream->io_watcher, 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 == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) + return; /* Not an error. */ + + if (err == UV_ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ + + if (err == UV_EMFILE || err == UV_ENFILE) { + err = uv__emfile_trick(loop, uv__stream_fd(stream)); + if (err == UV_EAGAIN || err == UV__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, 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; + + assert(server->loop == client->loop); + + if (server->accepted_fd == -1) + return UV_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 UV_EINVAL; + } + + client->flags |= UV_HANDLE_BOUND; + +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, 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 = UV_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, 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 = UV__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; + int err; + +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) { + int fd_to_send; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + char data[64]; + struct cmsghdr alias; + } scratch; + + if (uv__is_closing(req->send_handle)) { + err = UV_EBADF; + goto error; + } + + fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + + memset(&scratch, 0, sizeof(scratch)); + + 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 = &scratch.alias; + 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 (!WRITE_RETRY_ON_ERROR(req->send_handle)) { + err = UV__ERR(errno); + goto error; + } 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, POLLOUT); + + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); + + return; + +error: + req->error = err; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) + uv__handle_stop(stream); + 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 sslen; + socklen_t len; + int type; + + memset(&ss, 0, sizeof(ss)); + sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) + return UV_UNKNOWN_HANDLE; + + len = sizeof type; + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly 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 (sslen == 0) + return UV_NAMED_PIPE; +#endif + 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, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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 UV_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 UV_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; +} + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + +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); + + buf = uv_buf_init(NULL, 0); + stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); + if (buf.base == NULL || 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, POLLIN); + uv__stream_osx_interrupt_select(stream); + } + stream->read_cb(stream, 0, &buf); +#if defined(__CYGWIN__) || defined(__MSYS__) + } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { + uv__stream_eof(stream, &buf); + return; +#endif + } else { + /* Error. User should call uv_close(). */ + stream->read_cb(stream, UV__ERR(errno), &buf); + if (stream->flags & UV_STREAM_READING) { + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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; + } + } + +#if defined(__MVS__) + if (is_ipc && msg.msg_controllen > 0) { + uv_buf_t blankbuf; + int nread; + struct iovec *old; + + blankbuf.base = 0; + blankbuf.len = 0; + old = msg.msg_iov; + msg.msg_iov = (struct iovec*) &blankbuf; + nread = 0; + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + msg.msg_iov = old; + return; + } + } while (nread == 0 && msg.msg_controllen > 0); + msg.msg_iov = old; + } +#endif + 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; + } + } + } +} + + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#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_TTY || + stream->type == UV_NAMED_PIPE); + + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || + stream->flags & UV_STREAM_SHUTTING || + uv__is_closing(stream)) { + return UV_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, 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 & (POLLIN | POLLERR | 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 & 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 & (POLLOUT | POLLERR | 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 = UV__ERR(error); + } + + if (error == UV__ERR(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, POLLOUT); + } + + if (req->cb) + req->cb(req, error); + + if (uv__stream_fd(stream) == -1) + return; + + if (error < 0) { + uv__stream_flush_write_queue(stream, UV_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 UV_EBADF; + + if (send_handle) { + if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) + return UV_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 UV_EBADF; + +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. + See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ + return UV_ENOSYS; +#endif + } + + /* 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 UV_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, 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 UV_EAGAIN; + + has_pollout = uv__io_active(&stream->io_watcher, 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, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + if (written == 0 && req_size != 0) + return UV_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 UV_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, 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, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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, POLLIN | 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/3rd/libuv-1.19.2/src/unix/sunos.c b/3rd/libuv-1.19.2/src/unix/sunos.c new file mode 100644 index 00000000..b6b3dfea --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sunos.c @@ -0,0 +1,821 @@ +/* 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 +#include +#include +#include +#include +#include + +#ifndef SUNOS_NO_IFADDRS +# include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 + +#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 UV__ERR(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; + } +} + + +int uv__io_fork(uv_loop_t* loop) { +#if defined(PORT_SOURCE_FILE) + if (loop->fs_fd != -1) { + /* stop the watcher before we blow away its fileno */ + uv__io_stop(loop, &loop->fs_event_watcher, POLLIN); + } +#endif + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + + +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; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return UV__ERR(errno); + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + +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 have_signals; + 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; + } + + have_signals = 0; + 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; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + 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); + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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 UV_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 UV__ERR(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 UV_EBADF; + + if (port_associate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo, + FILE_ATTRIB | FILE_MODIFIED, + handle) == -1) { + return UV__ERR(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 UV_EINVAL; + + first_run = 0; + if (handle->loop->fs_fd == -1) { + portfd = port_create(); + if (portfd == -1) + return UV__ERR(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) { + uv_fs_event_stop(handle); + 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, 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 UV_ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return UV_ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return UV_ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + +#endif /* defined(PORT_SOURCE_FILE) */ + + +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 UV__ERR(errno); + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = UV_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 UV_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 UV_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 UV_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); +} + +#ifdef SUNOS_NO_IFADDRS +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + return UV_ENOSYS; +} +#else /* SUNOS_NO_IFADDRS */ +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return UV__ERR(errno); + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} + + +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + if (ent->ifa_addr->sa_family != AF_INET && + ent->ifa_addr->sa_family != AF_INET6) + return 1; + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + struct ifaddrs* addrs; + struct ifaddrs* ent; + + if (getifaddrs(&addrs)) + return UV__ERR(errno); + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + continue; + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + 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)); + + uv__set_phys_addr(address, ent); + 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/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c b/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c new file mode 100644 index 00000000..ebad0e89 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c @@ -0,0 +1,36 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +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; +} diff --git a/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c b/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c new file mode 100644 index 00000000..23b4fc6e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/tcp.c b/3rd/libuv-1.19.2/src/unix/tcp.c new file mode 100644 index 00000000..96f89312 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/tcp.c @@ -0,0 +1,444 @@ +/* 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 +#include +#include +#include + + +static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + int sockfd; + int err; + + 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; + } + + if (flags & UV_HANDLE_BOUND) { + /* Bind this new socket to an arbitrary port */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); + if (err) { + uv__close(sockfd); + return err; + } + + err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); + if (err) { + uv__close(sockfd); + return err; + } + } + + return 0; +} + + +static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + + if (domain == AF_UNSPEC) { + handle->flags |= flags; + return 0; + } + + if (uv__stream_fd(handle) != -1) { + + if (flags & UV_HANDLE_BOUND) { + + if (handle->flags & UV_HANDLE_BOUND) { + /* It is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Query to see if tcp socket is bound. */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) + return UV__ERR(errno); + + if ((saddr.ss_family == AF_INET6 && + ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || + (saddr.ss_family == AF_INET && + ((struct sockaddr_in*) &saddr)->sin_port != 0)) { + /* Handle is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Bind to arbitrary port */ + if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) + return UV__ERR(errno); + } + + handle->flags |= flags; + return 0; + } + + return new_socket(handle, domain, flags); +} + + +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 UV_EINVAL; + + if (flags & ~0xFF) + return UV_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 UV_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 UV__ERR(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) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return UV_EINVAL; +#endif + return UV__ERR(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 UV_EINVAL; + return UV__ERR(errno); + } + tcp->delayed_error = UV__ERR(errno); + + tcp->flags |= UV_HANDLE_BOUND; + 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 UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ + + err = maybe_new_socket(handle, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + handle->delayed_error = 0; + + do { + errno = 0; + r = connect(uv__stream_fd(handle), addr, addrlen); + } while (r == -1 && errno == EINTR); + + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { + 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 = UV__ERR(errno); + else + return UV__ERR(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, 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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(uv__stream_fd(handle), name, &socklen)) + return UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getpeername(uv__stream_fd(handle), name, &socklen)) + return UV__ERR(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; + unsigned long flags; + 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; + + flags = UV_STREAM_READABLE; +#if defined(__MVS__) + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + flags |= UV_HANDLE_BOUND; +#endif + err = maybe_new_socket(tcp, AF_INET, flags); + if (err) + return err; + + if (listen(tcp->io_watcher.fd, backlog)) + return UV__ERR(errno); + + tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; + + /* Start listening for connections. */ + tcp->io_watcher.cb = uv__server_io; + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); + + return 0; +} + + +int uv__tcp_nodelay(int fd, int on) { + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) + return UV__ERR(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 UV__ERR(errno); + +#ifdef TCP_KEEPIDLE + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return UV__ERR(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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/thread.c b/3rd/libuv-1.19.2/src/unix/thread.c new file mode 100644 index 00000000..3def2945 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/thread.c @@ -0,0 +1,729 @@ +/* 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 +#include +#include + +#include +#include /* getrlimit() */ +#include /* getpagesize() */ + +#include + +#ifdef __MVS__ +#include +#include +#endif + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + +#if defined(UV__PTHREAD_BARRIER_FALLBACK) +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} +#endif + + +/* On MacOS, threads other than the main thread are created with a reduced + * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. + * + * On Linux, threads created by musl have a much smaller stack than threads + * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. + */ +static size_t thread_stack_size(void) { +#if defined(__APPLE__) || defined(__linux__) + struct rlimit lim; + + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + return lim.rlim_cur; + } +#endif + +#if !defined(__linux__) + return 0; +#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) + return 4 << 20; /* glibc default. */ +#else + return 2 << 20; /* glibc default. */ +#endif +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + int err; + size_t stack_size; + pthread_attr_t* attr; + pthread_attr_t attr_storage; + + attr = NULL; + stack_size = thread_stack_size(); + + if (stack_size > 0) { + attr = &attr_storage; + + if (pthread_attr_init(attr)) + abort(); + + if (pthread_attr_setstacksize(attr, stack_size)) + abort(); + } + + err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); + + if (attr != NULL) + pthread_attr_destroy(attr); + + return UV__ERR(err); +} + + +uv_thread_t uv_thread_self(void) { + return pthread_self(); +} + +int uv_thread_join(uv_thread_t *tid) { + return UV__ERR(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 UV__ERR(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 UV__ERR(err); +#endif +} + + +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return UV__ERR(err); +} + + +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 UV_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 UV__ERR(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 UV_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 UV_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 UV_EINVAL; + if (err == KERN_RESOURCE_SHORTAGE) + return UV_ENOMEM; + + abort(); + return UV_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 UV_EAGAIN; + + abort(); + return UV_EINVAL; /* Satisfy the compiler. */ +} + +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + int err; + union { + int val; + struct semid_ds* buf; + unsigned short* array; + } arg; + + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return UV__ERR(errno); + + arg.val = value; + if (-1 == semctl(semid, 0, SETVAL, arg)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return UV__ERR(err); + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return UV_EAGAIN; + abort(); + } + + return 0; +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + if (sem_init(sem, 0, value)) + return UV__ERR(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 UV_EAGAIN; + abort(); + } + + return 0; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) + +int uv_cond_init(uv_cond_t* cond) { + return UV__ERR(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 UV__ERR(err); + +#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) + 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 UV__ERR(err); +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + 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(__MVS__) + struct timeval tv; +#endif + +#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 +#if defined(__MVS__) + if (gettimeofday(&tv, NULL)) + abort(); + timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; +#else + timeout += uv__hrtime(UV_CLOCK_PRECISE); +#endif + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + + /* + * 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_API__ */ +#endif + + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return UV_ETIMEDOUT; + + abort(); + return UV_EINVAL; /* Satisfy the compiler. */ +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(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; +} + + +int uv_key_create(uv_key_t* key) { + return UV__ERR(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/3rd/libuv-1.19.2/src/unix/timer.c b/3rd/libuv-1.19.2/src/unix/timer.c new file mode 100644 index 00000000..54dabfe7 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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, uv_timer_t, heap_node); + b = container_of(hb, 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 UV_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 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) { + 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, 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/3rd/libuv-1.19.2/src/unix/tty.c b/3rd/libuv-1.19.2/src/unix/tty.c new file mode 100644 index 00000000..f22b3b80 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/tty.c @@ -0,0 +1,372 @@ +/* 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 +#include +#include +#include +#include +#include + +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#elif defined(__NetBSD__) + /* + * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave + * device name for both descriptors, the master one and slave one. + * + * Implement function to compare major device number with pts devices. + * + * The major numbers are machine-dependent, on NetBSD/amd64 they are + * respectively: + * - master tty: ptc - major 6 + * - slave tty: pts - major 5 + */ + + struct stat sb; + /* Lookup device's major for the pts driver and cache it. */ + static devmajor_t pts = NODEVMAJOR; + + if (pts == NODEVMAJOR) { + pts = getdevmajor("pts", S_IFCHR); + if (pts == NODEVMAJOR) + abort(); + } + + /* Lookup stat structure behind the file descriptor. */ + if (fstat(fd, &sb) != 0) + abort(); + + /* Assert character device. */ + if (!S_ISCHR(sb.st_mode)) + abort(); + + /* Assert valid major. */ + if (major(sb.st_rdev) == NODEVMAJOR) + abort(); + + result = (pts == major(sb.st_rdev)); +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} + +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; + int saved_flags; + char path[256]; + + /* 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 UV_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) { + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; + + 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 != UV_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; + } + +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return UV__ERR(errno); + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + +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 (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + +#if defined(__APPLE__) + r = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (r) { + int rc = r; + if (newfd != -1) + uv__close(newfd); + QUEUE_REMOVE(&tty->handle_queue); + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; + } +#endif + + if (readable) + flags |= UV_STREAM_READABLE; + else + flags |= UV_STREAM_WRITABLE; + + 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); + +#if defined __sun || defined __MVS__ + /* + * 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 UV__ERR(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 UV__ERR(errno); + + tty->mode = mode; + return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); + + if (err == -1) + return UV__ERR(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) || defined(__DragonFly__) + /* on AIX/DragonFly 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) || defined(__DragonFly__) */ + + 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 UV_EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = UV__ERR(errno); + + uv_spinlock_unlock(&termios_spinlock); + errno = saved_errno; + + return err; +} diff --git a/3rd/libuv-1.19.2/src/unix/udp.c b/3rd/libuv-1.19.2/src/unix/udp.c new file mode 100644 index 00000000..74d613b6 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/udp.c @@ -0,0 +1,902 @@ +/* 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 +#include +#include +#include +#include +#if defined(__MVS__) +#include +#endif + +#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, POLLIN | 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 = UV_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, POLLOUT); + if (!uv__io_active(&handle->io_watcher, 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 & POLLIN) + uv__udp_recvmsg(handle); + + if (revents & 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 { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + if (buf.base == NULL || 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, UV__ERR(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) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + break; + } + + req->status = (size == -1 ? UV__ERR(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 UV__ERR(errno); +#else + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(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 UV_EINVAL; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) + return UV_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) + return err; + } + + if (flags & UV_UDP_IPV6ONLY) { +#ifdef IPV6_V6ONLY + yes = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { + err = UV__ERR(errno); + return err; + } +#else + err = UV_ENOTSUP; + return err; +#endif + } + + if (bind(fd, addr, addrlen)) { + err = UV__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 = UV_EINVAL; + return err; + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + handle->flags |= UV_HANDLE_BOUND; + return 0; +} + + +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags) { + union { + struct sockaddr_in6 in6; + struct sockaddr_in in; + struct sockaddr addr; + } taddr; + socklen_t addrlen; + + if (handle->io_watcher.fd != -1) + return 0; + + switch (domain) { + case AF_INET: + { + struct sockaddr_in* addr = &taddr.in; + 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 = &taddr.in6; + 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, &taddr.addr, 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 UV_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); + + /* `uv__udp_sendmsg` may not be able to do non-blocking write straight + * away. In such cases the `io_watcher` has to be queued for asynchronous + * write. + */ + if (!QUEUE_EMPTY(&handle->write_queue)) + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + } else { + uv__io_start(handle->loop, &handle->io_watcher, 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 UV_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 || errno == ENOBUFS) + return UV_EAGAIN; + else + return UV__ERR(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 UV_EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return UV_ENODEV; +#endif + return UV__ERR(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 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->io_watcher.fd, + IPPROTO_IPV6, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return UV_ENODEV; +#endif + return UV__ERR(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 UV_EINVAL; + + if (flags & ~0xFF) + return UV_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 UV_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 UV_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 UV__ERR(errno); + + return 0; +} + +static int uv__setsockopt_maybe_char(uv_udp_t* handle, + int option4, + int option6, + int val) { +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + char arg = val; +#elif defined(__OpenBSD__) + unsigned char arg = val; +#else + int arg = val; +#endif + + if (val < 0 || val > 255) + return UV_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 UV__ERR(errno); + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (ttl < 1 || ttl > 255) + return UV_EINVAL; + +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + +/* + * 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__) || \ + defined(__MVS__) + + return uv__setsockopt(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ + + 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) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + 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) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + &on, + sizeof(on)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + 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 UV_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 UV__ERR(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 UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(handle->io_watcher.fd, name, &socklen)) + return UV__ERR(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 UV_EINVAL; + + if (uv__io_active(&handle->io_watcher, POLLIN)) + return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_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, POLLIN); + uv__handle_start(handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); + + if (!uv__io_active(&handle->io_watcher, POLLOUT)) + uv__handle_stop(handle); + + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/uv-common.c b/3rd/libuv-1.19.2/src/uv-common.c new file mode 100644 index 00000000..bc7d1379 --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-common.c @@ -0,0 +1,664 @@ +/* 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 +#include +#include +#include /* NULL */ +#include +#include /* malloc */ +#include /* memset */ + +#if defined(_WIN32) +# include /* malloc */ +#else +# include /* 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) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; + uv__allocator.local_free(ptr); + errno = saved_errno; +} + +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 = ""; + } + + 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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, handle->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + 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 +} + +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#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__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { + uv__dirent_t** dents; + uv__dirent_t* dent; + unsigned int* nbufs; + + /* Check to see if req passed */ + if (req->result < 0) + return req->result; + + /* Ptr will be null if req was canceled or no files found */ + if (!req->ptr) + return UV_EOF; + + nbufs = uv__get_nbufs(req); + assert(nbufs); + + dents = req->ptr; + + /* Free previous entity */ + if (*nbufs > 0) + uv__fs_scandir_free(dents[*nbufs - 1]); + + /* End was already reached */ + if (*nbufs == (unsigned int) req->result) { + uv__fs_scandir_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; +#ifndef NDEBUG + void* saved_data; +#endif + + 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 + saved_data = loop->data; + memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; +#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/3rd/libuv-1.19.2/src/uv-common.h b/3rd/libuv-1.19.2/src/uv-common.h new file mode 100644 index 00000000..d4fa22aa --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-common.h @@ -0,0 +1,260 @@ +/* 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 +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "tree.h" +#include "queue.h" + +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + +#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__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ + UV__HANDLE_INTERNAL = 0x8000, + UV__HANDLE_ACTIVE = 0x4000, + UV__HANDLE_REF = 0x2000, + UV__HANDLE_CLOSING = 0 /* no-op on unix */ +}; +#else +# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 +# define UV__SIGNAL_ONE_SHOT 0x100 +# 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) + +/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of + * a circular dependency between src/uv-common.h and src/win/internal.h. + */ +#if defined(_WIN32) +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \ + } \ + while (0) +#else +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + } \ + while (0) +#endif + +#define uv__req_init(loop, req, typ) \ + do { \ + UV_REQ_INIT(req, typ); \ + uv__req_register(loop, req); \ + } \ + 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/3rd/libuv-1.19.2/src/uv-data-getter-setters.c b/3rd/libuv-1.19.2/src/uv-data-getter-setters.c new file mode 100644 index 00000000..533e4a2f --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-data-getter-setters.c @@ -0,0 +1,96 @@ +#include "uv.h" + +const char* uv_handle_type_name(uv_handle_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + case UV_FILE: return "file"; + case UV_HANDLE_TYPE_MAX: + case UV_UNKNOWN_HANDLE: return NULL; + } + return NULL; +} + +uv_handle_type uv_handle_get_type(const uv_handle_t* handle) { + return handle->type; +} + +void* uv_handle_get_data(const uv_handle_t* handle) { + return handle->data; +} + +uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) { + return handle->loop; +} + +void uv_handle_set_data(uv_handle_t* handle, void* data) { + handle->data = data; +} + +const char* uv_req_type_name(uv_req_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_REQ_TYPE_MAP(XX) +#undef XX + case UV_REQ_TYPE_MAX: + case UV_UNKNOWN_REQ: return NULL; + } + return NULL; +} + +uv_req_type uv_req_get_type(const uv_req_t* req) { + return req->type; +} + +void* uv_req_get_data(const uv_req_t* req) { + return req->data; +} + +void uv_req_set_data(uv_req_t* req, void* data) { + req->data = data; +} + +size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) { + return stream->write_queue_size; +} + +size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) { + return handle->send_queue_size; +} + +size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) { + return handle->send_queue_count; +} + +uv_pid_t uv_process_get_pid(const uv_process_t* proc) { + return proc->pid; +} + +uv_fs_type uv_fs_get_type(const uv_fs_t* req) { + return req->fs_type; +} + +ssize_t uv_fs_get_result(const uv_fs_t* req) { + return req->result; +} + +void* uv_fs_get_ptr(const uv_fs_t* req) { + return req->ptr; +} + +const char* uv_fs_get_path(const uv_fs_t* req) { + return req->path; +} + +uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) { + return &req->statbuf; +} + +void* uv_loop_get_data(const uv_loop_t* loop) { + return loop->data; +} + +void uv_loop_set_data(uv_loop_t* loop, void* data) { + loop->data = data; +} diff --git a/3rd/libuv-1.19.2/src/version.c b/3rd/libuv-1.19.2/src/version.c new file mode 100644 index 00000000..686dedd9 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/src/win/async.c b/3rd/libuv-1.19.2/src/win/async.c new file mode 100644 index 00000000..0b636ed1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/async.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 + +#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(req, 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/3rd/libuv-1.19.2/src/win/atomicops-inl.h b/3rd/libuv-1.19.2/src/win/atomicops-inl.h new file mode 100644 index 00000000..6d8126f6 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/atomicops-inl.h @@ -0,0 +1,57 @@ +/* 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" +#include "internal.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 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/3rd/libuv-1.19.2/src/win/core.c b/3rd/libuv-1.19.2/src/win/core.c new file mode 100644 index 00000000..9ed4e824 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/core.c @@ -0,0 +1,605 @@ +/* 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 +#include +#include +#include +#include +#include +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) +#include +#endif + +#include "uv.h" +#include "internal.h" +#include "queue.h" +#include "handle-inl.h" +#include "req-inl.h" + +/* 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 uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init(void) { + uv_mutex_init(&uv__loops_lock); +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + if (uv__loops_size == 0) { + uv__loops_capacity = 0; + uv__free(uv__loops); + uv__loops = NULL; + goto loop_removed; + } + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops(void) { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} + +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 + + /* Initialize tracking of all uv loops */ + uv__loops_init(); + + /* 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(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); +} + + +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; + + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + + 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; + + uv__loops_remove(loop); + + /* 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_loop_fork(uv_loop_t* loop) { + return UV_ENOSYS; +} + + +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; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + 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 target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +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; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + 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 target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +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/3rd/libuv-1.19.2/src/win/detect-wakeup.c b/3rd/libuv-1.19.2/src/win/detect-wakeup.c new file mode 100644 index 00000000..72dfb7a1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(void); + +void uv__init_detect_system_wakeup(void) { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback(void) { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/3rd/libuv-1.19.2/src/win/dl.c b/3rd/libuv-1.19.2/src/win/dl.c new file mode 100644 index 00000000..97ac1c1a --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/dl.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 "internal.h" + +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + WCHAR filename_w[32768]; + + lib->handle = NULL; + lib->errmsg = NULL; + + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, filename, GetLastError()); + } + + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, filename, 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, const char* filename, DWORD errorno) { + DWORD_PTR arg; + DWORD res; + char* msg; + + if (lib->errmsg) { + LocalFree(lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno == 0) + return 0; + + 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 && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) { + msg = lib->errmsg; + lib->errmsg = NULL; + arg = (DWORD_PTR) filename; + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + msg, + 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); + LocalFree(msg); + } + + if (!res) + uv__format_fallback_error(lib, errorno); + + return -1; +} diff --git a/3rd/libuv-1.19.2/src/win/error.c b/3rd/libuv-1.19.2/src/win/error.c new file mode 100644 index 00000000..9b03bfef --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/error.c @@ -0,0 +1,171 @@ +/* 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 +#include +#include +#include +#include + +#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); + } + + DebugBreak(); + 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_ELEVATION_REQUIRED: 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/3rd/libuv-1.19.2/src/win/fs-event.c b/3rd/libuv-1.19.2/src/win/fs-event.c new file mode 100644 index 00000000..95f843ad --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/fs-event.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 +#include +#include +#include + +#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 void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') + dirlen--; + relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); + if (!*relpath) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; +} + +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { + size_t len, i; + + if (filename == NULL) { + if (dir != NULL) + *dir = NULL; + *file = NULL; + return 0; + } + + len = wcslen(filename); + 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 + 2) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = 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(&handle->req, 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_buffer[MAX_PATH]; + WCHAR* short_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 = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); + pathw = (WCHAR*)uv__malloc(name_size); + if (!pathw) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + 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. */ + 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. */ + short_path = short_path_buffer; + if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + short_path = NULL; + } + + 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; + } + + assert(is_path_dir ? pathw != NULL : pathw == NULL); + handle->dirw = pathw; + 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; + } + + if (uv__is_active(handle)) + uv__handle_stop(handle); + + 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; +} + + +static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) { + size_t str_len; + + if (str == NULL) + return -1; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + +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; + char* filename = NULL; + WCHAR* filenamew = NULL; + WCHAR* 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(!filenamew); + assert(!long_filenamew); + + /* + * Fire the event only if we were asked to watch a directory, + * or if the filename filter matches. + */ + if (handle->dirw || + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 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 / (DWORD)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. */ + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); + uv__free(long_filenamew); + long_filenamew = filenamew; + sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + 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. + */ + 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; + } + + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); + + 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; + 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/3rd/libuv-1.19.2/src/win/fs.c b/3rd/libuv-1.19.2/src/win/fs.c new file mode 100644 index 00000000..6e0bdc7b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/fs.c @@ -0,0 +1,2426 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" +#include "handle-inl.h" + +#include + + +#define UV_FS_FREE_PATHS 0x0002 +#define UV_FS_FREE_PTR 0x0008 +#define UV_FS_CLEANEDUP 0x0010 + + +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + uv_fs_req_init(loop, req, subtype, cb); \ + } \ + while (0) + +#define POST \ + do { \ + if (cb != NULL) { \ + uv__req_register(loop, req); \ + 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) + +#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 = ((uint64_t) ((time) * 10000000ULL)) + \ + 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; + +static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + +void uv_fs_init(void) { + _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 = 0, 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; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf)); + req->path = pos; + } + + 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__once_init(); + UV_REQ_INIT(req, 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; + req->fs.info.bufs = NULL; + memset(&req->fs, 0, sizeof(req->fs)); +} + + +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'\\')) { + /* \??\:\ */ + 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\\\ - make sure the final path looks like */ + /* \\\\ */ + 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 \??\:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{}, */ + /* 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 & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { + case UV_FS_O_RDONLY: + access = FILE_GENERIC_READ; + break; + case UV_FS_O_WRONLY: + access = FILE_GENERIC_WRITE; + break; + case UV_FS_O_RDWR: + access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & UV_FS_O_APPEND) { + access &= ~FILE_WRITE_DATA; + access |= FILE_APPEND_DATA; + } + + /* + * 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. + * We still support exclusive sharing mode, since it is necessary + * for opening raw block devices, otherwise Windows will prevent + * any attempt to write past the master boot record. + */ + if (flags & UV_FS_O_EXLOCK) { + share = 0; + } else { + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + } + + switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { + case 0: + case UV_FS_O_EXCL: + disposition = OPEN_EXISTING; + break; + case UV_FS_O_CREAT: + disposition = OPEN_ALWAYS; + break; + case UV_FS_O_CREAT | UV_FS_O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL: + disposition = CREATE_NEW; + break; + case UV_FS_O_TRUNC: + case UV_FS_O_TRUNC | UV_FS_O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case UV_FS_O_CREAT | UV_FS_O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & UV_FS_O_CREAT) { + if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & UV_FS_O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & UV_FS_O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) { + case 0: + break; + case UV_FS_O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case UV_FS_O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + if (flags & UV_FS_O_DIRECT) { + attributes |= FILE_FLAG_NO_BUFFERING; + } + + switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) { + case 0: + break; + case UV_FS_O_DSYNC: + case UV_FS_O_SYNC: + attributes |= FILE_FLAG_WRITE_THROUGH; + 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 & UV_FS_O_CREAT) && + !(flags & UV_FS_O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_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; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; + + VERIFY_FD(fd, req); + + zero_offset.QuadPart = 0; + restore_position = 0; + 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; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } + } 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 (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + + 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; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; + + VERIFY_FD(fd, req); + + zero_offset.QuadPart = 0; + restore_position = 0; + 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; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } + } 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 (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + + 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. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; + 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, + int do_lstat) { + 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; + + /* + * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism + * by which filesystem drivers can intercept and alter file system requests. + * + * The only reparse points we care about are symlinks and mount points, both + * of which are treated as POSIX symlinks. Further, we only care when + * invoked via lstat, which seeks information about the link instead of its + * target. Otherwise, reparse points must be treated as regular files. + */ + if (do_lstat && + (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + /* + * If reading the link fails, the reparse point is not a symlink and needs + * to be treated as a regular file. The higher level lstat function will + * detect this failure and retry without do_lstat if appropriate. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + return -1; + statbuf->st_mode |= S_IFLNK; + } + + if (statbuf->st_mode == 0) { + 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. + * + * 4096 is the minimum required to be compatible with newer Advanced Format + * drives (which have 4096 bytes per physical sector), and to be backwards + * compatible with older drives (which have 512 bytes per physical sector). + */ + statbuf->st_blksize = 4096; + + /* 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, do_lstat) != 0) { + DWORD error = GetLastError(); + if (do_lstat && + (error == ERROR_SYMLINK_NOT_SUPPORTED || + error == ERROR_NOT_A_REPARSE_POINT)) { + /* 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) != 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__copyfile(uv_fs_t* req) { + int flags; + int overwrite; + + flags = req->fs.info.file_flags; + overwrite = flags & UV_FS_COPYFILE_EXCL; + + if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + +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->fs.info.mode & 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(atime, &filetime_a); + TIME_T_TO_FILETIME(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; + WCHAR* new_pathw; + int flags; + int err; + + pathw = req->file.pathw; + new_pathw = req->fs.info.new_pathw; + + if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, pathw, new_pathw); + return; + } + if (!pCreateSymbolicLinkW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) + flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; + else + flags = uv__file_symlink_usermode_flag; + + if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + SET_REQ_RESULT(req, 0); + return; + } + + /* Something went wrong. We will test if it is because of user-mode + * symlinks. + */ + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER && + flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) { + /* This system does not support user-mode symlinks. We will clear the + * unsupported flag and retry. + */ + uv__file_symlink_usermode_flag = 0; + fs__symlink(req); + } else { + SET_REQ_WIN32_ERROR(req, err); + } +} + + +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 = NULL; + WCHAR* w_realpath_buf; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + w_realpath_ptr = w_realpath_buf; + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_buf); + 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_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 4; + w_realpath_len -= 4; + } else { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); + 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(COPYFILE, copyfile) + 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 == NULL) + return; + + 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) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } + + if (req->fs.info.bufs != req->fs.info.bufsml) + uv__free(req->fs.info.bufs); + + req->path = NULL; + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->fs.info.bufs = 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; + + INIT(UV_FS_OPEN); + 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; + POST; +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_CLOSE); + req->file.fd = fd; + POST; +} + + +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) { + INIT(UV_FS_READ); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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; + POST; +} + + +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) { + INIT(UV_FS_WRITE); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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; + POST; +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_UNLINK); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_MKDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + POST; +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_MKDTEMP); + err = fs__capture_path(req, tpl, NULL, TRUE); + if (err) + return uv_translate_sys_error(err); + + POST; +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_RMDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_SCANDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + POST; +} + + +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; + + INIT(UV_FS_LINK); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + 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) { + int err; + + INIT(UV_FS_SYMLINK); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + POST; +} + + +int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_READLINK); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_REALPATH); + + if (!path) { + return UV_EINVAL; + } + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + 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) { + int err; + + INIT(UV_FS_CHOWN); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +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) { + INIT(UV_FS_FCHOWN); + POST; +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_STAT); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LSTAT); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FSTAT); + req->file.fd = fd; + POST; +} + + +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; + + INIT(UV_FS_RENAME); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FSYNC); + req->file.fd = fd; + POST; +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FDATASYNC); + req->file.fd = fd; + POST; +} + + +int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, + int64_t offset, uv_fs_cb cb) { + INIT(UV_FS_FTRUNCATE); + req->file.fd = fd; + req->fs.info.offset = offset; + POST; +} + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + + err = fs__capture_path(req, path, new_path, cb != NULL); + + if (err) + return uv_translate_sys_error(err); + + req->fs.info.file_flags = flags; + POST; +} + + +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) { + INIT(UV_FS_SENDFILE); + 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; + POST; +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_ACCESS); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + + req->fs.info.mode = flags; + POST; +} + + +int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_CHMOD); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + POST; +} + + +int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, + uv_fs_cb cb) { + INIT(UV_FS_FCHMOD); + req->file.fd = fd; + req->fs.info.mode = mode; + POST; +} + + +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; + + INIT(UV_FS_UTIME); + 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; + POST; +} + + +int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, + double mtime, uv_fs_cb cb) { + INIT(UV_FS_FUTIME); + req->file.fd = fd; + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + POST; +} diff --git a/3rd/libuv-1.19.2/src/win/getaddrinfo.c b/3rd/libuv-1.19.2/src/win/getaddrinfo.c new file mode 100644 index 00000000..282d919c --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/getaddrinfo.c @@ -0,0 +1,453 @@ +/* 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 + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +/* EAI_* constants. */ +#include + +/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */ +#include + +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) + +#ifndef NDIS_IF_MAX_STRING_SIZE +#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE +#endif + +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 = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + 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 = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); + 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)) { + return UV_EINVAL; + } + + UV_REQ_INIT(req, UV_GETADDRINFO); + req->getaddrinfo_cb = getaddrinfo_cb; + req->addrinfo = NULL; + req->loop = loop; + req->retcode = 0; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); + if (nodesize == 0) { + err = GetLastError(); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + 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 (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (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 (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (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); +} + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + NET_LUID luid; + wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ + DWORD bufsize; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = ConvertInterfaceIndexToLuid(ifindex, &luid); + + if (r != 0) + return uv_translate_sys_error(r); + + r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); + + if (r != 0) + return uv_translate_sys_error(r); + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + wname, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = snprintf(buffer, *size, "%d", ifindex); + + if (r < 0) + return uv_translate_sys_error(r); + + if (r >= (int) *size) { + *size = r + 1; + return UV_ENOBUFS; + } + + *size = r; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/win/getnameinfo.c b/3rd/libuv-1.19.2/src/win/getnameinfo.c new file mode 100644 index 00000000..9f10cd2a --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/getnameinfo.c @@ -0,0 +1,149 @@ +/* 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 +#include + +#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(req, UV_GETNAMEINFO); + uv__req_register(loop, req); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + 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/3rd/libuv-1.19.2/src/win/handle-inl.h b/3rd/libuv-1.19.2/src/win/handle-inl.h new file mode 100644 index 00000000..8d0334cc --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/src/win/handle.c b/3rd/libuv-1.19.2/src/win/handle.c new file mode 100644 index 00000000..39150702 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/handle.c @@ -0,0 +1,159 @@ +/* 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 +#include +#include + +#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)); +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return uv__get_osfhandle(fd); +} diff --git a/3rd/libuv-1.19.2/src/win/internal.h b/3rd/libuv-1.19.2/src/win/internal.h new file mode 100644 index 00000000..217fcdb5 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/internal.h @@ -0,0 +1,394 @@ +/* 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 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 + +/* 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(void); + +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_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(void); + + +/* + * 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(void); +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(void); + + +/* + * 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(void); + +uint64_t uv__hrtime(double scale); +int uv_current_pid(void); +__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); +int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); + + +/* + * 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(void); + + +/* + * Winsock utility functions + */ +void uv_winsock_init(void); + +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_; + +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(void); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(void); + +#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/loop-watcher.c b/3rd/libuv-1.19.2/src/win/loop-watcher.c new file mode 100644 index 00000000..20e4509f --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/src/win/pipe.c b/3rd/libuv-1.19.2/src/win/pipe.c new file mode 100644 index 00000000..1a7c4dc1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/pipe.c @@ -0,0 +1,2214 @@ +/* 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 +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +#include +#include + +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-%lu", 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(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_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 | WRITE_DAC, + 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, ¤t_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(req, UV_ACCEPT); + req->data = handle; + req->pipeHandle = INVALID_HANDLE_VALUE; + req->next_pending = NULL; + } + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + 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 | WRITE_DAC, + 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(req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + 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 | WRITE_DAC, + 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, FALSE, DUPLICATE_SAME_ACCESS)) { + handle->pipe.conn.readfile_thread = hThread; + } else { + hThread = NULL; + } + uv_mutex_unlock(m); + } +restart_readfile: + if (handle->flags & UV_HANDLE_READING) { + 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 */ + } + } + } + } else { + result = 1; /* successfully aborted read before it even started */ + } + 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(req, 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(ipc_header_req, 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_OPERATION_ABORTED) { + /* do nothing (equivalent to EINTR) */ + } + else 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); + } + } + + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, avail, &buf); + if (buf.base == NULL || 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; + + uv__once_init(); + /* 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_os_getppid(); + 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; + + uv__once_init(); + 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 + 1; + 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; + buffer[addrlen] = '\0'; + + err = 0; + +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; +} + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + EXPLICIT_ACCESS ea; + PSID everyone; + int error; + + if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (!AllocateAndInitializeSid(&sid_world, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &everyone)) { + error = GetLastError(); + goto done; + } + + if (GetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &old_dacl, + NULL, + &sd)) { + error = GetLastError(); + goto clean_sid; + } + + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); + if (mode & UV_READABLE) + ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + if (mode & UV_WRITABLE) + ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + ea.grfAccessPermissions |= SYNCHRONIZE; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPTSTR)everyone; + + if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { + error = GetLastError(); + goto clean_sd; + } + + if (SetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + new_dacl, + NULL)) { + error = GetLastError(); + goto clean_dacl; + } + + error = 0; + +clean_dacl: + LocalFree((HLOCAL) new_dacl); +clean_sd: + LocalFree((HLOCAL) sd); +clean_sid: + FreeSid(everyone); +done: + return uv_translate_sys_error(error); +} diff --git a/3rd/libuv-1.19.2/src/win/poll.c b/3rd/libuv-1.19.2/src/win/poll.c new file mode 100644 index 00000000..a648ba71 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/poll.c @@ -0,0 +1,644 @@ +/* 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 +#include + +#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(void) { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) { + 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 { + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ + 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; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } + } + 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_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } + } + 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 | UV_DISCONNECT)) == 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(&handle->poll_req_1, UV_POLL_REQ); + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + UV_REQ_INIT(&handle->poll_req_2, 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/3rd/libuv-1.19.2/src/win/process-stdio.c b/3rd/libuv-1.19.2/src/win/process-stdio.c new file mode 100644 index 00000000..032e3093 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/process-stdio.c @@ -0,0 +1,511 @@ +/* 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 +#include +#include +#include + +#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; + break; + + 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/3rd/libuv-1.19.2/src/win/process.c b/3rd/libuv-1.19.2/src/win/process.c new file mode 100644 index 00000000..75235222 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/process.c @@ -0,0 +1,1272 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include /* 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(&handle->exit_req, 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; + + /* If path is quoted, find quote end */ + if (*dir_start == L'"' || *dir_start == L'\'') { + dir_end = wcschr(dir_start + 1, *dir_start); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + } + /* Slice until the next ; or \0 is found */ + dir_end = wcschr(dir_end, 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); + + process_flags = CREATE_UNICODE_ENVIRONMENT; + + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Avoid creating console window if stdio is not inherited. */ + for (i = 0; i < options->stdio_count; i++) { + if (options->stdio[i].flags & UV_INHERIT_FD) + break; + if (i == options->stdio_count - 1) + process_flags |= CREATE_NO_WINDOW; + } + + /* Use SW_HIDE to avoid any potential process window. */ + startup.wShowWindow = SW_HIDE; + } else { + startup.wShowWindow = SW_SHOWDEFAULT; + } + + 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) { + if (signum < 0 || signum >= NSIG) { + return UV_EINVAL; + } + + 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; + + if (pid == 0) { + process_handle = GetCurrentProcess(); + } else { + 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/3rd/libuv-1.19.2/src/win/req-inl.h b/3rd/libuv-1.19.2/src/win/req-inl.h new file mode 100644 index 00000000..f2513b7d --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/req-inl.h @@ -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. + */ + +#ifndef UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include + +#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))) + +/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency + * between src/uv-common.h and src/win/internal.h. + */ +#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 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/3rd/libuv-1.19.2/src/win/req.c b/3rd/libuv-1.19.2/src/win/req.c new file mode 100644 index 00000000..111cc5e2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#include "uv.h" +#include "internal.h" diff --git a/3rd/libuv-1.19.2/src/win/signal.c b/3rd/libuv-1.19.2/src/win/signal.c new file mode 100644 index 00000000..a174da1f --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/signal.c @@ -0,0 +1,277 @@ +/* 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 +#include + +#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 CRITICAL_SECTION uv__signal_lock; + +static BOOL WINAPI uv__signal_control_handler(DWORD type); + +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); + +void uv_signals_init(void) { + InitializeCriticalSection(&uv__signal_lock); + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + abort(); +} + + +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; + + 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 (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) + continue; + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + if (handle->flags & UV__SIGNAL_ONE_SHOT) + handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; + } + + 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; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ); + handle->signal_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); + + 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) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { + /* Test for invalid signal values. */ + if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) + 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); + + handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + + 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__SIGNAL_ONE_SHOT) + uv_signal_stop(handle); + + 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/3rd/libuv-1.19.2/src/win/snprintf.c b/3rd/libuv-1.19.2/src/win/snprintf.c new file mode 100644 index 00000000..776c0e39 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/src/win/stream-inl.h b/3rd/libuv-1.19.2/src/win/stream-inl.h new file mode 100644 index 00000000..dba03747 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/stream-inl.h @@ -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. + */ + +#ifndef UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include + +#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; + handle->stream.conn.shutdown_req = NULL; +} + + +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->read_req, UV_READ); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.data = handle; +} + + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/stream.c b/3rd/libuv-1.19.2/src/win/stream.c new file mode 100644 index 00000000..13cbfdcb --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/stream.c @@ -0,0 +1,248 @@ +/* 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 + +#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(req, 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/3rd/libuv-1.19.2/src/win/tcp.c b/3rd/libuv-1.19.2/src/win/tcp.c new file mode 100644 index 00000000..fd6efbaf --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/tcp.c @@ -0,0 +1,1525 @@ +/* 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 +#include + +#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->tcp.conn.read_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); + if (handle->tcp.conn.read_buffer.base == NULL || + 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) { + 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(req, 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(req, 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; + struct sockaddr_storage converted; + BOOL success; + DWORD bytes; + int err; + + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return 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(req, 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, + (const struct sockaddr*) &converted, + 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(req, 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) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || 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; + struct sockaddr_storage saddr; + int saddr_len; + + /* 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); + } + + /* Support already active socket. */ + saddr_len = sizeof(saddr); + if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already bound. */ + handle->flags |= UV_HANDLE_BOUND; + saddr_len = sizeof(saddr); + if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already connected. */ + uv_connection_init((uv_stream_t*) handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + } + + 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/3rd/libuv-1.19.2/src/win/thread.c b/3rd/libuv-1.19.2/src/win/thread.c new file mode 100644 index 00000000..9eaad77c --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/thread.c @@ -0,0 +1,703 @@ +/* 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 +#include +#include + +#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; + MemoryBarrier(); /* For feature parity with pthread_join(). */ + 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; +} + + +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + return uv_mutex_init(mutex); +} + + +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 here since Win32 manual-reset events */ + /* maintain state when used with . This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to being */ + /* called or 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 . */ + 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 . */ + 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/3rd/libuv-1.19.2/src/win/timer.c b/3rd/libuv-1.19.2/src/win/timer.c new file mode 100644 index 00000000..7e006fed --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/timer.c @@ -0,0 +1,195 @@ +/* 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 +#include + +#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); + assert(new_time >= loop->time); + loop->time = new_time; +} + + +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/3rd/libuv-1.19.2/src/win/tty.c b/3rd/libuv-1.19.2/src/win/tty.c new file mode 100644 index 00000000..05a11e88 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/tty.c @@ -0,0 +1,2328 @@ +/* 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 +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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" + +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif + +#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 +#define MAX_CONSOLE_CHAR 8192 + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); + + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + + +/* + * 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; + +/* The console window size + * We keep this separate from uv_tty_virtual_*. We use those values to only + * handle signalling SIGWINCH + */ + +static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static int uv__tty_console_height = -1; +static int uv__tty_console_width = -1; + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime); + +/* We use a semaphore rather than a mutex or critical section because in some + cases (uv__cancel_read_console) we need take the lock in the main thread and + release it in another thread. Using a semaphore ensures that in such + scenario the main thread will still block when trying to acquire the lock. */ +static uv_sem_t uv_tty_output_lock; + +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; + +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); + +void uv_console_init(void) { + if (uv_sem_init(&uv_tty_output_lock, 1)) + abort(); + uv__tty_console_handle = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle != NULL) { + QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, + NULL, + WT_EXECUTELONGFUNCTION); + } +} + + +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; + + uv__once_init(); + 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. */ + uv_sem_wait(&uv_tty_output_lock); + + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + + /* Remember the original console text attributes. */ + uv_tty_capture_initial_style(&screen_buffer_info); + + uv_tty_update_virtual_window(&screen_buffer_info); + + uv_sem_post(&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; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = 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; + default: + return UV_EINVAL; + } + + /* 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; + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); + } + } else { + was_reading = 0; + } + + uv_sem_wait(&uv_tty_output_lock); + if (!SetConsoleMode(tty->handle, flags)) { + err = uv_translate_sys_error(GetLastError()); + uv_sem_post(&uv_tty_output_lock); + return err; + } + uv_sem_post(&uv_tty_output_lock); + + /* 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()); + } + + uv_sem_wait(&uv_tty_output_lock); + uv_tty_update_virtual_window(&info); + uv_sem_post(&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; + LONG status; + COORD pos; + BOOL read_console_success; + + 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; + + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + read_console_success = ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL); + + if (read_console_success) { + 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()); + } + + status = InterlockedExchange(&uv__read_console_status, COMPLETED); + + if (status == TRAP_REQUESTED) { + /* If we canceled the read by sending a VK_RETURN event, restore the + screen state to undo the visual effect of the VK_RETURN */ + if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer; + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by one + line. The right position to reset the cursor to is therefore one line + higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + uv_sem_post(&uv_tty_output_lock); + } + 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->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); + if (handle->tty.rd.read_line_buffer.base == NULL || + 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); + + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; + 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); + } + + 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--; + + /* Ignore other events that are not key 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) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); + if (buf.base == NULL || 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) { + /* 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 { + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* 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); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &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); + /* Make sure no attempt is made to insert it again until it's handled. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + return 0; + } + + uv_tty_queue_read(loop, handle); + + return 0; +} + + +int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ + /* Write some bullshit event to force the console wait to return. */ + memset(&record, 0, sizeof record); + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { + return GetLastError(); + } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + /* Hold the output lock during the cancellation, to ensure that further + writes don't interfere with the screen state. It will be the ReadConsole + thread's responsibility to release the lock. */ + uv_sem_wait(&uv_tty_output_lock); + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + uv_sem_post(&uv_tty_output_lock); + return 0; + } + + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); + } + + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); + + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; +} + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { + 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; + } +} + + +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[MAX_CONSOLE_CHAR]; + WCHAR* utf16_buffer; + DWORD utf16_buf_used = 0; + unsigned int i, len, max_len, pos; + int allocate = 0; + +#define FLUSH_TEXT() \ + do { \ + pos = 0; \ + do { \ + len = utf16_buf_used - pos; \ + if (len > MAX_CONSOLE_CHAR) \ + len = MAX_CONSOLE_CHAR; \ + uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \ + pos += len; \ + } while (pos < utf16_buf_used); \ + if (allocate) { \ + uv__free(utf16_buffer); \ + allocate = 0; \ + utf16_buffer = utf16_buf; \ + } \ + 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; + + utf16_buffer = utf16_buf; + + uv_sem_wait(&uv_tty_output_lock); + + for (i = 0; i < nbufs; i++) { + uv_buf_t buf = bufs[i]; + unsigned int j; + + if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + max_len = (utf16_buf_used + 1) * sizeof(WCHAR); + allocate = max_len > MAX_CONSOLE_CHAR; + if (allocate) + utf16_buffer = uv__malloc(max_len); + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buffer, + utf16_buf_used)) { + if (allocate) + uv__free(utf16_buffer); + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + + continue; + } + + 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; + + uv_sem_post(&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(req, 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 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; +} + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + MSG msg; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return 0; + + uv__tty_console_width = sb_info.dwSize.X; + uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (pSetWinEventHook == NULL) + return 0; + + if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, + EVENT_CONSOLE_LAYOUT, + NULL, + uv__tty_console_resize_event, + 0, + 0, + WINEVENT_OUTOFCONTEXT)) + return 0; + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + int width, height; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return; + + width = sb_info.dwSize.X; + height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (width != uv__tty_console_width || height != uv__tty_console_height) { + uv__tty_console_width = width; + uv__tty_console_height = height; + uv__signal_dispatch(SIGWINCH); + } +} diff --git a/3rd/libuv-1.19.2/src/win/udp.c b/3rd/libuv-1.19.2/src/win/udp.c new file mode 100644 index 00000000..cd1d0e07 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/udp.c @@ -0,0 +1,965 @@ +/* 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 +#include + +#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(&handle->recv_req, 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->recv_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + if (handle->recv_buffer.base == NULL || 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(req, 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? */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || 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 + return UV_EINVAL; + 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) { + DWORD bytes; + const struct sockaddr* bind_addr; + struct sockaddr_storage converted; + int err; + + assert(nbufs > 0); + + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return err; + + /* Already sending a message.*/ + if (handle->send_queue_count != 0) + return UV_EAGAIN; + + 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 + return UV_EINVAL; + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + (const struct sockaddr*) &converted, + addrlen, + NULL, + NULL); + + if (err) + return uv_translate_sys_error(WSAGetLastError()); + + return bytes; +} diff --git a/3rd/libuv-1.19.2/src/win/util.c b/3rd/libuv-1.19.2/src/win/util.c new file mode 100644 index 00000000..3100bc23 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/util.c @@ -0,0 +1,1581 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include + + +/* + * 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 + +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif + +/* + Max hostname length. The Windows gethostname() documentation states that 256 + bytes will always be large enough to hold the null-terminated hostname. +*/ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +/* Maximum environment variable size, including the terminating null */ +#define MAX_ENV_VAR_LENGTH 32767 + +/* 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(void) { + 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_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, + (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; + 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; +} + + +uv_pid_t uv_os_getpid(void) { + return GetCurrentProcessId(); +} + + +uv_pid_t uv_os_getppid(void) { + 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(void) { + 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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(void) { + WCHAR title_w[MAX_TITLE_LENGTH]; + + if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { + return -1; + } + + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) + return -1; + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + 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); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + 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; + + uv__convert_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + &(cpu_info->model)); + } + + 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; + PROCESS_MEMORY_COUNTERS memCounters; + IO_COUNTERS ioCounters; + 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()); + } + + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + 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; + + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + + uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + + return 0; +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + 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 { + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; + } + + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + 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 (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + *utf8 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf8)[bufsize] = '\0'; + return 0; +} + + +/* + * Converts a UTF-8 string into a UTF-16 one. The resulting string is + * null-terminated. + * + * If utf8 is null terminated, utf8len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { + int bufsize; + + if (utf8 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so + * we do it ourselves always, just in case. */ + *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1)); + + if (*utf16 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-16 */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); + + if (bufsize == 0) { + uv__free(*utf16); + *utf16 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf16)[bufsize] = '\0'; + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = ARRAY_SIZE(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = ARRAY_SIZE(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + wchar_t var[MAX_ENV_VAR_LENGTH]; + wchar_t* name_w; + DWORD bufsize; + size_t len; + int r; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); + uv__free(name_w); + assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ + + if (len == 0) { + r = GetLastError(); + + if (r == ERROR_ENVVAR_NOT_FOUND) + return UV_ENOENT; + + return uv_translate_sys_error(r); + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + var, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + wchar_t* name_w; + wchar_t* value_w; + int r; + + if (name == NULL || value == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = uv__convert_utf8_to_utf16(value, -1, &value_w); + + if (r != 0) { + uv__free(name_w); + return r; + } + + r = SetEnvironmentVariableW(name_w, value_w); + uv__free(name_w); + uv__free(value_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + wchar_t* name_w; + int r; + + if (name == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = SetEnvironmentVariableW(name_w, NULL); + uv__free(name_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + +int uv_os_gethostname(char* buffer, size_t* size) { + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + uv__once_init(); /* Initialize winsock */ + + if (gethostname(buf, sizeof(buf)) != 0) + return uv_translate_sys_error(WSAGetLastError()); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/win/winapi.c b/3rd/libuv-1.19.2/src/win/winapi.c new file mode 100644 index 00000000..4ccdf0a5 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winapi.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 + +#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; + + +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +/* User32.dll function pointer */ +sSetWinEventHook pSetWinEventHook; + + +void uv_winapi_init(void) { + HMODULE ntdll_module; + HMODULE kernel32_module; + HMODULE powrprof_module; + HMODULE user32_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"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + + user32_module = LoadLibraryA("user32.dll"); + if (user32_module != NULL) { + pSetWinEventHook = (sSetWinEventHook) + GetProcAddress(user32_module, "SetWinEventHook"); + } + +} diff --git a/3rd/libuv-1.19.2/src/win/winapi.h b/3rd/libuv-1.19.2/src/win/winapi.h new file mode 100644 index 00000000..cc54b79b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winapi.h @@ -0,0 +1,4778 @@ +/* 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 + + +/* + * 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 + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002 +#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; + }; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + 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_ELEVATION_REQUIRED +# define ERROR_ELEVATION_REQUIRED 740 +#endif + +#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); + +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + +/* from Winuser.h */ +typedef VOID (CALLBACK* WINEVENTPROC) + (HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD idEventThread, + DWORD dwmsEventTime); + +typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) + (UINT eventMin, + UINT eventMax, + HMODULE hmodWinEventProc, + WINEVENTPROC lpfnWinEventProc, + DWORD idProcess, + DWORD idThread, + UINT 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; + + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +/* User32.dll function pointer */ +extern sSetWinEventHook pSetWinEventHook; + +#endif /* UV_WIN_WINAPI_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/winsock.c b/3rd/libuv-1.19.2/src/win/winsock.c new file mode 100644 index 00000000..84188954 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winsock.c @@ -0,0 +1,591 @@ +/* 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 +#include + +#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(void) { + 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; + } +} + +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage) { + struct sockaddr_in* dest4; + struct sockaddr_in6* dest6; + + if (addr == NULL) + return UV_EINVAL; + + switch (addr->sa_family) { + case AF_INET: + dest4 = (struct sockaddr_in*) storage; + memcpy(dest4, addr, sizeof(*dest4)); + if (dest4->sin_addr.s_addr == 0) + dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return 0; + case AF_INET6: + dest6 = (struct sockaddr_in6*) storage; + memcpy(dest6, addr, sizeof(*dest6)); + if (memcmp(&dest6->sin6_addr, + &uv_addr_ip6_any_.sin6_addr, + sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) { + struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT; + dest6->sin6_addr = init_sin6_addr; + } + return 0; + default: + return UV_EINVAL; + } +} diff --git a/3rd/libuv-1.19.2/src/win/winsock.h b/3rd/libuv-1.19.2/src/win/winsock.h new file mode 100644 index 00000000..7ecb755b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winsock.h @@ -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. + */ + +#ifndef UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include +#include + +#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 + +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage); + +#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/3rd/libuv-1.19.2/test/benchmark-async-pummel.c b/3rd/libuv-1.19.2/test/benchmark-async-pummel.c new file mode 100644 index 00000000..cca3de10 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-async.c b/3rd/libuv-1.19.2/test/benchmark-async.c new file mode 100644 index 00000000..e44165f2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-fs-stat.c b/3rd/libuv-1.19.2/test/benchmark-fs-stat.c new file mode 100644 index 00000000..32d25895 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c b/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c new file mode 100644 index 00000000..1dbc23dd --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/benchmark-list.h b/3rd/libuv-1.19.2/test/benchmark-list.h new file mode 100644 index 00000000..1e843071 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-loop-count.c b/3rd/libuv-1.19.2/test/benchmark-loop-count.c new file mode 100644 index 00000000..970a94c2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-million-async.c b/3rd/libuv-1.19.2/test/benchmark-million-async.c new file mode 100644 index 00000000..5395ed54 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-million-timers.c b/3rd/libuv-1.19.2/test/benchmark-million-timers.c new file mode 100644 index 00000000..60a308be --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-multi-accept.c b/3rd/libuv-1.19.2/test/benchmark-multi-accept.c new file mode 100644 index 00000000..2f32c0ca --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c b/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c new file mode 100644 index 00000000..646a7df9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/test/benchmark-pound.c b/3rd/libuv-1.19.2/test/benchmark-pound.c new file mode 100644 index 00000000..79f36345 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-pump.c b/3rd/libuv-1.19.2/test/benchmark-pump.c new file mode 100644 index 00000000..8685258e --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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(void); + +static uv_req_t* req_alloc(void); +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/3rd/libuv-1.19.2/test/benchmark-sizes.c b/3rd/libuv-1.19.2/test/benchmark-sizes.c new file mode 100644 index 00000000..9bf42f91 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-spawn.c b/3rd/libuv-1.19.2/test/benchmark-spawn.c new file mode 100644 index 00000000..ed9ad608 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c b/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c new file mode 100644 index 00000000..96921b70 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-thread.c b/3rd/libuv-1.19.2/test/benchmark-thread.c new file mode 100644 index 00000000..b37a7fd6 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c b/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c new file mode 100644 index 00000000..68a2373d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/blackhole-server.c b/3rd/libuv-1.19.2/test/blackhole-server.c new file mode 100644 index 00000000..ad878b35 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/dns-server.c b/3rd/libuv-1.19.2/test/dns-server.c new file mode 100644 index 00000000..80052c70 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/echo-server.c b/3rd/libuv-1.19.2/test/echo-server.c new file mode 100644 index 00000000..bfed6767 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/fixtures/empty_file b/3rd/libuv-1.19.2/test/fixtures/empty_file new file mode 100644 index 00000000..e69de29b diff --git a/3rd/libuv-1.19.2/test/fixtures/load_error.node b/3rd/libuv-1.19.2/test/fixtures/load_error.node new file mode 100644 index 00000000..323fae03 --- /dev/null +++ b/3rd/libuv-1.19.2/test/fixtures/load_error.node @@ -0,0 +1 @@ +foobar diff --git a/3rd/libuv-1.19.2/test/run-benchmarks.c b/3rd/libuv-1.19.2/test/run-benchmarks.c new file mode 100644 index 00000000..6e42623d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/run-tests.c b/3rd/libuv-1.19.2/test/run-tests.c new file mode 100644 index 00000000..da4ac82e --- /dev/null +++ b/3rd/libuv-1.19.2/test/run-tests.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 +#include +#include + +#ifdef _WIN32 +# include +#else +# include +#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_helper_closed_handle(void); +int ipc_send_recv_helper(void); +int ipc_helper_bind_twice(void); +int stdio_over_pipes_helper(void); +int spawn_stdin_stdout(void); +int spawn_tcp_server_helper(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]); + case 4: return maybe_run_test(argc, argv); + 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_closed_handle") == 0) { + return ipc_helper_closed_handle(); + } + + 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_tcp_server_helper") == 0) { + return spawn_tcp_server_helper(); + } + + 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(); + } + +#ifndef _WIN32 + if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) { + uv_uid_t uid = atoi(argv[2]); + uv_gid_t gid = atoi(argv[3]); + + ASSERT(uid == getuid()); + ASSERT(gid == getgid()); + + return 1; + } +#endif /* !_WIN32 */ + + return run_test(argv[1], 0, 1); +} diff --git a/3rd/libuv-1.19.2/test/runner-unix.c b/3rd/libuv-1.19.2/test/runner-unix.c new file mode 100644 index 00000000..3167ed44 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* uintptr_t */ + +#include +#include /* readlink, usleep */ +#include /* strdup */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* Do platform-specific initialization. */ +int platform_init(int argc, char **argv) { + /* 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; + int stdout_fd; + const char* arg; + char* args[16]; + int n; + pid_t pid; + + stdout_file = tmpfile(); + stdout_fd = fileno(stdout_file); + 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(stdout_fd, STDOUT_FILENO); + dup2(stdout_fd, 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 defined(__MVS__) + if (pthread_attr_setstacksize(&attr, 1024 * 1024)) +#else + if (pthread_attr_setstacksize(&attr, 256 * 1024)) +#endif + 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, FILE* stream) { + 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) + print_lines(buf, strlen(buf), stream); + + 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) { +#if defined(__MVS__) + fprintf(stderr, "\047[2K\r"); +#else + fprintf(stderr, "\033[2K\r"); +#endif +} + + +/* Pause the calling thread for a number of milliseconds. */ +void uv_sleep(int msec) { + int sec; + int usec; + + sec = msec / 1000; + usec = (msec % 1000) * 1000; + if (sec > 0) + sleep(sec); + if (usec > 0) + usleep(usec); +} diff --git a/3rd/libuv-1.19.2/test/runner-unix.h b/3rd/libuv-1.19.2/test/runner-unix.h new file mode 100644 index 00000000..e21847f9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* 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/3rd/libuv-1.19.2/test/runner-win.c b/3rd/libuv-1.19.2/test/runner-win.c new file mode 100644 index 00000000..d86fda3c --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner-win.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 +#include +#include +#include +#include +#if !defined(__MINGW32__) +# include +#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) { + /* 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, FILE* stream) { + char buf[1024]; + int fd, r; + FILE* f; + + fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); + if (fd == -1) + return -1; + f = _fdopen(fd, "rt"); + if (f == NULL) { + _close(fd); + return -1; + } + + r = fseek(f, 0, SEEK_SET); + if (r < 0) + return -1; + + while (fgets(buf, sizeof(buf), f) != NULL) + print_lines(buf, strlen(buf), stream); + + if (ferror(f)) + return -1; + + fclose(f); + 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); +} + + +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/3rd/libuv-1.19.2/test/runner-win.h b/3rd/libuv-1.19.2/test/runner-win.h new file mode 100644 index 00000000..8cc4c16e --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/runner.c b/3rd/libuv-1.19.2/test/runner.c new file mode 100644 index 00000000..f017902a --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner.c @@ -0,0 +1,434 @@ +/* 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 +#include + +#include "runner.h" +#include "task.h" +#include "uv.h" + +char executable_path[sizeof(executable_path)]; + + +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); +} + + +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 ""; + + 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 actual; + int total; + int passed; + int failed; + int skipped; + int current; + int test_result; + int skip; + task_entry_t* task; + + /* Count the number of tests. */ + actual = 0; + total = 0; + for (task = TASKS; task->main; task++, actual++) { + if (!task->is_helper) { + total++; + } + } + + /* Keep platform_output first. */ + skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output")); + qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task); + + fprintf(stderr, "1..%d\n", total); + fflush(stderr); + + /* Run all tests. */ + passed = 0; + failed = 0; + skipped = 0; + current = 1; + for (task = TASKS; task->main; task++) { + if (task->is_helper) { + continue; + } + + test_result = run_test(task->task_name, benchmark_output, current); + switch (test_result) { + case TEST_OK: passed++; break; + case TEST_SKIP: skipped++; break; + default: failed++; + } + current++; + } + + 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]; + int reason_length; + + switch (status) { + case TEST_OK: + result = "ok"; + directive = ""; + break; + case TEST_SKIP: + result = "ok"; + directive = " # SKIP "; + break; + default: + result = "not ok"; + directive = ""; + } + + if (status == TEST_SKIP && process_output_size(process) > 0) { + process_read_last_line(process, reason, sizeof reason); + reason_length = strlen(reason); + if (reason_length > 0 && reason[reason_length - 1] == '\n') + reason[reason_length - 1] = '\0'; + } 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] = ""; + 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"); + } + + log_tap_result(test_count, test, status, &processes[i]); + + /* Show error and output from processes if the test failed. */ + if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { + if (strlen(errmsg) > 0) + fprintf(stderr, "# %s\n", errmsg); + fprintf(stderr, "# "); + 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], stderr); + break; + } + } + + /* 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], 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 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); + } + } +} + + +void print_lines(const char* buffer, size_t size, FILE* stream) { + const char* start; + const char* end; + + start = buffer; + while ((end = memchr(start, '\n', &buffer[size] - start))) { + fprintf(stream, "# %.*s\n", (int) (end - start), start); + fflush(stream); + start = end + 1; + } + + if (start < &buffer[size]) { + fprintf(stream, "# %s\n", start); + fflush(stream); + } +} diff --git a/3rd/libuv-1.19.2/test/runner.h b/3rd/libuv-1.19.2/test/runner.h new file mode 100644 index 00000000..555f2f8e --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner.h @@ -0,0 +1,177 @@ +/* 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 /* PATH_MAX */ +#include /* 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); + +/* Print lines in |buffer| as TAP diagnostics to |stream|. */ +void print_lines(const char* buffer, size_t size, FILE* stream); + +/* + * Stuff that should be implemented by test-runner-.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 `stream`. */ +int process_copy_output(process_info_t* p, FILE* stream); + +/* 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); + +#endif /* RUNNER_H_ */ diff --git a/3rd/libuv-1.19.2/test/task.h b/3rd/libuv-1.19.2/test/task.h new file mode 100644 index 00000000..af99d92f --- /dev/null +++ b/3rd/libuv-1.19.2/test/task.h @@ -0,0 +1,232 @@ +/* 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 +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if !defined(_WIN32) +# include +# include /* 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 +# 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()); \ + ASSERT(0 == uv_loop_close(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_SKIP +}; + +#define RETURN_OK() \ + do { \ + return TEST_OK; \ + } 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 0; /* Assume no 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; +} + +#if defined(__CYGWIN__) || defined(__MSYS__) +# define NO_FS_EVENTS "Filesystem watching not supported on this platform." +#endif + +#if defined(__MSYS__) +# define NO_SEND_HANDLE_ON_PIPE \ + "MSYS2 runtime does not support sending handles on pipes." +#elif defined(__CYGWIN__) +# define NO_SEND_HANDLE_ON_PIPE \ + "Cygwin runtime does not support sending handles on pipes." +#endif + +#if defined(__MSYS__) +# define NO_SELF_CONNECT \ + "MSYS2 runtime hangs on listen+connect in same process." +#elif defined(__CYGWIN__) +# define NO_SELF_CONNECT \ + "Cygwin runtime hangs on listen+connect in same process." +#endif + +#endif /* TASK_H_ */ diff --git a/3rd/libuv-1.19.2/test/test-active.c b/3rd/libuv-1.19.2/test/test-active.c new file mode 100644 index 00000000..b17bd176 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-async-null-cb.c b/3rd/libuv-1.19.2/test/test-async-null-cb.c new file mode 100644 index 00000000..52652d91 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-async-null-cb.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 + +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) { + /* + * Fill async_handle with garbage values. + * uv_async_init() should properly initialize struct fields regardless of + * initial values. + * This is added to verify paddings between fields do not affect behavior. + */ + memset(&async_handle, 0xff, sizeof(async_handle)); + + 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/3rd/libuv-1.19.2/test/test-async.c b/3rd/libuv-1.19.2/test/test-async.c new file mode 100644 index 00000000..6f5351bf --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-barrier.c b/3rd/libuv-1.19.2/test/test-barrier.c new file mode 100644 index 00000000..dfd2dbde --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-callback-order.c b/3rd/libuv-1.19.2/test/test-callback-order.c new file mode 100644 index 00000000..8bc2c4f7 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-callback-stack.c b/3rd/libuv-1.19.2/test/test-callback-stack.c new file mode 100644 index 00000000..8855c084 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-close-fd.c b/3rd/libuv-1.19.2/test/test-close-fd.c new file mode 100644 index 00000000..93a7bd7c --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-close-order.c b/3rd/libuv-1.19.2/test/test-close-order.c new file mode 100644 index 00000000..2b24f6d6 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-condvar.c b/3rd/libuv-1.19.2/test/test-condvar.c new file mode 100644 index 00000000..d956efef --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-condvar.c @@ -0,0 +1,245 @@ +/* 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 +#include + +typedef struct worker_config { + uv_mutex_t mutex; + uv_cond_t cond; + int signal_delay; + int wait_delay; + int use_broadcast; + volatile int posted_1; + volatile int posted_2; + void (*signal_cond)(struct worker_config* c, volatile int* flag); + int (*wait_cond)(struct worker_config* c, const volatile int* flag); +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + c->signal_cond(c, &c->posted_1); + c->wait_cond(c, &c->posted_2); +} + +static void noop_worker(void* arg) { + return; +} + +static void condvar_signal(worker_config* c, volatile int* flag) { + if (c->signal_delay) + uv_sleep(c->signal_delay); + + uv_mutex_lock(&c->mutex); + ASSERT(*flag == 0); + *flag = 1; + if (c->use_broadcast) + uv_cond_broadcast(&c->cond); + else + uv_cond_signal(&c->cond); + uv_mutex_unlock(&c->mutex); +} + + +static int condvar_wait(worker_config* c, const volatile int* flag) { + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + uv_cond_wait(&c->cond, &c->mutex); + } + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); + + return 0; +} + + +TEST_IMPL(condvar_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.wait_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + 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.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +static int condvar_timedwait(worker_config* c, const volatile int* flag) { + int r; + + r = 0; + + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0 || r == UV_ETIMEDOUT); + if (r == UV_ETIMEDOUT) + break; + } + uv_mutex_unlock(&c->mutex); + + return r; +} + +/* Test that uv_cond_timedwait will return early when cond is signaled. */ +TEST_IMPL(condvar_3) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + 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; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); + + 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; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + +/* Test that uv_cond_timedwait will time out when cond is not signaled. */ +TEST_IMPL(condvar_6) { + uv_thread_t thread; + worker_config wc; + int r; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, noop_worker, &wc)); + + /* This can only return having timed out, because otherwise we + * loop forever in condvar_timedwait. */ + r = wc.wait_cond(&wc, &wc.posted_1); + ASSERT(r == UV_ETIMEDOUT); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-connect-unspecified.c b/3rd/libuv-1.19.2/test/test-connect-unspecified.c new file mode 100644 index 00000000..04e1c8a5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-connect-unspecified.c @@ -0,0 +1,61 @@ +/* Copyright 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. +*/ + +#include "uv.h" +#include "task.h" + +static void connect_4(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +static void connect_6(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +TEST_IMPL(connect_unspecified) { + uv_loop_t* loop; + uv_tcp_t socket4; + struct sockaddr_in addr4; + uv_connect_t connect4; + uv_tcp_t socket6; + struct sockaddr_in6 addr6; + uv_connect_t connect6; + + loop = uv_default_loop(); + + ASSERT(uv_tcp_init(loop, &socket4) == 0); + ASSERT(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4) == 0); + ASSERT(uv_tcp_connect(&connect4, + &socket4, + (const struct sockaddr*) &addr4, + connect_4) == 0); + + ASSERT(uv_tcp_init(loop, &socket6) == 0); + ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); + ASSERT(uv_tcp_connect(&connect6, + &socket6, + (const struct sockaddr*) &addr6, + connect_6) == 0); + + ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-connection-fail.c b/3rd/libuv-1.19.2/test/test-connection-fail.c new file mode 100644 index 00000000..328bff46 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c b/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c new file mode 100644 index 00000000..1e95043c --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/test-default-loop-close.c b/3rd/libuv-1.19.2/test/test-default-loop-close.c new file mode 100644 index 00000000..fd11cfa8 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-delayed-accept.c b/3rd/libuv-1.19.2/test/test-delayed-accept.c new file mode 100644 index 00000000..4a799890 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-dlerror.c b/3rd/libuv-1.19.2/test/test-dlerror.c new file mode 100644 index 00000000..8f7697b5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-dlerror.c @@ -0,0 +1,57 @@ +/* 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 + + +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, path) != 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, path) != NULL); + ASSERT(strstr(msg, dlerror_no_error) == NULL); + + uv_dlclose(&lib); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-eintr-handling.c b/3rd/libuv-1.19.2/test/test-eintr-handling.c new file mode 100644 index 00000000..1aaf623b --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-eintr-handling.c @@ -0,0 +1,94 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 + +TEST_IMPL(eintr_handling) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + iov = uv_buf_init(buf, sizeof(buf)); + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); + + ASSERT(nread == sizeof(test_buf)); + ASSERT(0 == strcmp(buf, test_buf)); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-embed.c b/3rd/libuv-1.19.2/test/test-embed.c new file mode 100644 index 00000000..c6ddceb1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-embed.c @@ -0,0 +1,139 @@ +/* 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 +#include +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + 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 +# include +# include +#endif + +#if defined(HAVE_EPOLL) +# include +#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/3rd/libuv-1.19.2/test/test-emfile.c b/3rd/libuv-1.19.2/test/test-emfile.c new file mode 100644 index 00000000..8e44ac5c --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-emfile.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. + */ + +#if !defined(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +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) { +#if defined(_AIX) || defined(__MVS__) + /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket + * which causes uv__emfile_trick to not work as intended and this test + * to fail. + */ + RETURN_SKIP("uv__emfile_trick does not work on this OS"); +#endif + 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/3rd/libuv-1.19.2/test/test-env-vars.c b/3rd/libuv-1.19.2/test/test-env-vars.c new file mode 100644 index 00000000..641050e6 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-env-vars.c @@ -0,0 +1,90 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define BUF_SIZE 10 + +TEST_IMPL(env_vars) { + const char* name = "UV_TEST_FOO"; + char buf[BUF_SIZE]; + size_t size; + int r; + + /* Reject invalid inputs when setting an environment variable */ + r = uv_os_setenv(NULL, "foo"); + ASSERT(r == UV_EINVAL); + r = uv_os_setenv(name, NULL); + ASSERT(r == UV_EINVAL); + r = uv_os_setenv(NULL, NULL); + ASSERT(r == UV_EINVAL); + + /* Reject invalid inputs when retrieving an environment variable */ + size = BUF_SIZE; + r = uv_os_getenv(NULL, buf, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_getenv(name, NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_getenv(name, buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_EINVAL); + + /* Reject invalid inputs when deleting an environment variable */ + r = uv_os_unsetenv(NULL); + ASSERT(r == UV_EINVAL); + + /* Successfully set an environment variable */ + r = uv_os_setenv(name, "123456789"); + ASSERT(r == 0); + + /* Successfully read an environment variable */ + size = BUF_SIZE; + buf[0] = '\0'; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == 0); + ASSERT(strcmp(buf, "123456789") == 0); + ASSERT(size == BUF_SIZE - 1); + + /* Return UV_ENOBUFS if the buffer cannot hold the environment variable */ + size = BUF_SIZE - 1; + buf[0] = '\0'; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_ENOBUFS); + ASSERT(size == BUF_SIZE); + + /* Successfully delete an environment variable */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + /* Return UV_ENOENT retrieving an environment variable that does not exist */ + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_ENOENT); + + /* Successfully delete an environment variable that does not exist */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-error.c b/3rd/libuv-1.19.2/test/test-error.c new file mode 100644 index 00000000..a2d559a4 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-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" +#if defined(_WIN32) +# include "../src/win/winapi.h" +#endif + +#include +#include +#include + + +/* + * 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; +} + + +TEST_IMPL(sys_error) { +#if defined(_WIN32) + ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); + ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); + ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); +#else + ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM); + ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE); + ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL); +#endif + ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL); + ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE); + ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES); + ASSERT(uv_translate_sys_error(0) == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fail-always.c b/3rd/libuv-1.19.2/test/test-fail-always.c new file mode 100644 index 00000000..0008459e --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-fork.c b/3rd/libuv-1.19.2/test/test-fork.c new file mode 100644 index 00000000..39b59c8f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fork.c @@ -0,0 +1,681 @@ +/* Copyright 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. + */ + +/* These tests are Unix only. */ +#ifndef _WIN32 + +#include +#include +#include +#include + +#include "uv.h" +#include "task.h" + +static int timer_cb_called; +static int socket_cb_called; + +static void timer_cb(uv_timer_t* timer) { + timer_cb_called++; + uv_close((uv_handle_t*) timer, NULL); +} + + +static int socket_cb_read_fd; +static int socket_cb_read_size; +static char socket_cb_read_buf[1024]; + + +static void socket_cb(uv_poll_t* poll, int status, int events) { + ssize_t cnt; + socket_cb_called++; + ASSERT(0 == status); + printf("Socket cb got events %d\n", events); + ASSERT(UV_READABLE == (events & UV_READABLE)); + if (socket_cb_read_fd) { + cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size); + ASSERT(cnt == socket_cb_read_size); + } + uv_close((uv_handle_t*) poll, NULL); +} + + +static void run_timer_loop_once(void) { + uv_loop_t* loop; + uv_timer_t timer_handle; + + loop = uv_default_loop(); + + timer_cb_called = 0; /* Reset for the child. */ + + 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); +} + + +static void assert_wait_child(pid_t child_pid) { + pid_t waited_pid; + int child_stat; + + waited_pid = waitpid(child_pid, &child_stat, 0); + printf("Waited pid is %d with status %d\n", waited_pid, child_stat); + if (waited_pid == -1) { + perror("Failed to wait"); + } + ASSERT(child_pid == waited_pid); + ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ + ASSERT(!WIFSIGNALED(child_stat)); + ASSERT(0 == WEXITSTATUS(child_stat)); +} + + +TEST_IMPL(fork_timer) { + /* Timers continue to work after we fork. */ + + /* + * Establish the loop before we fork to make sure that it + * has state to get reset after the fork. + */ + pid_t child_pid; + + run_timer_loop_once(); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + run_timer_loop_once(); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair) { + /* A socket opened in the parent and accept'd in the + child works after a fork. */ + pid_t child_pid; + int socket_fds[2]; + uv_poll_t poll_handle; + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + + /* Create the server watcher in the parent, use it in the child. */ + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(0 == socket_cb_called); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + printf("Going to run the loop in the child\n"); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == socket_cb_called); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair_started) { + /* A socket opened in the parent and accept'd in the + child works after a fork, even if the watcher was already + started, and then stopped in the parent. */ + pid_t child_pid; + int socket_fds[2]; + int sync_pipe[2]; + char sync_buf[1]; + uv_poll_t poll_handle; + + ASSERT(0 == pipe(sync_pipe)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + + /* Create and start the server watcher in the parent, use it in the child. */ + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + + /* Run the loop AFTER the poll watcher is registered to make sure it + gets passed to the kernel. Use NOWAIT and expect a non-zero + return to prove the poll watcher is active. + */ + ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(0 == uv_poll_stop(&poll_handle)); + uv_close((uv_handle_t*)&poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == socket_cb_called); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */ + ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == socket_cb_called); + + assert_wait_child(child_pid); + } else { + /* child */ + printf("Child is %d\n", getpid()); + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(0 == socket_cb_called); + + printf("Going to run the loop in the child\n"); + socket_cb_read_fd = socket_fds[0]; + socket_cb_read_size = 3; + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == socket_cb_called); + printf("Buf %s\n", socket_cb_read_buf); + ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static int fork_signal_cb_called; + +void fork_signal_to_child_cb(uv_signal_t* handle, int signum) +{ + fork_signal_cb_called = signum; + uv_close((uv_handle_t*)handle, NULL); +} + + +TEST_IMPL(fork_signal_to_child) { + /* A signal handler installed before forking + is run only in the child when the child is signalled. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == pipe(sync_pipe)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + ASSERT(0 == kill(child_pid, SIGUSR1)); + /* Run the loop, make sure we don't get the signal. */ + printf("Running loop in parent\n"); + uv_unref((uv_handle_t*)&signal_handle); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT(0 == fork_signal_cb_called); + printf("Waiting for child in parent\n"); + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + /* Get the signal. */ + ASSERT(0 != uv_loop_alive(uv_default_loop())); + printf("Running loop in child\n"); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT(SIGUSR1 == fork_signal_cb_called); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_signal_to_child_closed) { + /* A signal handler installed before forking + doesn't get received anywhere when the child is signalled, + but isnt running the loop. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + int sync_pipe2[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == pipe(sync_pipe)); + ASSERT(0 == pipe(sync_pipe2)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + printf("Wating on child in parent\n"); + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + printf("Parent killing child\n"); + ASSERT(0 == kill(child_pid, SIGUSR1)); + /* Run the loop, make sure we don't get the signal. */ + printf("Running loop in parent\n"); + uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit; + we *shouldn't* get any signals */ + run_timer_loop_once(); /* but while we share a pipe, we do, so + have something active. */ + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + printf("Signal in parent %d\n", fork_signal_cb_called); + ASSERT(0 == fork_signal_cb_called); + ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */ + printf("Waiting for child in parent\n"); + assert_wait_child(child_pid); + } else { + /* child */ + /* Our signal handler should still be installed. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + printf("Checking loop in child\n"); + ASSERT(0 != uv_loop_alive(uv_default_loop())); + printf("Alerting parent in child\n"); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + /* Don't run the loop. Wait for the parent to call us */ + printf("Waiting on parent in child\n"); + /* Wait for parent. read may fail if the parent tripped an ASSERT + and exited, so this isn't in an ASSERT. + */ + read(sync_pipe2[0], sync_buf, 1); + ASSERT(0 == fork_signal_cb_called); + printf("Exiting child \n"); + /* Note that we're deliberately not running the loop + * in the child, and also not closing the loop's handles, + * so the child default loop can't be cleanly closed. + * We need to explicitly exit to avoid an automatic failure + * in that case. + */ + exit(0); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +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 int timer_cb_touch_called; + +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 int fs_event_cb_called; + +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(status == 0); +#if defined(__APPLE__) || defined(__linux__) + ASSERT(strcmp(filename, "watch_file") == 0); +#else + ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); +#endif + uv_close((uv_handle_t*)handle, NULL); +} + + +static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) { + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + + /* Setup */ + remove("watch_file"); + create_file("watch_file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + /* watching a dir is the only way to get fsevents involved on apple + platforms */ + r = uv_fs_event_start(&fs_event, + fs_event_cb_file_current_dir, + file_or_dir == 1 ? "." : "watch_file", + 0); + ASSERT(r == 0); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */ +} + + +#define FS_TEST_FILE 0 +#define FS_TEST_DIR 1 + +static int _do_fork_fs_events_child(int file_or_dir) { + /* basic fsevents work in the child after a fork */ + pid_t child_pid; + uv_loop_t loop; + + /* Watch in the parent, prime the loop and/or threads. */ + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + /* Ee can watch in a new loop, but dirs only work + if we're on linux. */ +#if defined(__APPLE__) + file_or_dir = FS_TEST_FILE; +#endif + printf("Running child\n"); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_watch_file_current_dir(&loop, file_or_dir); + ASSERT(0 == uv_loop_close(&loop)); + printf("Child second watch default loop\n"); + /* Ee can watch in the default loop. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + /* On some platforms (OS X), if we don't update the time now, + * the timer cb fires before the event loop enters uv__io_poll, + * instead of after, meaning we don't see the change! This may be + * a general race. + */ + uv_update_time(uv_default_loop()); + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + + /* We can close the parent loop successfully too. This is + especially important on Apple platforms where if we're not + careful trying to touch the CFRunLoop, even just to shut it + down, that we allocated in the FS_TEST_DIR case would crash. */ + ASSERT(0 == uv_loop_close(uv_default_loop())); + + printf("Exiting child \n"); + } + + MAKE_VALGRIND_HAPPY(); + return 0; + +} + + +TEST_IMPL(fork_fs_events_child) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + return _do_fork_fs_events_child(FS_TEST_FILE); +} + + +TEST_IMPL(fork_fs_events_child_dir) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__APPLE__) || defined (__linux__) + return _do_fork_fs_events_child(FS_TEST_DIR); +#else + /* You can't spin up a cfrunloop thread on an apple platform + and then fork. See + http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale + */ + return 0; +#endif +} + + +TEST_IMPL(fork_fs_events_file_parent_child) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + /* It's not possible to implement this without additional + * bookkeeping on SunOS. For AIX it is possible, but has to be + * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 + * TODO: On z/OS, we need to open another message queue and subscribe to the + * same events as the parent. + */ + return 0; +#else + /* Establishing a started fs events watcher in the parent should + still work in the child. */ + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + pid_t child_pid; + uv_loop_t* loop; + + 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); + + child_pid = fork(); + ASSERT(child_pid != -1); + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + printf("Running child\n"); + ASSERT(0 == uv_loop_fork(loop)); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + printf("Running loop in child \n"); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */ + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + + +static int work_cb_count; +static int after_work_cb_count; + + +static void work_cb(uv_work_t* req) { + work_cb_count++; +} + + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT(status == 0); + after_work_cb_count++; +} + + +static void assert_run_work(uv_loop_t* const loop) { + uv_work_t work_req; + int r; + + ASSERT(work_cb_count == 0); + ASSERT(after_work_cb_count == 0); + printf("Queue in %d\n", getpid()); + r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); + ASSERT(r == 0); + printf("Running in %d\n", getpid()); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(work_cb_count == 1); + ASSERT(after_work_cb_count == 1); + + /* cleanup */ + work_cb_count = 0; + after_work_cb_count = 0; +} + + +#ifndef __MVS__ +TEST_IMPL(fork_threadpool_queue_work_simple) { + /* The threadpool works in a child process. */ + + pid_t child_pid; + uv_loop_t loop; + + /* Prime the pool and default loop. */ + assert_run_work(uv_default_loop()); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + /* We can still run work. */ + assert_run_work(uv_default_loop()); + assert_wait_child(child_pid); + } else { + /* child */ + /* We can work in a new loop. */ + printf("Running child in %d\n", getpid()); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_run_work(&loop); + uv_loop_close(&loop); + printf("Child second watch default loop\n"); + /* We can work in the default loop. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + assert_run_work(uv_default_loop()); + printf("Exiting child \n"); + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* !__MVS__ */ + + +#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-fs-copyfile.c b/3rd/libuv-1.19.2/test/test-fs-copyfile.c new file mode 100644 index 00000000..4b1fdc5e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-copyfile.c @@ -0,0 +1,173 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" + +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#include /* unlink, etc. */ +#else +# include +# include +# define unlink _unlink +#endif + +static const char fixture[] = "test/fixtures/load_error.node"; +static const char dst[] = "test_file_dst"; +static int result_check_count; + + +static void fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} + +static void handle_result(uv_fs_t* req) { + uv_fs_t stat_req; + uint64_t size; + uint64_t mode; + int r; + + ASSERT(req->fs_type == UV_FS_COPYFILE); + ASSERT(req->result == 0); + + /* Verify that the file size and mode are the same. */ + r = uv_fs_stat(NULL, &stat_req, req->path, NULL); + ASSERT(r == 0); + size = stat_req.statbuf.st_size; + mode = stat_req.statbuf.st_mode; + uv_fs_req_cleanup(&stat_req); + r = uv_fs_stat(NULL, &stat_req, dst, NULL); + ASSERT(r == 0); + ASSERT(stat_req.statbuf.st_size == size); + ASSERT(stat_req.statbuf.st_mode == mode); + uv_fs_req_cleanup(&stat_req); + uv_fs_req_cleanup(req); + result_check_count++; +} + + +static void touch_file(const char* name, unsigned int size) { + uv_file file; + uv_fs_t req; + uv_buf_t buf; + int r; + unsigned int i; + + r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, + S_IWUSR | S_IRUSR, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r >= 0); + file = r; + + buf = uv_buf_init("a", 1); + + /* Inefficient but simple. */ + for (i = 0; i < size; i++) { + r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r >= 0); + } + + r = uv_fs_close(NULL, &req, file, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r == 0); +} + + +TEST_IMPL(fs_copyfile) { + const char src[] = "test_file_src"; + uv_loop_t* loop; + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + /* Fails with EINVAL if bad flags are passed. */ + r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&req); + + /* Fails with ENOENT if source does not exist. */ + unlink(src); + unlink(dst); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(req.result == UV_ENOENT); + ASSERT(r == UV_ENOENT); + uv_fs_req_cleanup(&req); + /* The destination should not exist. */ + r = uv_fs_stat(NULL, &req, dst, NULL); + ASSERT(r != 0); + uv_fs_req_cleanup(&req); + + /* Copies file synchronously. Creates new file. */ + unlink(dst); + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies a file of size zero. */ + unlink(dst); + touch_file(src, 0); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies file synchronously. Overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Fails to overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); + ASSERT(r == UV_EEXIST); + uv_fs_req_cleanup(&req); + + /* Truncates when an existing destination is larger than the source file. */ + touch_file(src, 1); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies a larger file. */ + unlink(dst); + touch_file(src, 4096 * 2); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + unlink(src); + + /* Copies file asynchronously */ + unlink(dst); + r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); + ASSERT(r == 0); + ASSERT(result_check_count == 5); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 6); + + /* If the flags are invalid, the loop should not be kept open */ + unlink(dst); + r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + unlink(dst); /* Cleanup */ + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fs-event.c b/3rd/libuv-1.19.2/test/test-fs-event.c new file mode 100644 index 00000000..39d73300 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-event.c @@ -0,0 +1,1051 @@ +/* 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 +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_KQUEUE 1 +# endif +#endif + +#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */ +# define CREATE_TIMEOUT 100 +#else +# define CREATE_TIMEOUT 1 +#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 int timer_cb_exact_called; + +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 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, + CREATE_TIMEOUT, + 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 || events == 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) { +#ifdef _WIN32 + /* Each file created (or deleted) will cause this callback to be called twice + * under Windows: once with the name of the file, and second time with the + * name of the directory. We will ignore the callback for the directory + * itself. */ + if (filename && strcmp(filename, file_prefix_in_subdir) == 0) + return; +#endif + fs_event_cb_called++; + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_CHANGE || events == 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_exact(uv_timer_t* handle) { + int r; + + if (timer_cb_exact_called == 0) { + touch_file("watch_dir/file.js"); + } else { + uv_close((uv_handle_t*)handle, NULL); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, NULL); + } + + ++timer_cb_exact_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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); +#endif + + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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_exact_path) { + /* + This test watches a file named "file.jsx" and modifies a file named + "file.js". The test verifies that no events occur for file.jsx. + */ + +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + create_dir("watch_dir"); + create_file("watch_dir/file.js"); + create_file("watch_dir/file.jsx"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_exact, 100, 100); + ASSERT(r == 0); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_cb_exact_called == 2); + + /* Cleanup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_watch_file_twice) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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, 100, 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; +} + +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_file_root_dir) { + uv_loop_t* loop; + int r; + + const char* sys_drive = getenv("SystemDrive"); + char path[] = "\\\\?\\X:\\bootsect.bak"; + + ASSERT(sys_drive != NULL); + strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fail_cb, path, 0); + if (r == UV_ENOENT) + RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &fs_event, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + +TEST_IMPL(fs_event_no_callback_after_close) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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; +} + +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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); +#endif + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + fs_event_unlink_files(NULL); + 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_close, "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); + + uv_close((uv_handle_t*)&timer, close_cb); + + uv_run(loop, UV_RUN_ONCE); + + ASSERT(close_cb_called == 2); + ASSERT(fs_event_cb_called == 3); + + /* Clean up */ + fs_event_unlink_files(NULL); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_start_and_close) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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(buf[len] == '\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__) */ + +TEST_IMPL(fs_event_watch_invalid_path) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0); + ASSERT(r != 0); + ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fs-poll.c b/3rd/libuv-1.19.2/test/test-fs-poll.c new file mode 100644 index 00000000..737d50df --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-poll.c @@ -0,0 +1,187 @@ +/* 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 + +#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(buf[len] == '\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/3rd/libuv-1.19.2/test/test-fs.c b/3rd/libuv-1.19.2/test/test-fs.c new file mode 100644 index 00000000..3318b866 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs.c @@ -0,0 +1,3174 @@ +/* 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 +#include /* memset */ +#include +#include + +/* FIXME we shouldn't need to branch in this file */ +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#include /* unlink, rmdir, etc. */ +#else +# include +# include +# include +# ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +# endif +# 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; + +#ifdef _WIN32 +/* + * This tag and guid have no special meaning, and don't conflict with + * reserved ids. +*/ +static unsigned REPARSE_TAG = 0x9913; +static GUID REPARSE_GUID = { + 0x1bf6205f, 0x46ae, 0x4527, + 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }; +#endif + +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; +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) + /* + * 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); +#if defined(_WIN32) || defined(__MSYS__) + /* 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 +# if defined(__CYGWIN__) + /* On Cygwin, uid 0 is invalid (no root). */ + ASSERT(req->result == UV_EINVAL); +# else + ASSERT(req->result == UV_EPERM); +# endif +#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 fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} + +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 non_existent_scandir_cb(uv_fs_t* req) { + uv_dirent_t dent; + + ASSERT(req == &scandir_req); + ASSERT(req->fs_type == UV_FS_SCANDIR); + ASSERT(req->result == UV_ENOENT); + ASSERT(req->ptr == NULL); + ASSERT(UV_ENOENT == 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; +#elif defined(__MSYS__) + /* MSYS2's approximation of symlinks with copies does not work for broken + links. */ + if (r == UV_ENOENT) + 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 + (s->st_atim.tv_nsec / 1000000000.0) == atime); + ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == 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(__ANDROID__) + ASSERT(s->st_atim.tv_sec == t.st_atime); + ASSERT(s->st_atim.tv_nsec == t.st_atimensec); + ASSERT(s->st_mtim.tv_sec == t.st_mtime); + ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec); + ASSERT(s->st_ctim.tv_sec == t.st_ctime); + ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec); +#elif defined(__sun) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + 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(__FreeBSD__) || \ + 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); + +#ifndef __MVS__ + /* chown to root (fail) */ + chown_cb_count = 0; + r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chown_cb_count == 1); +#endif + + /* 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); + +#if defined(__MSYS__) + RETURN_SKIP("symlink reading is not supported on MSYS2"); +#endif + + 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; +} + + +int test_symlink_dir_impl(int type) { + 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", type, NULL); + if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("this version of Windows doesn't support unprivileged " + "creation of directory symlinks"); + } + 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); +#if defined(__MSYS__) + RETURN_SKIP("symlink reading is not supported on MSYS2"); +#endif + 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_symlink_dir) { + return test_symlink_dir_impl(UV_FS_SYMLINK_DIR); +} + +TEST_IMPL(fs_symlink_junction) { + return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION); +} + +#ifdef _WIN32 +TEST_IMPL(fs_non_symlink_reparse_point) { + uv_fs_t req; + int r; + HANDLE file_handle; + REPARSE_GUID_DATA_BUFFER reparse_buffer; + DWORD bytes_returned; + uv_dirent_t dent; + + /* set-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + + file_handle = CreateFile("test_dir/test_file", + GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + ASSERT(file_handle != INVALID_HANDLE_VALUE); + + memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); + reparse_buffer.ReparseTag = REPARSE_TAG; + reparse_buffer.ReparseDataLength = 0; + reparse_buffer.ReparseGuid = REPARSE_GUID; + + r = DeviceIoControl(file_handle, + FSCTL_SET_REPARSE_POINT, + &reparse_buffer, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, + NULL, + 0, + &bytes_returned, + NULL); + ASSERT(r != 0); + + CloseHandle(file_handle); + + r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED); + uv_fs_req_cleanup(&req); + +/* + Placeholder tests for exercising the behavior fixed in issue #995. + To run, update the path with the IP address of a Mac with the hard drive + shared via SMB as "Macintosh HD". + + r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + +/* + uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse + points when a minifilter driver is registered which intercepts + associated filesystem requests. Installing a driver is beyond + the scope of this test. + + r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + + r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); + ASSERT(r == 1); + ASSERT(scandir_req.result == 1); + ASSERT(scandir_req.ptr); + while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { + ASSERT(strcmp(dent.name, "test_file") == 0); + /* uv_fs_scandir incorrectly identifies non-symlink reparse points + as links because it doesn't open the file and verify the reparse + point tag. The PowerShell Get-ChildItem command shares this + behavior, so it's reasonable to leave it as is. */ + ASSERT(dent.type == UV_DIRENT_LINK); + } + uv_fs_req_cleanup(&scandir_req); + ASSERT(!scandir_req.ptr); + + /* clean-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +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 */ + + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + + 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; + + 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) { +#if defined(_AIX) && !defined(_AIX71) + RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); +#else + 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 */ + + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + + 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); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(r == UV_ENOSYS); + RETURN_SKIP("futime not supported on Cygwin"); +#else + ASSERT(r == 0); + ASSERT(req.result == 0); +#endif + 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; +#endif +} + + +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_non_existent_dir) { + const char* path; + uv_fs_t req; + uv_dirent_t dent; + int r; + + path = "./non_existent_dir/"; + loop = uv_default_loop(); + + uv_fs_rmdir(NULL, &req, path, 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 == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + ASSERT(req.ptr == NULL); + ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent)); + uv_fs_req_cleanup(&req); + + r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_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_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) { +#if defined(__CYGWIN__) || defined(__MSYS__) + RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!"); +#endif + 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((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); + + 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, &read_req, 0, NULL, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL); + /* Validate some memory management on failed input validation before sending + fs work to the thread pool. */ + ASSERT(r == UV_EINVAL); + ASSERT(write_req.path == NULL); + ASSERT(write_req.ptr == NULL); +#ifdef _WIN32 + ASSERT(write_req.file.pathw == NULL); + ASSERT(write_req.fs.info.new_pathw == NULL); + ASSERT(write_req.fs.info.bufs == NULL); +#else + ASSERT(write_req.new_path == NULL); + ASSERT(write_req.bufs == NULL); +#endif + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&write_req); + + /* If the arguments are invalid, the loop should not be kept open */ + loop = uv_default_loop(); + + r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&write_req); + + return 0; +} + + +TEST_IMPL(get_osfhandle_valid_handle) { + int r; + uv_os_fd_t fd; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + 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); + + fd = uv_get_osfhandle(open_req1.result); +#ifdef _WIN32 + ASSERT(fd != INVALID_HANDLE_VALUE); +#else + ASSERT(fd >= 0); +#endif + + 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_file_pos_after_op_with_offset) { + int r; + + /* Setup. */ + unlink("test_file"); + loop = uv_default_loop(); + + r = uv_fs_open(loop, + &open_req1, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r > 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, 0, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(strcmp(buf, test_buf) == 0); + ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_null_req) { + /* Verify that all fs functions return UV_EINVAL when the request is NULL. */ + int r; + + r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_close(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + 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); + + r = uv_fs_unlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rmdir(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_link(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_readlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_realpath(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_stat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_lstat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fstat(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fsync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fdatasync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_access(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + /* This should be a no-op. */ + uv_fs_req_cleanup(NULL); + + return 0; +} + +#ifdef _WIN32 +TEST_IMPL(fs_exclusive_sharing_mode) { + int r; + + /* Setup. */ + unlink("test_file"); + + ASSERT(UV_FS_O_EXLOCK > 0); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r < 0); + ASSERT(open_req2.result < 0); + uv_fs_req_cleanup(&open_req2); + + 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_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req2.result >= 0); + uv_fs_req_cleanup(&open_req2); + + r = uv_fs_close(NULL, &close_req, open_req2.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; +} +#endif diff --git a/3rd/libuv-1.19.2/test/test-get-currentexe.c b/3rd/libuv-1.19.2/test/test-get-currentexe.c new file mode 100644 index 00000000..0e9d6965 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/test-get-loadavg.c b/3rd/libuv-1.19.2/test/test-get-loadavg.c new file mode 100644 index 00000000..4762e475 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-get-memory.c b/3rd/libuv-1.19.2/test/test-get-memory.c new file mode 100644 index 00000000..2396939b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-get-passwd.c b/3rd/libuv-1.19.2/test/test-get-passwd.c new file mode 100644 index 00000000..8e16fb83 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-get-passwd.c @@ -0,0 +1,86 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +TEST_IMPL(get_passwd) { + uv_passwd_t pwd; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + len = strlen(pwd.username); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.shell == NULL); +#else + len = strlen(pwd.shell); + ASSERT(len > 0); +#endif + + len = strlen(pwd.homedir); + ASSERT(len > 0); + +#ifdef _WIN32 + if (len == 3 && pwd.homedir[1] == ':') + ASSERT(pwd.homedir[2] == '\\'); + else + ASSERT(pwd.homedir[len - 1] != '\\'); +#else + if (len == 1) + ASSERT(pwd.homedir[0] == '/'); + else + ASSERT(pwd.homedir[len - 1] != '/'); +#endif + +#ifdef _WIN32 + ASSERT(pwd.uid == -1); + ASSERT(pwd.gid == -1); +#else + ASSERT(pwd.uid >= 0); + ASSERT(pwd.gid >= 0); +#endif + + /* Test uv_os_free_passwd() */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test a double free */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test invalid input */ + r = uv_os_get_passwd(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-getaddrinfo.c b/3rd/libuv-1.19.2/test/test-getaddrinfo.c new file mode 100644 index 00000000..03dc1269 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-getaddrinfo.c @@ -0,0 +1,191 @@ +/* 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 + +#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; + + ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), + &req, + (uv_getaddrinfo_cb) abort, + NULL, + NULL, + NULL)); + + /* 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/3rd/libuv-1.19.2/test/test-gethostname.c b/3rd/libuv-1.19.2/test/test-gethostname.c new file mode 100644 index 00000000..5229804b --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-gethostname.c @@ -0,0 +1,62 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +TEST_IMPL(gethostname) { + char buf[MAXHOSTNAMELEN + 1]; + size_t size; + size_t enobufs_size; + int r; + + /* Reject invalid inputs */ + size = 1; + r = uv_os_gethostname(NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_gethostname(buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_gethostname(buf, &size); + ASSERT(r == UV_EINVAL); + + /* Return UV_ENOBUFS if the buffer cannot hold the hostname */ + enobufs_size = 1; + buf[0] = '\0'; + r = uv_os_gethostname(buf, &enobufs_size); + ASSERT(r == UV_ENOBUFS); + ASSERT(buf[0] == '\0'); + ASSERT(enobufs_size > 1); + + /* Successfully get the hostname */ + size = MAXHOSTNAMELEN + 1; + r = uv_os_gethostname(buf, &size); + ASSERT(r == 0); + ASSERT(size > 1 && size == strlen(buf)); + ASSERT(size + 1 == enobufs_size); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-getnameinfo.c b/3rd/libuv-1.19.2/test/test-getnameinfo.c new file mode 100644 index 00000000..b1391616 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/test-getsockname.c b/3rd/libuv-1.19.2/test/test-getsockname.c new file mode 100644 index 00000000..565c17fe --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-getters-setters.c b/3rd/libuv-1.19.2/test/test-getters-setters.c new file mode 100644 index 00000000..60a1b926 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-getters-setters.c @@ -0,0 +1,88 @@ +#include "uv.h" +#include "task.h" +#include +#include + +int cookie1; +int cookie2; +int cookie3; + + +TEST_IMPL(handle_type_name) { + ASSERT(strcmp(uv_handle_type_name(UV_NAMED_PIPE), "pipe") == 0); + ASSERT(strcmp(uv_handle_type_name(UV_UDP), "udp") == 0); + ASSERT(strcmp(uv_handle_type_name(UV_FILE), "file") == 0); + ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX) == NULL); + ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX + 1) == NULL); + ASSERT(uv_handle_type_name(UV_UNKNOWN_HANDLE) == NULL); + return 0; +} + + +TEST_IMPL(req_type_name) { + ASSERT(strcmp(uv_req_type_name(UV_REQ), "req") == 0); + ASSERT(strcmp(uv_req_type_name(UV_UDP_SEND), "udp_send") == 0); + ASSERT(strcmp(uv_req_type_name(UV_WORK), "work") == 0); + ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX) == NULL); + ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX + 1) == NULL); + ASSERT(uv_req_type_name(UV_UNKNOWN_REQ) == NULL); + return 0; +} + + +TEST_IMPL(getters_setters) { + uv_loop_t* loop; + uv_pipe_t* pipe; + uv_fs_t* fs; + int r; + + loop = malloc(uv_loop_size()); + ASSERT(loop != NULL); + r = uv_loop_init(loop); + ASSERT(r == 0); + + uv_loop_set_data(loop, &cookie1); + ASSERT(loop->data == &cookie1); + ASSERT(uv_loop_get_data(loop) == &cookie1); + + pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); + r = uv_pipe_init(loop, pipe, 0); + ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); + + ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); + pipe->data = &cookie2; + ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie2); + uv_handle_set_data((uv_handle_t*)pipe, &cookie1); + ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie1); + ASSERT(pipe->data == &cookie1); + + ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 0); + pipe->write_queue_size++; + ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 1); + pipe->write_queue_size--; + uv_close((uv_handle_t*)pipe, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + fs = malloc(uv_req_size(UV_FS)); + uv_fs_stat(loop, fs, ".", NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(uv_fs_get_type(fs) == UV_FS_STAT); + ASSERT(uv_fs_get_result(fs) == 0); + ASSERT(uv_fs_get_ptr(fs) == uv_fs_get_statbuf(fs)); + ASSERT(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); + ASSERT(strcmp(uv_fs_get_path(fs), ".") == 0); + uv_fs_req_cleanup(fs); + + r = uv_loop_close(loop); + ASSERT(r == 0); + + free(pipe); + free(fs); + free(loop); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-handle-fileno.c b/3rd/libuv-1.19.2/test/test-handle-fileno.c new file mode 100644 index 00000000..3fe933ad --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-homedir.c b/3rd/libuv-1.19.2/test/test-homedir.c new file mode 100644 index 00000000..856534a4 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-homedir.c @@ -0,0 +1,72 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(homedir) { + char homedir[PATHMAX]; + size_t len; + 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'); + +#ifdef _WIN32 + if (len == 3 && homedir[1] == ':') + ASSERT(homedir[2] == '\\'); + else + ASSERT(homedir[len - 1] != '\\'); +#else + if (len == 1) + ASSERT(homedir[0] == '/'); + else + ASSERT(homedir[len - 1] != '/'); +#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/3rd/libuv-1.19.2/test/test-hrtime.c b/3rd/libuv-1.19.2/test/test-hrtime.c new file mode 100644 index 00000000..72a4d4b1 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-idle.c b/3rd/libuv-1.19.2/test/test-idle.c new file mode 100644 index 00000000..f49d1964 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-ip4-addr.c b/3rd/libuv-1.19.2/test/test-ip4-addr.c new file mode 100644 index 00000000..3d6e0cf2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-ip6-addr.c b/3rd/libuv-1.19.2/test/test-ip6-addr.c new file mode 100644 index 00000000..25570dca --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ip6-addr.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 +#include + +#ifdef __linux__ +# include +# include +#endif + + +TEST_IMPL(ip6_addr_link_local) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + 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]; + size_t scoped_addr_len; + char interface_id[UV_IF_NAMESIZE]; + size_t interface_id_len; + int count; + int ix; + int r; + + 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; + + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr, &scoped_addr_len)); +#ifndef _WIN32 + /* This assert fails on Windows, as Windows semantics are different. */ + ASSERT(0 == strcmp(device_name, scoped_addr)); +#endif + + interface_id_len = sizeof(interface_id); + r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); + ASSERT(0 == r); +#ifdef _WIN32 + /* On Windows, the interface identifier is the numeric string of the index. */ + ASSERT(strtol(interface_id, NULL, 10) == iface_index); +#else + /* On Unix/Linux, the interface identifier is the interface device name. */ + ASSERT(0 == strcmp(device_name, interface_id)); +#endif + + snprintf(scoped_addr, + sizeof(scoped_addr), + "%s%%%s", + string_address, + interface_id); + + 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); + + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); + + 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/3rd/libuv-1.19.2/test/test-ipc-send-recv.c b/3rd/libuv-1.19.2/test/test-ipc-send-recv.c new file mode 100644 index 00000000..917744cb --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ipc-send-recv.c @@ -0,0 +1,428 @@ +/* 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 +#include + +/* 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_count; +static int recv_cb_count; +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; + + pipe = (uv_pipe_t*) handle; + ASSERT(pipe == &ctx.channel); + + do { + if (++recv_cb_count == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } + + /* 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_count == 2); + } else { + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + 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); + } + } while (uv_pipe_pending_count(pipe) > 0); + + /* Close after two writes received */ + if (recv_cb_count == 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_count == 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + return run_ipc_send_recv_pipe(0); +} + +TEST_IMPL(ipc_send_recv_pipe_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + return run_ipc_send_recv_tcp(0); +} + +TEST_IMPL(ipc_send_recv_tcp_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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; + } + + pipe = (uv_pipe_t*) handle; + do { + if (++read_cb_count == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } + + ASSERT(pipe == &ctx2.channel); + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + 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); + } while (uv_pipe_pending_count(pipe) > 0); +} + +static void send_recv_start(void) { + 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/3rd/libuv-1.19.2/test/test-ipc.c b/3rd/libuv-1.19.2/test/test-ipc.c new file mode 100644 index 00000000..88d63d4d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ipc.c @@ -0,0 +1,887 @@ +/* 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 +#include + +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; +static int closed_handle_data_read; + +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 +#define LARGE_SIZE 1000000 + + +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); +} + + +#ifndef _WIN32 +static void on_read_closed_handle(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + if (nread == 0 || nread == UV_EOF) { + free(buf->base); + return; + } + + if (nread < 0) { + printf("error recving on channel: %s\n", uv_strerror(nread)); + abort(); + } + + closed_handle_data_read += nread; + free(buf->base); +} +#endif + + +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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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; +} + +#ifndef _WIN32 +TEST_IMPL(ipc_closed_handle) { + int r; + r = run_ipc_test("ipc_helper_closed_handle", on_read_closed_handle); + ASSERT(r == 0); + return 0; +} +#endif + + +#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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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 closed_handle_large_write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + ASSERT(closed_handle_data_read = LARGE_SIZE); +} + + +static void closed_handle_write_cb(uv_write_t* req, int status) { + ASSERT(status == UV_EBADF); +} + + +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_closed_handle(void) { + int r; + struct sockaddr_in addr; + uv_write_t write_req; + uv_write_t write_req2; + uv_buf_t buf; + char buffer[LARGE_SIZE]; + + 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)); + + memset(buffer, '.', LARGE_SIZE); + buf = uv_buf_init(buffer, LARGE_SIZE); + + 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_write(&write_req, + (uv_stream_t*)&channel, + &buf, + 1, + closed_handle_large_write_cb); + ASSERT(r == 0); + + r = uv_write2(&write_req2, + (uv_stream_t*)&channel, + &buf, + 1, + (uv_stream_t*)&tcp_server, + closed_handle_write_cb); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&tcp_server, NULL); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + 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/3rd/libuv-1.19.2/test/test-list.h b/3rd/libuv-1.19.2/test/test-list.h new file mode 100644 index 00000000..ff0a31d1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-list.h @@ -0,0 +1,905 @@ +/* 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" + +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_instant_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 (condvar_6) +TEST_DECLARE (semaphore_1) +TEST_DECLARE (semaphore_2) +TEST_DECLARE (semaphore_3) +TEST_DECLARE (tty) +#ifdef _WIN32 +TEST_DECLARE (tty_raw) +TEST_DECLARE (tty_empty_write) +TEST_DECLARE (tty_large_write) +#endif +TEST_DECLARE (tty_file) +TEST_DECLARE (tty_pty) +TEST_DECLARE (stdio_over_pipes) +TEST_DECLARE (ip6_pton) +TEST_DECLARE (connect_unspecified) +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) +#ifndef _WIN32 +TEST_DECLARE (ipc_closed_handle) +#endif +TEST_DECLARE (tcp_alloc_cb_fail) +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_open_bound) +TEST_DECLARE (tcp_open_connected) +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_alloc_cb_fail) +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_hang_loop) +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 (env_vars) +TEST_DECLARE (error_message) +TEST_DECLARE (sys_error) +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 (timer_early_check) +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 (pipe_set_chmod) +TEST_DECLARE (process_ref) +TEST_DECLARE (has_ref) +TEST_DECLARE (active) +TEST_DECLARE (embed) +TEST_DECLARE (async) +TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) +TEST_DECLARE (get_currentexe) +TEST_DECLARE (process_title) +TEST_DECLARE (process_title_threadsafe) +TEST_DECLARE (cwd_and_chdir) +TEST_DECLARE (get_memory) +TEST_DECLARE (get_passwd) +TEST_DECLARE (handle_fileno) +TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) +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 (gethostname) +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 (spawn_quoted_path) +TEST_DECLARE (spawn_tcp_server) +TEST_DECLARE (fs_poll) +TEST_DECLARE (fs_poll_getpath) +TEST_DECLARE (kill) +TEST_DECLARE (kill_invalid_signum) +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_copyfile) +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) +#ifdef _WIN32 +TEST_DECLARE (fs_symlink_junction) +TEST_DECLARE (fs_non_symlink_reparse_point) +#endif +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_exact_path) +TEST_DECLARE (fs_event_watch_file_twice) +TEST_DECLARE (fs_event_watch_file_current_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_file_root_dir) +#endif +TEST_DECLARE (fs_event_watch_invalid_path) +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_non_existent_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 (get_osfhandle_valid_handle) +TEST_DECLARE (fs_write_alotof_bufs) +TEST_DECLARE (fs_write_alotof_bufs_with_offset) +TEST_DECLARE (fs_file_pos_after_op_with_offset) +TEST_DECLARE (fs_null_req) +#ifdef _WIN32 +TEST_DECLARE (fs_exclusive_sharing_mode) +#endif +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_stack_size) +TEST_DECLARE (thread_mutex) +TEST_DECLARE (thread_mutex_recursive) +TEST_DECLARE (thread_rwlock) +TEST_DECLARE (thread_rwlock_trylock) +TEST_DECLARE (thread_create) +TEST_DECLARE (thread_equal) +TEST_DECLARE (dlerror) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) +TEST_DECLARE (poll_oob) +#endif +TEST_DECLARE (poll_duplex) +TEST_DECLARE (poll_unidirectional) +TEST_DECLARE (poll_close) +TEST_DECLARE (poll_bad_fdtype) +#ifdef __linux__ +TEST_DECLARE (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE +TEST_DECLARE (poll_nested_kqueue) +#endif + +TEST_DECLARE (ip4_addr) +TEST_DECLARE (ip6_addr_link_local) + +TEST_DECLARE (poll_close_doesnt_corrupt_stack) +TEST_DECLARE (poll_closesocket) +#ifdef _WIN32 +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) +TEST_DECLARE (win32_signum_number) +#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 (we_get_signal_one_shot) +TEST_DECLARE (we_get_signals_mixed) +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) + +TEST_DECLARE (handle_type_name) +TEST_DECLARE (req_type_name) +TEST_DECLARE (getters_setters) + +#ifndef _WIN32 +TEST_DECLARE (fork_timer) +TEST_DECLARE (fork_socketpair) +TEST_DECLARE (fork_socketpair_started) +TEST_DECLARE (fork_signal_to_child) +TEST_DECLARE (fork_signal_to_child_closed) +TEST_DECLARE (fork_fs_events_child) +TEST_DECLARE (fork_fs_events_child_dir) +TEST_DECLARE (fork_fs_events_file_parent_child) +#ifndef __MVS__ +TEST_DECLARE (fork_threadpool_queue_work_simple) +#endif +#endif + +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_instant_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 (condvar_6) + 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 (pipe_set_chmod) + TEST_ENTRY (tty) +#ifdef _WIN32 + TEST_ENTRY (tty_raw) + TEST_ENTRY (tty_empty_write) + TEST_ENTRY (tty_large_write) +#endif + TEST_ENTRY (tty_file) + TEST_ENTRY (tty_pty) + TEST_ENTRY (stdio_over_pipes) + TEST_ENTRY (ip6_pton) + TEST_ENTRY (connect_unspecified) + 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) +#ifndef _WIN32 + TEST_ENTRY (ipc_closed_handle) +#endif + + TEST_ENTRY (tcp_alloc_cb_fail) + + 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 + +#ifdef __MVS__ + TEST_ENTRY_CUSTOM (tcp_writealot, 0, 0, 20000) +#else + TEST_ENTRY (tcp_writealot) +#endif + 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_open_bound) + TEST_ENTRY (tcp_open_connected) + TEST_HELPER (tcp_open_connected, tcp4_echo_server) + + 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_alloc_cb_fail) + 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_hang_loop) + 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 (env_vars) + + TEST_ENTRY (error_message) + TEST_ENTRY (sys_error) + + 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 (timer_early_check) + + 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 (eintr_handling) + + TEST_ENTRY (get_currentexe) + + TEST_ENTRY (process_title) + TEST_ENTRY (process_title_threadsafe) + + TEST_ENTRY (cwd_and_chdir) + + TEST_ENTRY (get_memory) + + TEST_ENTRY (get_passwd) + + TEST_ENTRY (get_loadavg) + + TEST_ENTRY (handle_fileno) + + TEST_ENTRY (homedir) + + TEST_ENTRY (tmpdir) + + 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 (gethostname) + + 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 (poll_bad_fdtype) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) + TEST_ENTRY (poll_oob) +#endif + +#ifdef __linux__ + TEST_ENTRY (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE + TEST_ENTRY (poll_nested_kqueue) +#endif + + 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 (spawn_quoted_path) + TEST_ENTRY (spawn_tcp_server) + TEST_ENTRY (fs_poll) + TEST_ENTRY (fs_poll_getpath) + TEST_ENTRY (kill) + TEST_ENTRY (kill_invalid_signum) + + TEST_ENTRY (poll_close_doesnt_corrupt_stack) + TEST_ENTRY (poll_closesocket) +#ifdef _WIN32 + 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) + TEST_ENTRY (win32_signum_number) +#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 (we_get_signal_one_shot) + TEST_ENTRY (we_get_signals_mixed) + 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_copyfile) + 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) +#ifdef _WIN32 + TEST_ENTRY (fs_symlink_junction) + TEST_ENTRY (fs_non_symlink_reparse_point) +#endif + 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_exact_path) + TEST_ENTRY (fs_event_watch_file_twice) + TEST_ENTRY (fs_event_watch_file_current_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_file_root_dir) +#endif + TEST_ENTRY (fs_event_watch_invalid_path) + 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_non_existent_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 (fs_file_pos_after_op_with_offset) + TEST_ENTRY (fs_null_req) +#ifdef _WIN32 + TEST_ENTRY (fs_exclusive_sharing_mode) +#endif + TEST_ENTRY (get_osfhandle_valid_handle) + 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_stack_size) + TEST_ENTRY (thread_mutex) + TEST_ENTRY (thread_mutex_recursive) + 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) + + TEST_ENTRY (handle_type_name) + TEST_ENTRY (req_type_name) + TEST_ENTRY (getters_setters) + +#ifndef _WIN32 + TEST_ENTRY (fork_timer) + TEST_ENTRY (fork_socketpair) + TEST_ENTRY (fork_socketpair_started) + TEST_ENTRY (fork_signal_to_child) + TEST_ENTRY (fork_signal_to_child_closed) + TEST_ENTRY (fork_fs_events_child) + TEST_ENTRY (fork_fs_events_child_dir) + TEST_ENTRY (fork_fs_events_file_parent_child) +#ifndef __MVS__ + TEST_ENTRY (fork_threadpool_queue_work_simple) +#endif +#endif + +#if 0 + /* These are for testing the test runner. */ + TEST_ENTRY (fail_always) + TEST_ENTRY (pass_always) +#endif +TASK_LIST_END diff --git a/3rd/libuv-1.19.2/test/test-loop-alive.c b/3rd/libuv-1.19.2/test/test-loop-alive.c new file mode 100644 index 00000000..cf4d3019 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-loop-close.c b/3rd/libuv-1.19.2/test/test-loop-close.c new file mode 100644 index 00000000..f0f3e627 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-loop-close.c @@ -0,0 +1,75 @@ +/* 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; + + loop.data = &loop; + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(loop.data == (void*) &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(loop.data == (void*) &loop); + ASSERT(0 == uv_loop_close(&loop)); + ASSERT(loop.data == (void*) &loop); + + return 0; +} + +static void loop_instant_close_work_cb(uv_work_t* req) { +} + +static void loop_instant_close_after_work_cb(uv_work_t* req, int status) { +} + +TEST_IMPL(loop_instant_close) { + static uv_loop_t loop; + static uv_work_t req; + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_queue_work(&loop, + &req, + loop_instant_close_work_cb, + loop_instant_close_after_work_cb)); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-loop-configure.c b/3rd/libuv-1.19.2/test/test-loop-configure.c new file mode 100644 index 00000000..d057c1ed --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-loop-configure.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2014, Ben Noordhuis + * + * 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/3rd/libuv-1.19.2/test/test-loop-handles.c b/3rd/libuv-1.19.2/test/test-loop-handles.c new file mode 100644 index 00000000..c3e8498a --- /dev/null +++ b/3rd/libuv-1.19.2/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 + + +#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/3rd/libuv-1.19.2/test/test-loop-stop.c b/3rd/libuv-1.19.2/test/test-loop-stop.c new file mode 100644 index 00000000..14b8c111 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-loop-time.c b/3rd/libuv-1.19.2/test/test-loop-time.c new file mode 100644 index 00000000..a2db42cc --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-multiple-listen.c b/3rd/libuv-1.19.2/test/test-multiple-listen.c new file mode 100644 index 00000000..4ae5fa67 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-mutexes.c b/3rd/libuv-1.19.2/test/test-mutexes.c new file mode 100644 index 00000000..975222ca --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-mutexes.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 +#include + +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_mutex_recursive) { + uv_mutex_t mutex; + int r; + + r = uv_mutex_init_recursive(&mutex); + ASSERT(r == 0); + + uv_mutex_lock(&mutex); + uv_mutex_lock(&mutex); + ASSERT(0 == uv_mutex_trylock(&mutex)); + + uv_mutex_unlock(&mutex); + uv_mutex_unlock(&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/3rd/libuv-1.19.2/test/test-osx-select.c b/3rd/libuv-1.19.2/test/test-osx-select.c new file mode 100644 index 00000000..a0afda91 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-pass-always.c b/3rd/libuv-1.19.2/test/test-pass-always.c new file mode 100644 index 00000000..4fb58ff9 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-ping-pong.c b/3rd/libuv-1.19.2/test/test-ping-pong.c new file mode 100644 index 00000000..508f0db6 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ping-pong.c @@ -0,0 +1,274 @@ +/* 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 +#include + +static int completed_pingers = 0; + +#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__) +#define NUM_PINGS 100 /* fewer pings to avoid timeout */ +#else +#define NUM_PINGS 1000 +#endif + +/* 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/3rd/libuv-1.19.2/test/test-pipe-bind-error.c b/3rd/libuv-1.19.2/test/test-pipe-bind-error.c new file mode 100644 index 00000000..9cf93165 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-bind-error.c @@ -0,0 +1,139 @@ +/* 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 +#include + + +#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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c b/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c new file mode 100644 index 00000000..4ab14789 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c @@ -0,0 +1,107 @@ +/* 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 +#include +#include +#include + +#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; + char buf; + 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]); + /* block until write end of pipe is closed */ + read(fd[0], &buf, 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/3rd/libuv-1.19.2/test/test-pipe-connect-error.c b/3rd/libuv-1.19.2/test/test-pipe-connect-error.c new file mode 100644 index 00000000..ebb2a6ca --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +#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/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c b/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c new file mode 100644 index 00000000..0a60d4a9 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 +#include + + +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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c b/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c new file mode 100644 index 00000000..a86e7284 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 +#include + + +#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/3rd/libuv-1.19.2/test/test-pipe-getsockname.c b/3rd/libuv-1.19.2/test/test-pipe-getsockname.c new file mode 100644 index 00000000..d1628a67 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-getsockname.c @@ -0,0 +1,266 @@ +/* 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 +#include +#include + +#if defined(__linux__) + #include + #include +#endif + +#ifndef _WIN32 +# include /* close */ +#else +# include +#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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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(buf[len] == '\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(len1 == 0); /* It's an annonymous pipe. */ + + 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(len2 == 0); /* It's an annonymous pipe. */ + + 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); + + CloseHandle(writeh); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c b/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c new file mode 100644 index 00000000..b6ff911a --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c b/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c new file mode 100644 index 00000000..3bf427f8 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-sendmsg.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 "task.h" + + +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include + + +/* 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-server-close.c b/3rd/libuv-1.19.2/test/test-pipe-server-close.c new file mode 100644 index 00000000..ea9977dd --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-server-close.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 +#include + + +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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c b/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c new file mode 100644 index 00000000..59f0e6f5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c @@ -0,0 +1,66 @@ +/* Copyright 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. +*/ + + +#include "uv.h" +#include "task.h" + +TEST_IMPL(pipe_set_chmod) { + uv_pipe_t pipe_handle; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_pipe_init(loop, &pipe_handle, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); + ASSERT(r == 0); + + /* No easy way to test if this works, we will only make sure that */ + /* the call is successful. */ + r = uv_pipe_chmod(&pipe_handle, UV_READABLE); + if (r == UV_EPERM) { + MAKE_VALGRIND_HAPPY(); + RETURN_SKIP("Insufficient privileges to alter pipe fmode"); + } + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + r = uv_pipe_chmod(&pipe_handle, 12345678); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&pipe_handle, NULL); + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c b/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c new file mode 100644 index 00000000..fcc9fc0d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c @@ -0,0 +1,99 @@ +/* Copyright (c) 2015, Ben Noordhuis + * + * 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 +#include +#include +#include +#include +#include + +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/3rd/libuv-1.19.2/test/test-platform-output.c b/3rd/libuv-1.19.2/test/test-platform-output.c new file mode 100644 index 00000000..4025fba5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-platform-output.c @@ -0,0 +1,157 @@ +/* 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 + + +TEST_IMPL(platform_output) { + char buffer[512]; + size_t rss; + size_t size; + double uptime; + uv_pid_t pid; + uv_pid_t ppid; + uv_rusage_t rusage; + uv_cpu_info_t* cpus; + uv_interface_address_t* interfaces; + uv_passwd_t pwd; + 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); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else + ASSERT(err == 0); + printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); +#endif + + 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); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + + err = uv_cpu_info(&cpus, &count); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else + 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); + } +#endif + 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); + + err = uv_os_get_passwd(&pwd); + ASSERT(err == 0); + + printf("uv_os_get_passwd:\n"); + printf(" euid: %ld\n", pwd.uid); + printf(" gid: %ld\n", pwd.gid); + printf(" username: %s\n", pwd.username); + printf(" shell: %s\n", pwd.shell); + printf(" home directory: %s\n", pwd.homedir); + + pid = uv_os_getpid(); + ASSERT(pid > 0); + printf("uv_os_getpid: %d\n", (int) pid); + ppid = uv_os_getppid(); + ASSERT(ppid > 0); + printf("uv_os_getppid: %d\n", (int) ppid); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c b/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c new file mode 100644 index 00000000..1dfc80e3 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c @@ -0,0 +1,116 @@ +/* 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. + */ + +#include +#include + +#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; + +#ifdef _WIN32 +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); +} +#endif + + +TEST_IMPL(poll_close_doesnt_corrupt_stack) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else + 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 +} diff --git a/3rd/libuv-1.19.2/test/test-poll-close.c b/3rd/libuv-1.19.2/test/test-poll-close.c new file mode 100644 index 00000000..2eccddf5 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#ifndef _WIN32 +# include +# include +# include +#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/3rd/libuv-1.19.2/test/test-poll-closesocket.c b/3rd/libuv-1.19.2/test/test-poll-closesocket.c new file mode 100644 index 00000000..ecaa9e54 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-closesocket.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 + +#include "uv.h" +#include "task.h" + +uv_os_sock_t sock; +uv_poll_t handle; + +#ifdef _WIN32 +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); + +} +#endif + + +TEST_IMPL(poll_closesocket) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else + 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/3rd/libuv-1.19.2/test/test-poll-oob.c b/3rd/libuv-1.19.2/test/test-poll-oob.c new file mode 100644 index 00000000..2a6da843 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-oob.c @@ -0,0 +1,205 @@ +/* Copyright 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(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include +#include + +static uv_tcp_t server_handle; +static uv_tcp_t client_handle; +static uv_tcp_t peer_handle; +static uv_poll_t poll_req[2]; +static uv_idle_t idle; +static uv_os_fd_t client_fd; +static uv_os_fd_t server_fd; +static int ticks; +static const int kMaxTicks = 10; +static int cli_pr_check = 0; +static int cli_rd_check = 0; +static int srv_rd_check = 0; + +static int got_eagain(void) { + return errno == EAGAIN + || errno == EINPROGRESS +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ; +} + +static void idle_cb(uv_idle_t* idle) { + uv_sleep(100); + if (++ticks < kMaxTicks) + return; + + uv_poll_stop(&poll_req[0]); + uv_poll_stop(&poll_req[1]); + 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 poll_cb(uv_poll_t* handle, int status, int events) { + char buffer[5]; + int n; + int fd; + + ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + memset(buffer, 0, 5); + + if (events & UV_PRIORITIZED) { + do + n = recv(client_fd, &buffer, 5, MSG_OOB); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + cli_pr_check = 1; + ASSERT(0 == uv_poll_stop(&poll_req[0])); + ASSERT(0 == uv_poll_start(&poll_req[0], + UV_READABLE | UV_WRITABLE, + poll_cb)); + } + if (events & UV_READABLE) { + if (fd == client_fd) { + do + n = recv(client_fd, &buffer, 5, 0); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + if (cli_rd_check == 1) { + ASSERT(strncmp(buffer, "world", n) == 0); + ASSERT(5 == n); + cli_rd_check = 2; + } + if (cli_rd_check == 0) { + ASSERT(n == 4); + ASSERT(strncmp(buffer, "hello", n) == 0); + cli_rd_check = 1; + do { + do + n = recv(server_fd, &buffer, 5, 0); + while (n == -1 && errno == EINTR); + if (n > 0) { + ASSERT(n == 5); + ASSERT(strncmp(buffer, "world", n) == 0); + cli_rd_check = 2; + } + } while (n > 0); + + ASSERT(got_eagain()); + } + } + if (fd == server_fd) { + do + n = recv(server_fd, &buffer, 3, 0); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + ASSERT(3 == n); + ASSERT(strncmp(buffer, "foo", n) == 0); + srv_rd_check = 1; + uv_poll_stop(&poll_req[1]); + } + } + if (events & UV_WRITABLE) { + do { + n = send(client_fd, "foo", 3, 0); + } while (n < 0 && errno == EINTR); + ASSERT(3 == n); + } +} + +static void connection_cb(uv_stream_t* handle, int status) { + int r; + + ASSERT(0 == status); + ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); + ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); + ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); + ASSERT(0 == uv_poll_start(&poll_req[0], + UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, + poll_cb)); + ASSERT(0 == uv_poll_start(&poll_req[1], + UV_READABLE, + poll_cb)); + do { + r = send(server_fd, "hello", 5, MSG_OOB); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + do { + r = send(server_fd, "world", 5, 0); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + ASSERT(0 == uv_idle_start(&idle, idle_cb)); +} + + +TEST_IMPL(poll_oob) { + struct sockaddr_in addr; + int r = 0; + 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)); + + client_fd = socket(PF_INET, SOCK_STREAM, 0); + ASSERT(client_fd >= 0); + do { + errno = 0; + r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); + } while (r == -1 && errno == EINTR); + ASSERT(r == 0); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(ticks == kMaxTicks); + + /* Did client receive the POLLPRI message */ + ASSERT(cli_pr_check == 1); + /* Did client receive the POLLIN message */ + ASSERT(cli_rd_check == 2); + /* Could we write with POLLOUT and did the server receive our POLLOUT message + * through POLLIN. + */ + ASSERT(srv_rd_check == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif diff --git a/3rd/libuv-1.19.2/test/test-poll.c b/3rd/libuv-1.19.2/test/test-poll.c new file mode 100644 index 00000000..e828addb --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll.c @@ -0,0 +1,665 @@ +/* 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 + +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +#include "uv.h" +#include "task.h" + +#ifdef __linux__ +# include +#endif + +#ifdef UV_HAVE_KQUEUE +# include +# include +# include +#endif + + +#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, got_disconnect; + 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; + +#if !defined(_AIX) && !defined(__MVS__) +static int disconnects = 0; +#endif /* !_AIX && !__MVS__ */ + +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; + context->got_disconnect = 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 !defined(_AIX) && !defined(__MVS__) + if (events & UV_DISCONNECT) { + context->got_disconnect = 1; + ++disconnects; + new_events &= ~UV_DISCONNECT; + } + + if (context->got_fin && context->sent_fin && context->got_disconnect) { +#else /* _AIX && __MVS__ */ + if (context->got_fin && context->sent_fin) { +#endif /* !_AIX && !__MVS__ */ + /* 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 | UV_DISCONNECT; + r = uv_poll_start(&connection_context->poll_handle, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, + 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 | UV_DISCONNECT; + r = uv_poll_start(&context->poll_handle, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, + 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); +#if !defined(_AIX) && !defined(__MVS__) + ASSERT(disconnects == NUM_CLIENTS * 2); +#endif + MAKE_VALGRIND_HAPPY(); +} + + +TEST_IMPL(poll_duplex) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + test_mode = DUPLEX; + start_poll_test(); + return 0; +} + + +TEST_IMPL(poll_unidirectional) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + test_mode = UNIDIRECTIONAL; + start_poll_test(); + return 0; +} + + +/* Windows won't let you open a directory so we open a file instead. + * OS X lets you poll a file so open the $PWD instead. Both fail + * on Linux so it doesn't matter which one we pick. Both succeed + * on FreeBSD, Solaris and AIX so skip the test on those platforms. + */ +TEST_IMPL(poll_bad_fdtype) { +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ + !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) && \ + !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ + !defined(__NetBSD__) + uv_poll_t poll_handle; + int fd; + +#if defined(_WIN32) + fd = open("test/fixtures/empty_file", O_RDONLY); +#else + fd = open(".", O_RDONLY); +#endif + ASSERT(fd != -1); + ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == close(fd)); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#ifdef __linux__ +TEST_IMPL(poll_nested_epoll) { + uv_poll_t poll_handle; + int fd; + + fd = epoll_create(1); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* __linux__ */ + + +#ifdef UV_HAVE_KQUEUE +TEST_IMPL(poll_nested_kqueue) { + uv_poll_t poll_handle; + int fd; + + fd = kqueue(); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* UV_HAVE_KQUEUE */ diff --git a/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c b/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c new file mode 100644 index 00000000..d986576e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c @@ -0,0 +1,90 @@ +/* Copyright 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. +*/ + + +#include "uv.h" +#include "task.h" + +#include + +#ifdef __APPLE__ +# define NUM_ITERATIONS 20 +#else +# define NUM_ITERATIONS 50 +#endif + +static const char* titles[] = { + "8L2NY0Kdj0XyNFZnmUZigIOfcWjyNr0SkMmUhKw99VLUsZFrvCQQC3XIRfNR8pjyMjXObllled", + "jUAcscJN49oLSN8GdmXj2Wo34XX2T2vp2j5khfajNQarlOulp57cE130yiY53ipJFnPyTn5i82", + "9niCI5icXGFS72XudhXqo5alftmZ1tpE7B3cwUmrq0CCDjC84FzBNB8XAHqvpNQfI2QAQG6ztT", + "n8qXVXuG6IEHDpabJgTEiwtpY6LHMZ8MgznnMpdHARu5EywufA6hcBaQfetb0YhEsK0ykDd7JU" +}; + +static void getter_thread_body(void* arg) { + char buffer[512]; + + for (;;) { + ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); + ASSERT( + 0 == strcmp(buffer, titles[0]) || + 0 == strcmp(buffer, titles[1]) || + 0 == strcmp(buffer, titles[2]) || + 0 == strcmp(buffer, titles[3])); + + uv_sleep(0); + } +} + + +static void setter_thread_body(void* arg) { + int i; + + for (i = 0; i < NUM_ITERATIONS; i++) { + ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT(0 == uv_set_process_title(titles[1])); + ASSERT(0 == uv_set_process_title(titles[2])); + ASSERT(0 == uv_set_process_title(titles[3])); + } +} + + +TEST_IMPL(process_title_threadsafe) { + uv_thread_t setter_threads[4]; + uv_thread_t getter_thread; + int i; + +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ + defined(__MVS__) + RETURN_SKIP("uv_(get|set)_process_title is not implemented."); +#else + + ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT(0 == uv_thread_create(&getter_thread, getter_thread_body, NULL)); + + for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) + ASSERT(0 == uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); + + for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) + ASSERT(0 == uv_thread_join(&setter_threads[i])); + + return 0; +#endif +} diff --git a/3rd/libuv-1.19.2/test/test-process-title.c b/3rd/libuv-1.19.2/test/test-process-title.c new file mode 100644 index 00000000..886f83a7 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-process-title.c @@ -0,0 +1,75 @@ +/* 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 + + +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); +} + + +static void uv_get_process_title_edge_cases(void) { + char buffer[512]; + int r; + + /* Test a NULL buffer */ + r = uv_get_process_title(NULL, 100); + ASSERT(r == UV_EINVAL); + + /* Test size of zero */ + r = uv_get_process_title(buffer, 0); + ASSERT(r == UV_EINVAL); + + /* Test for insufficient buffer size */ + r = uv_get_process_title(buffer, 1); + ASSERT(r == UV_ENOBUFS); +} + + +TEST_IMPL(process_title) { +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) + 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"); + + /* Check uv_get_process_title() edge cases */ + uv_get_process_title_edge_cases(); + + return 0; +#endif +} diff --git a/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c b/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c new file mode 100644 index 00000000..45da2253 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + + +/* + * 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/3rd/libuv-1.19.2/test/test-ref.c b/3rd/libuv-1.19.2/test/test-ref.c new file mode 100644 index 00000000..05728c83 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ref.c @@ -0,0 +1,445 @@ +/* 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 +#include + + +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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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/3rd/libuv-1.19.2/test/test-run-nowait.c b/3rd/libuv-1.19.2/test/test-run-nowait.c new file mode 100644 index 00000000..43524f63 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-run-once.c b/3rd/libuv-1.19.2/test/test-run-once.c new file mode 100644 index 00000000..10cbf95e --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-semaphore.c b/3rd/libuv-1.19.2/test/test-semaphore.c new file mode 100644 index 00000000..ac03bb08 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-shutdown-close.c b/3rd/libuv-1.19.2/test/test-shutdown-close.c new file mode 100644 index 00000000..78c369be --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-shutdown-eof.c b/3rd/libuv-1.19.2/test/test-shutdown-eof.c new file mode 100644 index 00000000..9f95e756 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-shutdown-twice.c b/3rd/libuv-1.19.2/test/test-shutdown-twice.c new file mode 100644 index 00000000..d7aae899 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-shutdown-twice.c @@ -0,0 +1,85 @@ +/* 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); + 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(shutdown_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c b/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c new file mode 100644 index 00000000..1272d457 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c @@ -0,0 +1,298 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +/* 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) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: This test needs more investigation. Somehow the `read` in + uv__signal_lock fails spuriously with EACCES or even EAGAIN even + though it is supposed to be blocking. Also the test hangs during + thread setup occasionally. */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + 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); + } + + uv_sem_destroy(&sem); + 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/3rd/libuv-1.19.2/test/test-signal.c b/3rd/libuv-1.19.2/test/test-signal.c new file mode 100644 index 00000000..c2ce5ec0 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-signal.c @@ -0,0 +1,325 @@ +/* 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 +#endif + +TEST_IMPL(kill_invalid_signum) { + uv_pid_t pid; + + pid = uv_os_getpid(); + + ASSERT(uv_kill(pid, -1) == UV_EINVAL); +#ifdef _WIN32 + /* NSIG is not available on all platforms. */ + ASSERT(uv_kill(pid, NSIG) == UV_EINVAL); +#endif + ASSERT(uv_kill(pid, 4096) == UV_EINVAL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* For Windows we test only signum handling */ +#ifdef _WIN32 +static void signum_test_cb(uv_signal_t* handle, int signum) { + FATAL("signum_test_cb should not be called"); +} + +TEST_IMPL(win32_signum_number) { + uv_signal_t signal; + uv_loop_t* loop; + + loop = uv_default_loop(); + uv_signal_init(loop, &signal); + + ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); + MAKE_VALGRIND_HAPPY(); + return 0; +} +#else +#include +#include +#include +#include +#include +#include +#include + +#define NSIGNALS 10 + +struct timer_ctx { + unsigned int ncalls; + uv_timer_t handle; + int signum; +}; + +struct signal_ctx { + enum { CLOSE, STOP, NOOP } stop_or_close; + unsigned int ncalls; + uv_signal_t handle; + int signum; + int one_shot; +}; + + +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 signal_cb_one_shot(uv_signal_t* handle, int signum) { + struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); + ASSERT(signum == ctx->signum); + ASSERT(++ctx->ncalls == 1); + if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); +} + + +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, + int one_shot) { + ctx->ncalls = 0; + ctx->signum = signum; + ctx->stop_or_close = CLOSE; + ctx->one_shot = one_shot; + ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + if (one_shot) + ASSERT(0 == uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); + else + 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, 0); + 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, 0); + start_watcher(loop, SIGUSR1, sc + 1, 0); + start_watcher(loop, SIGUSR2, sc + 2, 0); + start_watcher(loop, SIGUSR2, sc + 3, 0); + 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; +} + +TEST_IMPL(we_get_signal_one_shot) { + 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, 1); + sc.stop_or_close = NOOP; + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == 1); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(sc.ncalls == 1); + + sc.ncalls = 0; + sc.stop_or_close = CLOSE; /* now close it when it's done */ + uv_signal_start_oneshot(&sc.handle, signal_cb_one_shot, SIGCHLD); + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(we_get_signals_mixed) { + struct signal_ctx sc[4]; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + + /* 2 one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + start_watcher(loop, SIGCHLD, sc + 1, 1); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 1); + ASSERT(sc[1].ncalls == 1); + + /* 2 one-shot, 1 normal then remove normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + start_watcher(loop, SIGCHLD, sc + 1, 1); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + start_watcher(loop, SIGCHLD, sc + 2, 0); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 1); + ASSERT(sc[1].ncalls == 1); + ASSERT(sc[2].ncalls == 0); + + /* 2 normal, 1 one-shot then remove one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + start_watcher(loop, SIGCHLD, sc + 2, 1); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == NSIGNALS); + ASSERT(sc[1].ncalls == NSIGNALS); + ASSERT(sc[2].ncalls == 0); + + /* 2 normal, 2 one-shot then remove 2 normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + start_watcher(loop, SIGCHLD, sc + 2, 1); + start_watcher(loop, SIGCHLD, sc + 3, 1); + sc[2].stop_or_close = CLOSE; + sc[3].stop_or_close = CLOSE; + uv_close((uv_handle_t*)&(sc[0]).handle, NULL); + uv_close((uv_handle_t*)&(sc[1]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 0); + ASSERT(sc[1].ncalls == 0); + ASSERT(sc[2].ncalls == 1); + ASSERT(sc[2].ncalls == 1); + + /* 1 normal, 1 one-shot, 2 normal then remove 1st normal, 2nd normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 1); + start_watcher(loop, SIGCHLD, sc + 2, 0); + start_watcher(loop, SIGCHLD, sc + 3, 0); + sc[3].stop_or_close = CLOSE; + uv_close((uv_handle_t*)&(sc[0]).handle, NULL); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 0); + ASSERT(sc[1].ncalls == 1); + ASSERT(sc[2].ncalls == 0); + ASSERT(sc[3].ncalls == NSIGNALS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* _WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-socket-buffer-size.c b/3rd/libuv-1.19.2/test/test-socket-buffer-size.c new file mode 100644 index 00000000..72f8c252 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-spawn.c b/3rd/libuv-1.19.2/test/test-spawn.c new file mode 100644 index 00000000..4a2869a1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-spawn.c @@ -0,0 +1,1875 @@ + +/* 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 +#include +#include +#include +#include + +#ifdef _WIN32 +# if defined(__MINGW32__) +# include +# endif +# include +# include +#else +# include +# include +#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[5]; +static int no_term_signal; +static int timer_counter; +static uv_tcp_t tcp_server; + +#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 +#if defined(__APPLE__) || defined(__MVS__) + /* + * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a + * process that is still starting up kills it with SIGKILL instead of SIGTERM. + * See: https://github.com/libuv/libuv/issues/1226 + */ + ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL); +#else + ASSERT(no_term_signal || term_signal == SIGTERM); +#endif + 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; + args[3] = NULL; + args[4] = 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*)∈ + 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; +} + + +int spawn_tcp_server_helper(void) { + uv_tcp_t tcp; + uv_os_sock_t handle; + int r; + + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT(r == 0); + +#ifdef _WIN32 + handle = _get_osfhandle(3); +#else + handle = 3; +#endif + r = uv_tcp_open(&tcp, handle); + ASSERT(r == 0); + + /* Make sure that we can listen on a socket that was + * passed down from the parent process + */ + r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL); + ASSERT(r == 0); + + return 1; +} + + +TEST_IMPL(spawn_tcp_server) { + uv_stdio_container_t stdio[4]; + struct sockaddr_in addr; + int fd; + int r; +#ifdef _WIN32 + uv_os_fd_t handle; +#endif + + init_process_options("spawn_tcp_server_helper", exit_cb); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + fd = -1; + r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET); + ASSERT(r == 0); + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); +#ifdef _WIN32 + r = uv_fileno((uv_handle_t*)&tcp_server, &handle); + fd = _open_osfhandle((intptr_t) handle, 0); +#else + r = uv_fileno((uv_handle_t*)&tcp_server, &fd); + #endif + ASSERT(r == 0); + ASSERT(fd > 0); + + options.stdio = stdio; + options.stdio[0].flags = UV_INHERIT_FD; + options.stdio[0].data.fd = 0; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = 1; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = 2; + options.stdio[3].flags = UV_INHERIT_FD; + options.stdio[3].data.fd = fd; + options.stdio_count = 4; + + 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_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); + + ASSERT(process.pid == uv_process_get_pid(&process)); + + 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*)∈ + 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*)∈ + 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*)∈ + 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*) ∈ + 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); + + /* Verify that uv_spawn() resets the signal disposition. */ +#ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL)); + } + ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); +#endif + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + +#ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); + } + ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); +#endif + + /* 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; + char uidstr[10]; + char gidstr[10]; + + /* if not root, then this will fail. */ + uv_uid_t uid = getuid(); + if (uid != 0) { + RETURN_SKIP("It should be run as root user"); + } + + init_process_options("spawn_helper_setuid_setgid", exit_cb); + + /* become the "nobody" user. */ + pw = getpwnam("nobody"); + ASSERT(pw != NULL); + options.uid = pw->pw_uid; + options.gid = pw->pw_gid; + snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); + snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); + options.args[2] = uidstr; + options.args[3] = gidstr; + 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); +#if defined(__CYGWIN__) + ASSERT(r == UV_EINVAL); +#else + ASSERT(r == UV_EPERM); +#endif + + 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; +#if defined(__MVS__) + options.gid = -1; +#else + options.gid = 0; +#endif + + r = uv_spawn(uv_default_loop(), &process, &options); +#if defined(__CYGWIN__) || defined(__MVS__) + ASSERT(r == UV_EINVAL); +#else + ASSERT(r == UV_EPERM); +#endif + + 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*) ∈ + 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"; +#elif defined __MVS__ + static const char dyld_path_var[] = "LIBPATH"; +#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); +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Carry over the dynamic linker path in case the test runner + is linked against cyguv-1.dll or msys-uv-1.dll, see above. */ + { + char* syspath = getenv("PATH"); + if (syspath != NULL) { + strcat(path, ":"); + strcat(path, syspath); + } + } +#endif + + 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; +} + +TEST_IMPL(spawn_quoted_path) { +#ifndef _WIN32 + RETURN_SKIP("Test for Windows"); +#else + char* quoted_path_env[2]; + args[0] = "not_existing"; + args[1] = NULL; + options.file = args[0]; + options.args = args; + options.exit_cb = exit_cb; + options.flags = 0; + /* We test if search_path works correctly with semicolons in quoted path. */ + /* We will use invalid drive, so we are sure no executable is spawned */ + quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; + quoted_path_env[1] = NULL; + options.env = quoted_path_env; + + /* We test if libuv will not segfault. */ + uv_spawn(uv_default_loop(), &process, &options); + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + +/* 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/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c b/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c new file mode 100644 index 00000000..15744761 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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*)∈ + 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/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c new file mode 100644 index 00000000..61ca667a --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c @@ -0,0 +1,123 @@ +/* Copyright 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 +#include +#include + +#include "uv.h" +#include "task.h" + +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 uv_write_t write_req; + +static char hello[] = "HELLO!"; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); +} + +static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + /* Do nothing, read_cb should be called with UV_ENOBUFS. */ +} + +static void conn_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == UV_ENOBUFS); + ASSERT(buf->base == NULL); + ASSERT(buf->len == 0); + + uv_close((uv_handle_t*) &incoming, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &server, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t buf; + + ASSERT(status == 0); + connect_cb_called++; + + buf = uv_buf_init(hello, sizeof(hello)); + r = uv_write(&write_req, 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)); + ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, + conn_alloc_cb, + conn_read_cb)); + + 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_alloc_cb_fail) { + 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(connection_cb_called == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-bind-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind-error.c new file mode 100644 index 00000000..10ed68e1 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c new file mode 100644 index 00000000..b762bcb3 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-close-accept.c b/3rd/libuv-1.19.2/test/test-tcp-close-accept.c new file mode 100644 index 00000000..e4878398 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-close-accept.c @@ -0,0 +1,194 @@ +/* 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 +#include + +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 unsigned int pending_incoming; + +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); + + /* + * Time to finish the test: close both the check and pending incoming + * connections + */ + uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], 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; + + pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; + ASSERT(pending_incoming < got_connections); + ASSERT(0 == uv_read_stop(stream)); + ASSERT(1 == nread); + + loop = stream->loop; + read_cb_called++; + + /* Close all active incomings, except current one */ + for (i = 0; i < got_connections; i++) { + if (i != pending_incoming) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + } + + /* Close server, so no one will connect to it */ + uv_close((uv_handle_t*) &tcp_server, 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)); +} + +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/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c b/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c new file mode 100644 index 00000000..8d0b8270 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c @@ -0,0 +1,97 @@ +/* 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 int netunreach_errors; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + /* The expected error is UV_ECANCELED but the test tries to connect to what + * is basically an arbitrary address in the expectation that no network path + * exists, so UV_ENETUNREACH is an equally plausible outcome. + */ + ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH); + uv_timer_stop(&timer2_handle); + connect_cb_called++; + if (status == UV_ENETUNREACH) + netunreach_errors++; +} + + +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, 1, 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(); + + if (netunreach_errors > 0) + RETURN_SKIP("Network unreachable."); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-close.c b/3rd/libuv-1.19.2/test/test-tcp-close.c new file mode 100644 index 00000000..e65885aa --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* 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/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c new file mode 100644 index 00000000..3f2e3572 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-tcp-connect-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error.c new file mode 100644 index 00000000..eab1eeb2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c b/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c new file mode 100644 index 00000000..081424b8 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c new file mode 100644 index 00000000..91ac0a3a --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c new file mode 100644 index 00000000..b87e7324 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 + +#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; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + 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); +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) + 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/3rd/libuv-1.19.2/test/test-tcp-flags.c b/3rd/libuv-1.19.2/test/test-tcp-flags.c new file mode 100644 index 00000000..68afb39f --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-oob.c b/3rd/libuv-1.19.2/test/test-tcp-oob.c new file mode 100644 index 00000000..4f1397a8 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-oob.c @@ -0,0 +1,141 @@ +/* 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 +#include +#include + +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) { +#ifdef __MVS__ + char lbuf[12]; +#endif + uv_os_fd_t fd; + + ASSERT(nread > 0); + ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + ASSERT(0 == uv_idle_start(&idle, idle_cb)); + +#ifdef __MVS__ + /* Need to flush out the OOB data. Otherwise, this callback will get + * triggered on every poll with nread = 0. + */ + ASSERT(-1 != recv(fd, lbuf, sizeof(lbuf), MSG_OOB)); +#endif +} + + +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/3rd/libuv-1.19.2/test/test-tcp-open.c b/3rd/libuv-1.19.2/test/test-tcp-open.c new file mode 100644 index 00000000..cb74c50e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-open.c @@ -0,0 +1,277 @@ +/* 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 +#include +#include + +#ifndef _WIN32 +# include +#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; +} + + +TEST_IMPL(tcp_open_bound) { + struct sockaddr_in addr; + uv_tcp_t server; + uv_os_sock_t sock; + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + + ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_open(&server, sock)); + + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_open_connected) { + struct sockaddr_in addr; + uv_tcp_t client; + uv_os_sock_t sock; + uv_buf_t buf = uv_buf_init("PING", 4); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + + ASSERT(0 == uv_tcp_open(&client, sock)); + + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); + + ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); + + ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(shutdown_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-read-stop.c b/3rd/libuv-1.19.2/test/test-tcp-read-stop.c new file mode 100644 index 00000000..488e8fb4 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c new file mode 100644 index 00000000..463b4b0d --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-try-write.c b/3rd/libuv-1.19.2/test/test-tcp-try-write.c new file mode 100644 index 00000000..97a1d6e3 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c b/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c new file mode 100644 index 00000000..c7b98145 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c b/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c new file mode 100644 index 00000000..aa03228f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-write-fail.c b/3rd/libuv-1.19.2/test/test-tcp-write-fail.c new file mode 100644 index 00000000..5256a9f4 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#ifndef _WIN32 +# include +#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/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c b/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c new file mode 100644 index 00000000..5119be6d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c @@ -0,0 +1,139 @@ +/* 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 +#include +#include + +#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++; +} + +static 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); +} + +static 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)); + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb, 1, 0)); + + 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; + int buffer_size = 16 * 1024; + + 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_send_buffer_size((uv_handle_t*) &client, &buffer_size)); + + 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/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c b/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c new file mode 100644 index 00000000..2fa2ae72 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-tcp-writealot.c b/3rd/libuv-1.19.2/test/test-tcp-writealot.c new file mode 100644 index 00000000..7206fdc2 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-writealot.c @@ -0,0 +1,180 @@ +/* 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 +#include + + +#define WRITES 3 +#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ +#define CHUNKS_PER_WRITE 2048 +#else +#define CHUNKS_PER_WRITE 4096 +#endif +#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/3rd/libuv-1.19.2/test/test-thread-equal.c b/3rd/libuv-1.19.2/test/test-thread-equal.c new file mode 100644 index 00000000..27c07ee2 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-thread.c b/3rd/libuv-1.19.2/test/test-thread.c new file mode 100644 index 00000000..955c9f2f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-thread.c @@ -0,0 +1,232 @@ +/* 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 +#include +#include /* 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; + 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 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[4]; + struct fs_req fs_reqs[4]; + uv_loop_t loop; + size_t i; + struct test_thread* thread = arg; + + ASSERT(0 == uv_loop_init(&loop)); + + for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { + struct getaddrinfo_req* req = getaddrinfo_reqs + i; + req->counter = 4; + req->loop = &loop; + getaddrinfo_do(req); + } + + for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { + struct fs_req* req = fs_reqs + i; + req->counter = 4; + req->loop = &loop; + fs_do(req); + } + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_loop_close(&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 == 1); + } + + 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; +} + + +static void thread_check_stack(void* arg) { +#if defined(__APPLE__) + /* 512 kB is the default stack size of threads other than the main thread + * on MacOS. */ + ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); +#elif defined(__linux__) && defined(__GLIBC__) + struct rlimit lim; + size_t stack_size; + pthread_attr_t attr; + ASSERT(0 == getrlimit(RLIMIT_STACK, &lim)); + if (lim.rlim_cur == RLIM_INFINITY) + lim.rlim_cur = 2 << 20; /* glibc default. */ + ASSERT(0 == pthread_getattr_np(pthread_self(), &attr)); + ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size)); + ASSERT(stack_size >= lim.rlim_cur); +#endif +} + + +TEST_IMPL(thread_stack_size) { + uv_thread_t thread; + ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT(0 == uv_thread_join(&thread)); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-threadpool-cancel.c b/3rd/libuv-1.19.2/test/test-threadpool-cancel.c new file mode 100644 index 00000000..dd13d8ae --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-threadpool-cancel.c @@ -0,0 +1,308 @@ +/* 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 unsigned fs_cb_called; +static unsigned done_cb_called; +static unsigned done2_cb_called; +static unsigned timer_cb_called; +static uv_work_t pause_reqs[4]; +static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)]; + + +static void work_cb(uv_work_t* req) { + uv_sem_wait(pause_sems + (req - pause_reqs)); +} + + +static void done_cb(uv_work_t* req, int status) { + uv_sem_destroy(pause_sems + (req - pause_reqs)); +} + + +static void saturate_threadpool(void) { + uv_loop_t* loop; + char buf[64]; + size_t i; + + snprintf(buf, + sizeof(buf), + "UV_THREADPOOL_SIZE=%lu", + (unsigned long)ARRAY_SIZE(pause_reqs)); + putenv(buf); + + loop = uv_default_loop(); + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) { + ASSERT(0 == uv_sem_init(pause_sems + i, 0)); + ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); + } +} + + +static void unblock_threadpool(void) { + size_t i; + + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) + uv_sem_post(pause_sems + i); +} + + +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_done_cb(uv_work_t* req, int status) { + ASSERT(status == UV_ECANCELED); + done_cb_called++; +} + + +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); + + 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); + + 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); + + 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); + + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_cancel_single) { + uv_loop_t* loop; + uv_work_t req; + + saturate_threadpool(); + loop = uv_default_loop(); + ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); + ASSERT(0 == uv_cancel((uv_req_t*) &req)); + ASSERT(0 == done_cb_called); + unblock_threadpool(); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == done_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-threadpool.c b/3rd/libuv-1.19.2/test/test-threadpool.c new file mode 100644 index 00000000..e3d17d75 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer-again.c b/3rd/libuv-1.19.2/test/test-timer-again.c new file mode 100644 index 00000000..f93c509b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer-from-check.c b/3rd/libuv-1.19.2/test/test-timer-from-check.c new file mode 100644 index 00000000..a18c7e1f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer.c b/3rd/libuv-1.19.2/test/test-timer.c new file mode 100644 index 00000000..080a7300 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-timer.c @@ -0,0 +1,330 @@ +/* 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; +} + + +static uint64_t timer_early_check_expected_time; + + +static void timer_early_check_cb(uv_timer_t* handle) { + uint64_t hrtime = uv_hrtime() / 1000000; + ASSERT(hrtime >= timer_early_check_expected_time); +} + + +TEST_IMPL(timer_early_check) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tmpdir.c b/3rd/libuv-1.19.2/test/test-tmpdir.c new file mode 100644 index 00000000..29e8055f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tmpdir.c @@ -0,0 +1,71 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tty.c b/3rd/libuv-1.19.2/test/test-tty.c new file mode 100644 index 00000000..e761822f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tty.c @@ -0,0 +1,390 @@ +/* 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 +# include +#else /* Unix */ +# include +# include +# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) +# include +# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# include +# elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# endif +#endif + +#include +#include + + +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; +} + + +#ifdef _WIN32 +static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + +static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + ASSERT(nread == 1); + ASSERT(buf->base[0] == ' '); + uv_close((uv_handle_t*) tty_in, NULL); + } else { + ASSERT(nread == 0); + } +} + +TEST_IMPL(tty_raw) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop = uv_default_loop(); + HANDLE handle; + INPUT_RECORD record; + DWORD written; + + /* Make sure we have an FD that refers to a tty */ + 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); + ASSERT(ttyin_fd >= 0); + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ + Sleep(100); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); + ASSERT(r == 0); + + /* Write ' ' that should be read in raw mode */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; + record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L' '; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle, &record, 1, &written); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tty_empty_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[1]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + 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); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + bufs[0].len = 0; + bufs[0].base = &dummy[0]; + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tty_large_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[10000]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + 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); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + memset(dummy, '.', sizeof(dummy) - 1); + dummy[sizeof(dummy) - 1] = '\n'; + + bufs[0] = uv_buf_init(dummy, sizeof(dummy)); + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 10000); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +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; +} + +TEST_IMPL(tty_pty) { +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + (defined(__linux__) && !defined(__ANDROID__)) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) + int master_fd, slave_fd, r; + struct winsize w; + uv_loop_t loop; + uv_tty_t master_tty, slave_tty; + + ASSERT(0 == uv_loop_init(&loop)); + + r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); + if (r != 0) + RETURN_SKIP("No pty available, skipping."); + + ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + /* Check if the file descriptor was reopened. If it is, + * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + */ + ASSERT(0 == (slave_tty.flags & 0x80)); + /* The master_fd of a pty should never be reopened. + */ + ASSERT(master_tty.flags & 0x80); + ASSERT(0 == close(slave_fd)); + uv_close((uv_handle_t*) &slave_tty, NULL); + ASSERT(0 == close(master_fd)); + uv_close((uv_handle_t*) &master_tty, NULL); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); +#endif + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c new file mode 100644 index 00000000..05b871e9 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c @@ -0,0 +1,197 @@ +/* Copyright libuv project 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 +#include +#include + +#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 sv_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 cl_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* Do nothing, recv_cb should be called with UV_ENOBUFS. */ +} + + +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); + ASSERT(nread == UV_ENOBUFS); + + 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, cl_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)); + + 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_alloc_cb_fail) { + 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, sv_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("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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-bind.c b/3rd/libuv-1.19.2/test/test-udp-bind.c new file mode 100644 index 00000000..a1e080ee --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c new file mode 100644 index 00000000..f7e46abc --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 + +#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; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + 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); +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) + 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/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c b/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c new file mode 100644 index 00000000..bd44c425 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-ipv6.c b/3rd/libuv-1.19.2/test/test-udp-ipv6.c new file mode 100644 index 00000000..00007918 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-ipv6.c @@ -0,0 +1,198 @@ +/* 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 +#include +#include + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#include +#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; + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +static int can_ipv6_ipv4_dual(void) { + 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 defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c new file mode 100644 index 00000000..0b3c0e62 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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 || status == UV_EPERM); + 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c new file mode 100644 index 00000000..40b05536 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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__) || defined(__FreeBSD_kernel__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-join.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join.c new file mode 100644 index 00000000..6110a8d9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c new file mode 100644 index 00000000..8814b5ad --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c @@ -0,0 +1,165 @@ +/* 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 +#include +#include + + +#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) || \ + defined(__MVS__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c b/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c new file mode 100644 index 00000000..e92608be --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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 || status == UV_EPERM); + 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/3rd/libuv-1.19.2/test/test-udp-open.c b/3rd/libuv-1.19.2/test/test-udp-open.c new file mode 100644 index 00000000..4d77f45d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#ifndef _WIN32 +# include +#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/3rd/libuv-1.19.2/test/test-udp-options.c b/3rd/libuv-1.19.2/test/test-udp-options.c new file mode 100644 index 00000000..8f913675 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-options.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 "uv.h" +#include "task.h" + +#include +#include +#include + + +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); +#if defined(__MVS__) + if (addr->sa_family == AF_INET6) + ASSERT(r == 0); + else + ASSERT(r == UV_ENOTSUP); +#else + ASSERT(r == 0); +#endif + } + + 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)); +#if defined(__MVS__) + ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); +#else + ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); +#endif + 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/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c b/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c new file mode 100644 index 00000000..633a1672 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c b/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c new file mode 100644 index 00000000..bf4dfebf --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c @@ -0,0 +1,99 @@ +/* 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 +#include +#include + +#define CHECK_OBJECT(handle, type, parent) \ + ASSERT((type*)(handle) == &(parent)) + +static uv_udp_t client; +static uv_idle_t idle_handle; +static uv_udp_send_t send_req; +static uv_buf_t buf; +static struct sockaddr_in addr; +static char send_data[1024]; + +static int loop_hang_called; + +static void send_cb(uv_udp_send_t* req, int status); + + +static void idle_cb(uv_idle_t* handle) { + int r; + + ASSERT(send_req.handle == NULL); + CHECK_OBJECT(handle, uv_idle_t, idle_handle); + ASSERT(0 == uv_idle_stop(handle)); + + /* It probably would have stalled by now if it's going to stall at all. */ + if (++loop_hang_called > 1000) { + uv_close((uv_handle_t*) &client, NULL); + uv_close((uv_handle_t*) &idle_handle, NULL); + return; + } + + r = uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0 || status == UV_ENETUNREACH); + CHECK_OBJECT(req->handle, uv_udp_t, client); + CHECK_OBJECT(req, uv_udp_send_t, send_req); + req->handle = NULL; + + ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); +} + + +TEST_IMPL(udp_send_hang_loop) { + ASSERT(0 == uv_idle_init(uv_default_loop(), &idle_handle)); + + /* 192.0.2.0/8 is "TEST-NET" and reserved for documentation. + * Good for us, though. Since we want to have something unreachable. + */ + ASSERT(0 == uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); + + ASSERT(0 == uv_udp_init(uv_default_loop(), &client)); + + buf = uv_buf_init(send_data, sizeof(send_data)); + + ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(loop_hang_called > 1000); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-send-immediate.c b/3rd/libuv-1.19.2/test/test-udp-send-immediate.c new file mode 100644 index 00000000..215f7225 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-send-immediate.c @@ -0,0 +1,149 @@ +/* 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 +#include +#include + +#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); + ASSERT(r == 0); + + 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/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c b/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c new file mode 100644 index 00000000..c6500320 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-try-send.c b/3rd/libuv-1.19.2/test/test-udp-try-send.c new file mode 100644 index 00000000..a31d3822 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-try-send.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 +#include +#include + +#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; +} diff --git a/3rd/libuv-1.19.2/test/test-walk-handles.c b/3rd/libuv-1.19.2/test/test-walk-handles.c new file mode 100644 index 00000000..4b0ca6eb --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c b/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c new file mode 100644 index 00000000..29a82a5c --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-watcher-cross-stop.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 +#include + +/* NOTE: Number should be big enough to trigger this problem */ +#if defined(__CYGWIN__) || defined(__MSYS__) +/* Cygwin crashes or hangs in socket() with too many AF_INET sockets. */ +static uv_udp_t sockets[1250]; +#else +static uv_udp_t sockets[2500]; +#endif +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) { +#if defined(__MVS__) + RETURN_SKIP("zOS does not allow address or port reuse when using UDP sockets"); +#endif + 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/3rd/libuv-1.19.2/test/test.gyp b/3rd/libuv-1.19.2/test/test.gyp new file mode 100644 index 00000000..480e5a26 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test.gyp @@ -0,0 +1,279 @@ +{ + 'targets': [ + { + 'target_name': 'run-tests', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'blackhole-server.c', + 'echo-server.c', + 'run-tests.c', + 'runner.c', + 'runner.h', + 'test-get-loadavg.c', + 'task.h', + 'test-active.c', + 'test-async.c', + 'test-async-null-cb.c', + 'test-callback-stack.c', + 'test-callback-order.c', + 'test-close-fd.c', + 'test-close-order.c', + 'test-connect-unspecified.c', + 'test-connection-fail.c', + 'test-cwd-and-chdir.c', + 'test-default-loop-close.c', + 'test-delayed-accept.c', + 'test-eintr-handling.c', + 'test-error.c', + 'test-embed.c', + 'test-emfile.c', + 'test-env-vars.c', + 'test-fail-always.c', + 'test-fork.c', + 'test-fs.c', + 'test-fs-copyfile.c', + 'test-fs-event.c', + 'test-getters-setters.c', + 'test-get-currentexe.c', + 'test-get-memory.c', + 'test-get-passwd.c', + 'test-getaddrinfo.c', + 'test-gethostname.c', + 'test-getnameinfo.c', + 'test-getsockname.c', + 'test-handle-fileno.c', + 'test-homedir.c', + 'test-hrtime.c', + 'test-idle.c', + 'test-ip6-addr.c', + 'test-ipc.c', + 'test-ipc-send-recv.c', + 'test-list.h', + 'test-loop-handles.c', + 'test-loop-alive.c', + 'test-loop-close.c', + 'test-loop-stop.c', + 'test-loop-time.c', + 'test-loop-configure.c', + 'test-walk-handles.c', + 'test-watcher-cross-stop.c', + 'test-multiple-listen.c', + 'test-osx-select.c', + 'test-pass-always.c', + 'test-ping-pong.c', + 'test-pipe-bind-error.c', + 'test-pipe-connect-error.c', + 'test-pipe-connect-multiple.c', + 'test-pipe-connect-prepare.c', + 'test-pipe-getsockname.c', + 'test-pipe-pending-instances.c', + 'test-pipe-sendmsg.c', + 'test-pipe-server-close.c', + 'test-pipe-close-stdout-read-stdin.c', + 'test-pipe-set-non-blocking.c', + 'test-pipe-set-fchmod.c', + 'test-platform-output.c', + 'test-poll.c', + 'test-poll-close.c', + 'test-poll-close-doesnt-corrupt-stack.c', + 'test-poll-closesocket.c', + 'test-poll-oob.c', + 'test-process-title.c', + 'test-process-title-threadsafe.c', + 'test-queue-foreach-delete.c', + 'test-ref.c', + 'test-run-nowait.c', + 'test-run-once.c', + 'test-semaphore.c', + 'test-shutdown-close.c', + 'test-shutdown-eof.c', + 'test-shutdown-twice.c', + 'test-signal.c', + 'test-signal-multiple-loops.c', + 'test-socket-buffer-size.c', + 'test-spawn.c', + 'test-fs-poll.c', + 'test-stdio-over-pipes.c', + 'test-tcp-alloc-cb-fail.c', + 'test-tcp-bind-error.c', + 'test-tcp-bind6-error.c', + 'test-tcp-close.c', + 'test-tcp-close-accept.c', + 'test-tcp-close-while-connecting.c', + 'test-tcp-create-socket-early.c', + 'test-tcp-connect-error-after-write.c', + 'test-tcp-shutdown-after-write.c', + 'test-tcp-flags.c', + 'test-tcp-connect-error.c', + 'test-tcp-connect-timeout.c', + 'test-tcp-connect6-error.c', + 'test-tcp-open.c', + 'test-tcp-write-to-half-open-connection.c', + 'test-tcp-write-after-connect.c', + 'test-tcp-writealot.c', + 'test-tcp-write-fail.c', + 'test-tcp-try-write.c', + 'test-tcp-unexpected-read.c', + 'test-tcp-oob.c', + 'test-tcp-read-stop.c', + 'test-tcp-write-queue-order.c', + 'test-threadpool.c', + 'test-threadpool-cancel.c', + 'test-thread-equal.c', + 'test-tmpdir.c', + 'test-mutexes.c', + 'test-thread.c', + 'test-barrier.c', + 'test-condvar.c', + 'test-timer-again.c', + 'test-timer-from-check.c', + 'test-timer.c', + 'test-tty.c', + 'test-udp-alloc-cb-fail.c', + 'test-udp-bind.c', + 'test-udp-create-socket-early.c', + 'test-udp-dgram-too-big.c', + 'test-udp-ipv6.c', + 'test-udp-open.c', + 'test-udp-options.c', + 'test-udp-send-and-recv.c', + 'test-udp-send-hang-loop.c', + 'test-udp-send-immediate.c', + 'test-udp-send-unreachable.c', + 'test-udp-multicast-join.c', + 'test-udp-multicast-join6.c', + 'test-dlerror.c', + 'test-udp-multicast-ttl.c', + 'test-ip4-addr.c', + 'test-ip6-addr.c', + 'test-udp-multicast-interface.c', + 'test-udp-multicast-interface6.c', + 'test-udp-try-send.c', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ], + 'conditions': [ + [ 'OS != "zos"', { + 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], + 'xcode_settings': { + 'WARNING_CFLAGS': [ '-Wno-long-long' ] + } + }], + ]}, + ], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], + [ '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', + ], + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + + { + 'target_name': 'run-benchmarks', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'benchmark-async.c', + 'benchmark-async-pummel.c', + 'benchmark-fs-stat.c', + 'benchmark-getaddrinfo.c', + 'benchmark-list.h', + 'benchmark-loop-count.c', + 'benchmark-million-async.c', + 'benchmark-million-timers.c', + 'benchmark-multi-accept.c', + 'benchmark-ping-pongs.c', + 'benchmark-pound.c', + 'benchmark-pump.c', + 'benchmark-sizes.c', + 'benchmark-spawn.c', + 'benchmark-thread.c', + 'benchmark-tcp-write-batch.c', + 'benchmark-udp-pummel.c', + 'dns-server.c', + 'echo-server.c', + 'blackhole-server.c', + 'run-benchmarks.c', + 'runner.c', + 'runner.h', + 'task.h', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'defines': [ '_GNU_SOURCE' ], + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ] + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + ], +} diff --git a/3rd/libuv-1.19.2/tools/make_dist_html.py b/3rd/libuv-1.19.2/tools/make_dist_html.py new file mode 100644 index 00000000..7a19d3e1 --- /dev/null +++ b/3rd/libuv-1.19.2/tools/make_dist_html.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +from __future__ import print_function + +import itertools +import os +import re +import subprocess + +HTML = r''' + + + + + + + + + {groups}
+ + +''' + +GROUPS = r''' + + {groups[0]} + {groups[1]} + {groups[2]} + {groups[3]} + +''' + +GROUP = r''' + + + + + + + + {rows} +
versiontarballgpgwindows
+''' + +ROW = r''' + + +
{tag} + + + tarball + + {maybe_gpg} + {maybe_exe} + +''' + +GPG = r''' +gpg +''' + +# The binaries don't have a predictable name, link to the directory instead. +EXE = r''' +exe +''' + +def version(tag): + return map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups()) + +def major_minor(tag): + return version(tag)[:2] + +def row_for(tag): + maybe_gpg = '' + maybe_exe = '' + # We didn't start signing releases and producing Windows installers + # until v1.7.0. + if version(tag) >= version('v1.7.0'): + maybe_gpg = GPG.format(**locals()) + maybe_exe = EXE.format(**locals()) + return ROW.format(**locals()) + +def group_for(tags): + rows = ''.join(row_for(tag) for tag in tags) + return GROUP.format(rows=rows) + +# Partition in groups of |n|. +def groups_for(groups, n=4): + html = '' + groups = groups[:] + [''] * (n - 1) + while len(groups) >= n: + html += GROUPS.format(groups=groups) + groups = groups[n:] + return html + +if __name__ == '__main__': + os.chdir(os.path.dirname(__file__)) + tags = subprocess.check_output(['git', 'tag']) + tags = [tag for tag in tags.split('\n') if tag.startswith('v')] + tags.sort(key=version, reverse=True) + groups = [group_for(list(g)) for _, g in itertools.groupby(tags, major_minor)] + groups = groups_for(groups) + html = HTML.format(groups=groups).strip() + html = re.sub('>\\s+<', '><', html) + print(html) diff --git a/3rd/libuv-1.19.2/uv.gyp b/3rd/libuv-1.19.2/uv.gyp new file mode 100644 index 00000000..a5046b87 --- /dev/null +++ b/3rd/libuv-1.19.2/uv.gyp @@ -0,0 +1,355 @@ +{ + 'variables': { + 'conditions': [ + ['OS=="win"', { + 'shared_unix_defines': [ + '_LARGEFILE_SOURCE', + '_FILE_OFFSET_BITS=64', + ], + }, { + 'shared_unix_defines': [ ], + }], + ['OS in "mac ios"', { + 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], + }, { + 'shared_mac_defines': [ ], + }], + ['OS=="zos"', { + 'shared_zos_defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_UNIX03_WITHDRAWN', + '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_IPV6', + '_OPEN_MSGQ_EXT', + '_XOPEN_SOURCE_EXTENDED', + '_ALL_SOURCE', + '_LARGE_TIME_API', + '_OPEN_SYS_FILE_EXT', + '_AE_BIMODAL', + 'PATH_MAX=255' + ], + }, { + 'shared_zos_defines': [ ], + }], + ], + }, + + 'targets': [ + { + 'target_name': 'libuv', + 'type': '<(uv_library)', + 'include_dirs': [ + 'include', + 'src/', + ], + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], + 'direct_dependent_settings': { + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], + 'include_dirs': [ 'include' ], + 'conditions': [ + ['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-data-getter-setters.c', + 'src/uv-common.c', + 'src/uv-common.h', + 'src/version.c' + ], + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'WARNING_CFLAGS': [ + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], + }, + '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/detect-wakeup.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/snprintf.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', + ], + 'link_settings': { + 'libraries': [ + '-ladvapi32', + '-liphlpapi', + '-lpsapi', + '-lshell32', + '-luser32', + '-luserenv', + '-lws2_32' + ], + }, + }, { # Not Windows i.e. POSIX + '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=="zos" and uv_library=="shared_library"', { + 'ldflags': [ '-Wl,DLL' ], + }], + ['OS != "solaris" and OS != "android" and OS != "zos"', { + 'ldflags': [ '-pthread' ], + }], + ], + }, + 'conditions': [ + ['uv_library=="shared_library"', { + 'conditions': [ + ['OS=="zos"', { + 'cflags': [ '-qexportall' ], + }, { + 'cflags': [ '-fPIC' ], + }], + ], + }], + ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { + # 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 zos"', { + 'sources': [ 'src/unix/proctitle.c' ], + }], + [ 'OS != "zos"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + }], + [ '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=="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', + 'src/unix/procfs-exepath.c', + 'src/unix/sysinfo-loadavg.c', + 'src/unix/sysinfo-memory.c', + ], + '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', + 'src/unix/procfs-exepath.c', + 'src/unix/sysinfo-loadavg.c', + 'src/unix/sysinfo-memory.c', + ], + 'link_settings': { + 'libraries': [ '-ldl' ], + }, + }], + [ 'OS=="solaris"', { + 'sources': [ + 'src/unix/no-proctitle.c', + 'src/unix/sunos.c', + ], + 'defines': [ + '__EXTENSIONS__', + '_XOPEN_SOURCE=500', + ], + 'link_settings': { + 'libraries': [ + '-lkstat', + '-lnsl', + '-lsendfile', + '-lsocket', + ], + }, + }], + [ 'OS=="aix"', { + 'variables': { + 'os_name': ' Date: Fri, 16 Mar 2018 21:43:58 +0800 Subject: [PATCH 02/11] add win libuv --- 3rd/libuv-1.19.2/libuv.vcxproj | 217 +++++++++++++++++++++++++++++++++ 3rd/libuv-1.19.2/src/win/tty.c | 4 +- 3rd/libuv-1.19.2/stdafx.cpp | Bin 0 -> 586 bytes 3rd/libuv-1.19.2/stdafx.h | Bin 0 -> 736 bytes 3rd/libuv-1.19.2/targetver.h | Bin 0 -> 630 bytes 3rd/libuv.sln | 31 +++++ 6 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 3rd/libuv-1.19.2/libuv.vcxproj create mode 100644 3rd/libuv-1.19.2/stdafx.cpp create mode 100644 3rd/libuv-1.19.2/stdafx.h create mode 100644 3rd/libuv-1.19.2/targetver.h create mode 100644 3rd/libuv.sln diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv-1.19.2/libuv.vcxproj new file mode 100644 index 00000000..d15ee945 --- /dev/null +++ b/3rd/libuv-1.19.2/libuv.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41} + Win32Proj + libuv + 10.0.16299.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectDir)\include;$(ProjectDir)\src;$(IncludePath) + + + true + + + false + $(ProjectDir)\include;$(ProjectDir)\src;$(IncludePath) + + + false + + + + NotUsing + Level3 + Disabled + true + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + ../include + + + Windows + true + + + + + Use + Level3 + Disabled + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + true + ../include + + + Windows + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/win/tty.c b/3rd/libuv-1.19.2/src/win/tty.c index 05a11e88..c822431e 100644 --- a/3rd/libuv-1.19.2/src/win/tty.c +++ b/3rd/libuv-1.19.2/src/win/tty.c @@ -320,8 +320,8 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { 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; + uv_alloc_cb alloc_cb = NULL; + uv_read_cb read_cb = NULL; int err; if (!(tty->flags & UV_HANDLE_TTY_READABLE)) { diff --git a/3rd/libuv-1.19.2/stdafx.cpp b/3rd/libuv-1.19.2/stdafx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b229caa6bec1b2d6a1f924a89ba58c5712cda48 GIT binary patch literal 586 zcmZ{iK~IA~6olt&;(s7|*519D7~{=@J$R)8VH*TOsmh;Mzu8SeG^W|^?%Vff=FQ{l zbEAzi9W<&?u1X)e){A<6nQr1sr=td9CAUgJO+1aN$sdUYwY)ZD6}%jX>^U1TW7RR+ zx12n44E+DCI@cLWtfc{Q2f`aldXQ^k?~%9Rw42$jrw6Un6MN*)C8}!xT2zdK#83R5zE|Om+^h^DbvL-*J~oD?Bv8&kGf-d z4(_vJdAHwYw4+np3px!mXO4$!2RxMtJxBJI+H#&jrYCJ-xz)X%as1(jTWMmh=)g`L NCQm|~^XY4_>Td)>WN82Z literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/stdafx.h b/3rd/libuv-1.19.2/stdafx.h new file mode 100644 index 0000000000000000000000000000000000000000..b642ffd7561e1b2e1b298f3df787d6071939e14f GIT binary patch literal 736 zcmaJn-A*y9?P zxFEOKJFFcMBHoFgQH_vxwyumfJB#L+v7rX#Nr}|9Ldc_N7?D|h)DD0N%ka4AIfEfw0WxN;+co0fK2Vs4B9U*sm0{`t1wOo&Foy0~*EXI^K{ z&F{}p2USW{Xp2p>*G`#oJ!s%(q!H-M(Ty4fmG}kNtEQTB%)V1m=}BwwfWPvrT#@e@ zH0NG}74Ao{glS)#QXA|NYdIfY7hrMp+Ji@H`t9kzWx_SD6;~Ri;cvXH)6CO{-I1p_IJPQ#X=r zigZeSqQguJz35q;zt9^Q_C^^>*mmuXUCp&pw^fPoGX+dho4RCrySs7j@9_UipWkA5 OQDt4mH~x-^Z~X_?9czaG literal 0 HcmV?d00001 diff --git a/3rd/libuv.sln b/3rd/libuv.sln new file mode 100644 index 00000000..3799c90d --- /dev/null +++ b/3rd/libuv.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2002 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv-1.19.2\libuv.vcxproj", "{DF6C5660-6B48-4E4A-BF98-E1739CA83E41}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Debug|x64.ActiveCfg = Debug|x64 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Debug|x64.Build.0 = Debug|x64 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Debug|x86.ActiveCfg = Debug|Win32 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Debug|x86.Build.0 = Debug|Win32 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Release|x64.ActiveCfg = Release|x64 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Release|x64.Build.0 = Release|x64 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Release|x86.ActiveCfg = Release|Win32 + {DF6C5660-6B48-4E4A-BF98-E1739CA83E41}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F89194FD-55E3-4AEF-98D6-25E2E5AD8012} + EndGlobalSection +EndGlobal -- Gitee From 2b460d0a010f66dd7d6aa4c8b6819a45b4afacbf Mon Sep 17 00:00:00 2001 From: thinking Date: Sat, 17 Mar 2018 04:39:07 +0800 Subject: [PATCH 03/11] del error libuv --- 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md | 10 - 3rd/libuv-1.19.2/.gitignore | 79 - 3rd/libuv-1.19.2/.mailmap | 46 - 3rd/libuv-1.19.2/AUTHORS | 332 -- 3rd/libuv-1.19.2/CONTRIBUTING.md | 169 - 3rd/libuv-1.19.2/ChangeLog | 3531 ------------ 3rd/libuv-1.19.2/LICENSE | 70 - 3rd/libuv-1.19.2/LICENSE-docs | 396 -- 3rd/libuv-1.19.2/MAINTAINERS.md | 43 - 3rd/libuv-1.19.2/Makefile.am | 468 -- 3rd/libuv-1.19.2/Makefile.mingw | 86 - 3rd/libuv-1.19.2/README.md | 332 -- 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md | 73 - 3rd/libuv-1.19.2/android-configure | 23 - 3rd/libuv-1.19.2/appveyor.yml | 32 - 3rd/libuv-1.19.2/autogen.sh | 46 - 3rd/libuv-1.19.2/checksparse.sh | 253 - 3rd/libuv-1.19.2/common.gypi | 208 - 3rd/libuv-1.19.2/configure.ac | 72 - 3rd/libuv-1.19.2/docs/code/cgi/main.c | 81 - 3rd/libuv-1.19.2/docs/code/cgi/tick.c | 13 - 3rd/libuv-1.19.2/docs/code/detach/main.c | 31 - 3rd/libuv-1.19.2/docs/code/dns/main.c | 80 - 3rd/libuv-1.19.2/docs/code/helloworld/main.c | 15 - 3rd/libuv-1.19.2/docs/code/idle-basic/main.c | 24 - .../docs/code/idle-compute/main.c | 43 - 3rd/libuv-1.19.2/docs/code/interfaces/main.c | 33 - 3rd/libuv-1.19.2/docs/code/locks/main.c | 57 - .../docs/code/multi-echo-server/hammer.js | 20 - .../docs/code/multi-echo-server/main.c | 114 - .../docs/code/multi-echo-server/worker.c | 88 - 3rd/libuv-1.19.2/docs/code/onchange/main.c | 44 - .../docs/code/pipe-echo-server/main.c | 94 - 3rd/libuv-1.19.2/docs/code/plugin/hello.c | 5 - 3rd/libuv-1.19.2/docs/code/plugin/main.c | 39 - 3rd/libuv-1.19.2/docs/code/plugin/plugin.h | 7 - .../docs/code/proc-streams/main.c | 49 - .../docs/code/proc-streams/test.c | 8 - 3rd/libuv-1.19.2/docs/code/progress/main.c | 47 - .../docs/code/queue-cancel/main.c | 59 - 3rd/libuv-1.19.2/docs/code/queue-work/main.c | 44 - 3rd/libuv-1.19.2/docs/code/ref-timer/main.c | 29 - 3rd/libuv-1.19.2/docs/code/signal/main.c | 66 - 3rd/libuv-1.19.2/docs/code/spawn/main.c | 36 - .../docs/code/tcp-echo-server/main.c | 87 - .../docs/code/thread-create/main.c | 36 - 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c | 48 - 3rd/libuv-1.19.2/docs/code/tty/main.c | 29 - 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c | 127 - 3rd/libuv-1.19.2/docs/code/uvcat/main.c | 63 - 3rd/libuv-1.19.2/docs/code/uvstop/main.c | 33 - 3rd/libuv-1.19.2/docs/code/uvtee/main.c | 80 - 3rd/libuv-1.19.2/docs/code/uvwget/main.c | 166 - 3rd/libuv-1.19.2/docs/make.bat | 243 - 3rd/libuv-1.19.2/docs/src/api.rst | 35 - 3rd/libuv-1.19.2/docs/src/async.rst | 61 - 3rd/libuv-1.19.2/docs/src/check.rst | 46 - 3rd/libuv-1.19.2/docs/src/conf.py | 348 -- 3rd/libuv-1.19.2/docs/src/design.rst | 138 - 3rd/libuv-1.19.2/docs/src/dll.rst | 44 - 3rd/libuv-1.19.2/docs/src/dns.rst | 108 - 3rd/libuv-1.19.2/docs/src/errors.rst | 344 -- 3rd/libuv-1.19.2/docs/src/fs.rst | 538 -- 3rd/libuv-1.19.2/docs/src/fs_event.rst | 132 - 3rd/libuv-1.19.2/docs/src/fs_poll.rst | 77 - 3rd/libuv-1.19.2/docs/src/guide.rst | 22 - 3rd/libuv-1.19.2/docs/src/guide/about.rst | 22 - 3rd/libuv-1.19.2/docs/src/guide/basics.rst | 188 - .../docs/src/guide/eventloops.rst | 48 - .../docs/src/guide/filesystem.rst | 287 - .../docs/src/guide/introduction.rst | 75 - .../docs/src/guide/networking.rst | 249 - 3rd/libuv-1.19.2/docs/src/guide/processes.rst | 389 -- 3rd/libuv-1.19.2/docs/src/guide/threads.rst | 381 -- 3rd/libuv-1.19.2/docs/src/guide/utilities.rst | 433 -- 3rd/libuv-1.19.2/docs/src/handle.rst | 264 - 3rd/libuv-1.19.2/docs/src/idle.rst | 54 - 3rd/libuv-1.19.2/docs/src/index.rst | 62 - 3rd/libuv-1.19.2/docs/src/loop.rst | 236 - .../docs/src/migration_010_100.rst | 244 - 3rd/libuv-1.19.2/docs/src/misc.rst | 519 -- 3rd/libuv-1.19.2/docs/src/pipe.rst | 113 - 3rd/libuv-1.19.2/docs/src/poll.rst | 121 - 3rd/libuv-1.19.2/docs/src/prepare.rst | 46 - 3rd/libuv-1.19.2/docs/src/process.rst | 231 - 3rd/libuv-1.19.2/docs/src/request.rst | 109 - 3rd/libuv-1.19.2/docs/src/signal.rst | 78 - .../docs/src/sphinx-plugins/manpage.py | 46 - .../docs/src/static/architecture.png | Bin 206767 -> 0 bytes .../src/static/diagrams.key/Data/st0-311.jpg | Bin 19328 -> 0 bytes .../src/static/diagrams.key/Data/st1-475.jpg | Bin 12655 -> 0 bytes .../docs/src/static/diagrams.key/Index.zip | Bin 71160 -> 0 bytes .../Metadata/BuildVersionHistory.plist | 8 - .../diagrams.key/Metadata/DocumentIdentifier | 1 - .../diagrams.key/Metadata/Properties.plist | Bin 340 -> 0 bytes .../src/static/diagrams.key/preview-micro.jpg | Bin 1425 -> 0 bytes .../src/static/diagrams.key/preview-web.jpg | Bin 8106 -> 0 bytes .../docs/src/static/diagrams.key/preview.jpg | Bin 107456 -> 0 bytes 3rd/libuv-1.19.2/docs/src/static/favicon.ico | Bin 15086 -> 0 bytes 3rd/libuv-1.19.2/docs/src/static/logo.png | Bin 33545 -> 0 bytes .../docs/src/static/loop_iteration.png | Bin 80528 -> 0 bytes 3rd/libuv-1.19.2/docs/src/stream.rst | 237 - 3rd/libuv-1.19.2/docs/src/tcp.rst | 115 - 3rd/libuv-1.19.2/docs/src/threading.rst | 168 - 3rd/libuv-1.19.2/docs/src/threadpool.rst | 67 - 3rd/libuv-1.19.2/docs/src/timer.rst | 81 - 3rd/libuv-1.19.2/docs/src/tty.rst | 101 - 3rd/libuv-1.19.2/docs/src/udp.rst | 314 -- 3rd/libuv-1.19.2/docs/src/upgrading.rst | 11 - 3rd/libuv-1.19.2/docs/src/version.rst | 60 - 3rd/libuv-1.19.2/gyp_uv.py | 73 - 3rd/libuv-1.19.2/img/banner.png | Bin 44102 -> 0 bytes 3rd/libuv-1.19.2/img/logos.svg | 152 - 3rd/libuv-1.19.2/include/android-ifaddrs.h | 54 - 3rd/libuv-1.19.2/include/pthread-barrier.h | 69 - 3rd/libuv-1.19.2/include/stdint-msvc2008.h | 247 - 3rd/libuv-1.19.2/include/tree.h | 768 --- 3rd/libuv-1.19.2/include/uv-aix.h | 32 - 3rd/libuv-1.19.2/include/uv-bsd.h | 34 - 3rd/libuv-1.19.2/include/uv-darwin.h | 61 - 3rd/libuv-1.19.2/include/uv-errno.h | 437 -- 3rd/libuv-1.19.2/include/uv-linux.h | 34 - 3rd/libuv-1.19.2/include/uv-os390.h | 33 - 3rd/libuv-1.19.2/include/uv-posix.h | 31 - 3rd/libuv-1.19.2/include/uv-sunos.h | 44 - 3rd/libuv-1.19.2/include/uv-threadpool.h | 37 - 3rd/libuv-1.19.2/include/uv-unix.h | 464 -- 3rd/libuv-1.19.2/include/uv-version.h | 43 - 3rd/libuv-1.19.2/include/uv-win.h | 676 --- 3rd/libuv-1.19.2/include/uv.h | 1567 ------ 3rd/libuv-1.19.2/libuv.pc.in | 12 - 3rd/libuv-1.19.2/libuv.vcxproj | 217 - 3rd/libuv-1.19.2/m4/.gitignore | 4 - 3rd/libuv-1.19.2/m4/as_case.m4 | 21 - 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 | 319 -- 3rd/libuv-1.19.2/samples/.gitignore | 22 - .../samples/socks5-proxy/.gitignore | 21 - 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE | 53 - .../samples/socks5-proxy/build.gyp | 46 - .../samples/socks5-proxy/client.c | 736 --- 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h | 139 - .../samples/socks5-proxy/getopt.c | 131 - 3rd/libuv-1.19.2/samples/socks5-proxy/main.c | 99 - 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c | 271 - 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h | 94 - .../samples/socks5-proxy/server.c | 241 - 3rd/libuv-1.19.2/samples/socks5-proxy/util.c | 72 - 3rd/libuv-1.19.2/src/fs-poll.c | 256 - 3rd/libuv-1.19.2/src/heap-inl.h | 245 - 3rd/libuv-1.19.2/src/inet.c | 309 -- 3rd/libuv-1.19.2/src/queue.h | 108 - 3rd/libuv-1.19.2/src/threadpool.c | 318 -- 3rd/libuv-1.19.2/src/unix/aix-common.c | 292 - 3rd/libuv-1.19.2/src/unix/aix.c | 1041 ---- 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c | 710 --- 3rd/libuv-1.19.2/src/unix/async.c | 269 - 3rd/libuv-1.19.2/src/unix/atomic-ops.h | 100 - 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c | 152 - 3rd/libuv-1.19.2/src/unix/core.c | 1355 ----- 3rd/libuv-1.19.2/src/unix/cygwin.c | 54 - 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c | 209 - 3rd/libuv-1.19.2/src/unix/darwin.c | 231 - 3rd/libuv-1.19.2/src/unix/dl.c | 80 - 3rd/libuv-1.19.2/src/unix/freebsd.c | 375 -- 3rd/libuv-1.19.2/src/unix/fs.c | 1513 ------ 3rd/libuv-1.19.2/src/unix/fsevents.c | 919 ---- 3rd/libuv-1.19.2/src/unix/getaddrinfo.c | 232 - 3rd/libuv-1.19.2/src/unix/getnameinfo.c | 120 - 3rd/libuv-1.19.2/src/unix/ibmi.c | 112 - 3rd/libuv-1.19.2/src/unix/internal.h | 340 -- 3rd/libuv-1.19.2/src/unix/kqueue.c | 533 -- 3rd/libuv-1.19.2/src/unix/linux-core.c | 951 ---- 3rd/libuv-1.19.2/src/unix/linux-inotify.c | 352 -- 3rd/libuv-1.19.2/src/unix/linux-syscalls.c | 471 -- 3rd/libuv-1.19.2/src/unix/linux-syscalls.h | 151 - 3rd/libuv-1.19.2/src/unix/loop-watcher.c | 68 - 3rd/libuv-1.19.2/src/unix/loop.c | 193 - 3rd/libuv-1.19.2/src/unix/netbsd.c | 309 -- 3rd/libuv-1.19.2/src/unix/no-fsevents.c | 42 - 3rd/libuv-1.19.2/src/unix/no-proctitle.c | 42 - 3rd/libuv-1.19.2/src/unix/openbsd.c | 313 -- 3rd/libuv-1.19.2/src/unix/os390-syscalls.c | 499 -- 3rd/libuv-1.19.2/src/unix/os390-syscalls.h | 72 - 3rd/libuv-1.19.2/src/unix/os390.c | 998 ---- 3rd/libuv-1.19.2/src/unix/pipe.c | 357 -- 3rd/libuv-1.19.2/src/unix/poll.c | 147 - 3rd/libuv-1.19.2/src/unix/posix-hrtime.c | 35 - 3rd/libuv-1.19.2/src/unix/posix-poll.c | 324 -- 3rd/libuv-1.19.2/src/unix/process.c | 599 --- 3rd/libuv-1.19.2/src/unix/procfs-exepath.c | 45 - 3rd/libuv-1.19.2/src/unix/proctitle.c | 132 - 3rd/libuv-1.19.2/src/unix/pthread-fixes.c | 56 - 3rd/libuv-1.19.2/src/unix/signal.c | 564 -- 3rd/libuv-1.19.2/src/unix/spinlock.h | 53 - 3rd/libuv-1.19.2/src/unix/stream.c | 1696 ------ 3rd/libuv-1.19.2/src/unix/sunos.c | 821 --- 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c | 36 - 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c | 42 - 3rd/libuv-1.19.2/src/unix/tcp.c | 444 -- 3rd/libuv-1.19.2/src/unix/thread.c | 729 --- 3rd/libuv-1.19.2/src/unix/timer.c | 172 - 3rd/libuv-1.19.2/src/unix/tty.c | 372 -- 3rd/libuv-1.19.2/src/unix/udp.c | 902 ---- 3rd/libuv-1.19.2/src/uv-common.c | 664 --- 3rd/libuv-1.19.2/src/uv-common.h | 260 - 3rd/libuv-1.19.2/src/uv-data-getter-setters.c | 96 - 3rd/libuv-1.19.2/src/version.c | 45 - 3rd/libuv-1.19.2/src/win/async.c | 98 - 3rd/libuv-1.19.2/src/win/atomicops-inl.h | 57 - 3rd/libuv-1.19.2/src/win/core.c | 605 --- 3rd/libuv-1.19.2/src/win/detect-wakeup.c | 35 - 3rd/libuv-1.19.2/src/win/dl.c | 133 - 3rd/libuv-1.19.2/src/win/error.c | 171 - 3rd/libuv-1.19.2/src/win/fs-event.c | 561 -- 3rd/libuv-1.19.2/src/win/fs.c | 2426 --------- 3rd/libuv-1.19.2/src/win/getaddrinfo.c | 453 -- 3rd/libuv-1.19.2/src/win/getnameinfo.c | 149 - 3rd/libuv-1.19.2/src/win/handle-inl.h | 179 - 3rd/libuv-1.19.2/src/win/handle.c | 159 - 3rd/libuv-1.19.2/src/win/internal.h | 394 -- 3rd/libuv-1.19.2/src/win/loop-watcher.c | 122 - 3rd/libuv-1.19.2/src/win/pipe.c | 2214 -------- 3rd/libuv-1.19.2/src/win/poll.c | 644 --- 3rd/libuv-1.19.2/src/win/process-stdio.c | 511 -- 3rd/libuv-1.19.2/src/win/process.c | 1272 ----- 3rd/libuv-1.19.2/src/win/req-inl.h | 221 - 3rd/libuv-1.19.2/src/win/req.c | 25 - 3rd/libuv-1.19.2/src/win/signal.c | 277 - 3rd/libuv-1.19.2/src/win/snprintf.c | 42 - 3rd/libuv-1.19.2/src/win/stream-inl.h | 54 - 3rd/libuv-1.19.2/src/win/stream.c | 248 - 3rd/libuv-1.19.2/src/win/tcp.c | 1525 ------ 3rd/libuv-1.19.2/src/win/thread.c | 703 --- 3rd/libuv-1.19.2/src/win/timer.c | 195 - 3rd/libuv-1.19.2/src/win/tty.c | 2328 -------- 3rd/libuv-1.19.2/src/win/udp.c | 965 ---- 3rd/libuv-1.19.2/src/win/util.c | 1581 ------ 3rd/libuv-1.19.2/src/win/winapi.c | 169 - 3rd/libuv-1.19.2/src/win/winapi.h | 4778 ----------------- 3rd/libuv-1.19.2/src/win/winsock.c | 591 -- 3rd/libuv-1.19.2/src/win/winsock.h | 193 - 3rd/libuv-1.19.2/stdafx.cpp | Bin 586 -> 0 bytes 3rd/libuv-1.19.2/stdafx.h | Bin 736 -> 0 bytes 3rd/libuv-1.19.2/targetver.h | Bin 630 -> 0 bytes .../test/benchmark-async-pummel.c | 119 - 3rd/libuv-1.19.2/test/benchmark-async.c | 141 - 3rd/libuv-1.19.2/test/benchmark-fs-stat.c | 136 - 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c | 92 - 3rd/libuv-1.19.2/test/benchmark-list.h | 163 - 3rd/libuv-1.19.2/test/benchmark-loop-count.c | 92 - .../test/benchmark-million-async.c | 112 - .../test/benchmark-million-timers.c | 86 - .../test/benchmark-multi-accept.c | 447 -- 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c | 221 - 3rd/libuv-1.19.2/test/benchmark-pound.c | 351 -- 3rd/libuv-1.19.2/test/benchmark-pump.c | 476 -- 3rd/libuv-1.19.2/test/benchmark-sizes.c | 46 - 3rd/libuv-1.19.2/test/benchmark-spawn.c | 164 - .../test/benchmark-tcp-write-batch.c | 144 - 3rd/libuv-1.19.2/test/benchmark-thread.c | 64 - 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c | 243 - 3rd/libuv-1.19.2/test/blackhole-server.c | 121 - 3rd/libuv-1.19.2/test/dns-server.c | 340 -- 3rd/libuv-1.19.2/test/echo-server.c | 378 -- 3rd/libuv-1.19.2/test/fixtures/empty_file | 0 .../test/fixtures/load_error.node | 1 - 3rd/libuv-1.19.2/test/run-benchmarks.c | 65 - 3rd/libuv-1.19.2/test/run-tests.c | 204 - 3rd/libuv-1.19.2/test/runner-unix.c | 400 -- 3rd/libuv-1.19.2/test/runner-unix.h | 36 - 3rd/libuv-1.19.2/test/runner-win.c | 351 -- 3rd/libuv-1.19.2/test/runner-win.h | 39 - 3rd/libuv-1.19.2/test/runner.c | 434 -- 3rd/libuv-1.19.2/test/runner.h | 177 - 3rd/libuv-1.19.2/test/task.h | 232 - 3rd/libuv-1.19.2/test/test-active.c | 84 - 3rd/libuv-1.19.2/test/test-async-null-cb.c | 64 - 3rd/libuv-1.19.2/test/test-async.c | 134 - 3rd/libuv-1.19.2/test/test-barrier.c | 106 - 3rd/libuv-1.19.2/test/test-callback-order.c | 77 - 3rd/libuv-1.19.2/test/test-callback-stack.c | 205 - 3rd/libuv-1.19.2/test/test-close-fd.c | 76 - 3rd/libuv-1.19.2/test/test-close-order.c | 80 - 3rd/libuv-1.19.2/test/test-condvar.c | 245 - .../test/test-connect-unspecified.c | 61 - 3rd/libuv-1.19.2/test/test-connection-fail.c | 151 - 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c | 51 - .../test/test-default-loop-close.c | 59 - 3rd/libuv-1.19.2/test/test-delayed-accept.c | 189 - 3rd/libuv-1.19.2/test/test-dlerror.c | 57 - 3rd/libuv-1.19.2/test/test-eintr-handling.c | 94 - 3rd/libuv-1.19.2/test/test-embed.c | 139 - 3rd/libuv-1.19.2/test/test-emfile.c | 117 - 3rd/libuv-1.19.2/test/test-env-vars.c | 90 - 3rd/libuv-1.19.2/test/test-error.c | 73 - 3rd/libuv-1.19.2/test/test-fail-always.c | 29 - 3rd/libuv-1.19.2/test/test-fork.c | 681 --- 3rd/libuv-1.19.2/test/test-fs-copyfile.c | 173 - 3rd/libuv-1.19.2/test/test-fs-event.c | 1051 ---- 3rd/libuv-1.19.2/test/test-fs-poll.c | 187 - 3rd/libuv-1.19.2/test/test-fs.c | 3174 ----------- 3rd/libuv-1.19.2/test/test-get-currentexe.c | 86 - 3rd/libuv-1.19.2/test/test-get-loadavg.c | 35 - 3rd/libuv-1.19.2/test/test-get-memory.c | 38 - 3rd/libuv-1.19.2/test/test-get-passwd.c | 86 - 3rd/libuv-1.19.2/test/test-getaddrinfo.c | 191 - 3rd/libuv-1.19.2/test/test-gethostname.c | 62 - 3rd/libuv-1.19.2/test/test-getnameinfo.c | 101 - 3rd/libuv-1.19.2/test/test-getsockname.c | 361 -- 3rd/libuv-1.19.2/test/test-getters-setters.c | 88 - 3rd/libuv-1.19.2/test/test-handle-fileno.c | 121 - 3rd/libuv-1.19.2/test/test-homedir.c | 72 - 3rd/libuv-1.19.2/test/test-hrtime.c | 54 - 3rd/libuv-1.19.2/test/test-idle.c | 99 - 3rd/libuv-1.19.2/test/test-ip4-addr.c | 46 - 3rd/libuv-1.19.2/test/test-ip6-addr.c | 162 - 3rd/libuv-1.19.2/test/test-ipc-send-recv.c | 428 -- 3rd/libuv-1.19.2/test/test-ipc.c | 887 --- 3rd/libuv-1.19.2/test/test-list.h | 905 ---- 3rd/libuv-1.19.2/test/test-loop-alive.c | 67 - 3rd/libuv-1.19.2/test/test-loop-close.c | 75 - 3rd/libuv-1.19.2/test/test-loop-configure.c | 38 - 3rd/libuv-1.19.2/test/test-loop-handles.c | 337 -- 3rd/libuv-1.19.2/test/test-loop-stop.c | 71 - 3rd/libuv-1.19.2/test/test-loop-time.c | 63 - 3rd/libuv-1.19.2/test/test-multiple-listen.c | 109 - 3rd/libuv-1.19.2/test/test-mutexes.c | 182 - 3rd/libuv-1.19.2/test/test-osx-select.c | 140 - 3rd/libuv-1.19.2/test/test-pass-always.c | 28 - 3rd/libuv-1.19.2/test/test-ping-pong.c | 274 - 3rd/libuv-1.19.2/test/test-pipe-bind-error.c | 139 - .../test/test-pipe-close-stdout-read-stdin.c | 107 - .../test/test-pipe-connect-error.c | 95 - .../test/test-pipe-connect-multiple.c | 107 - .../test/test-pipe-connect-prepare.c | 83 - 3rd/libuv-1.19.2/test/test-pipe-getsockname.c | 266 - .../test/test-pipe-pending-instances.c | 59 - 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c | 172 - .../test/test-pipe-server-close.c | 94 - 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c | 66 - .../test/test-pipe-set-non-blocking.c | 99 - 3rd/libuv-1.19.2/test/test-platform-output.c | 157 - .../test-poll-close-doesnt-corrupt-stack.c | 116 - 3rd/libuv-1.19.2/test/test-poll-close.c | 73 - 3rd/libuv-1.19.2/test/test-poll-closesocket.c | 93 - 3rd/libuv-1.19.2/test/test-poll-oob.c | 205 - 3rd/libuv-1.19.2/test/test-poll.c | 665 --- .../test/test-process-title-threadsafe.c | 90 - 3rd/libuv-1.19.2/test/test-process-title.c | 75 - .../test/test-queue-foreach-delete.c | 200 - 3rd/libuv-1.19.2/test/test-ref.c | 445 -- 3rd/libuv-1.19.2/test/test-run-nowait.c | 45 - 3rd/libuv-1.19.2/test/test-run-once.c | 48 - 3rd/libuv-1.19.2/test/test-semaphore.c | 111 - 3rd/libuv-1.19.2/test/test-shutdown-close.c | 108 - 3rd/libuv-1.19.2/test/test-shutdown-eof.c | 182 - 3rd/libuv-1.19.2/test/test-shutdown-twice.c | 85 - .../test/test-signal-multiple-loops.c | 298 - 3rd/libuv-1.19.2/test/test-signal.c | 325 -- .../test/test-socket-buffer-size.c | 77 - 3rd/libuv-1.19.2/test/test-spawn.c | 1875 ------- 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c | 255 - .../test/test-tcp-alloc-cb-fail.c | 123 - 3rd/libuv-1.19.2/test/test-tcp-bind-error.c | 216 - 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c | 176 - 3rd/libuv-1.19.2/test/test-tcp-close-accept.c | 194 - .../test/test-tcp-close-while-connecting.c | 97 - 3rd/libuv-1.19.2/test/test-tcp-close.c | 136 - .../test/test-tcp-connect-error-after-write.c | 98 - .../test/test-tcp-connect-error.c | 73 - .../test/test-tcp-connect-timeout.c | 91 - .../test/test-tcp-connect6-error.c | 71 - .../test/test-tcp-create-socket-early.c | 209 - 3rd/libuv-1.19.2/test/test-tcp-flags.c | 52 - 3rd/libuv-1.19.2/test/test-tcp-oob.c | 141 - 3rd/libuv-1.19.2/test/test-tcp-open.c | 277 - 3rd/libuv-1.19.2/test/test-tcp-read-stop.c | 76 - .../test/test-tcp-shutdown-after-write.c | 138 - 3rd/libuv-1.19.2/test/test-tcp-try-write.c | 135 - .../test/test-tcp-unexpected-read.c | 117 - .../test/test-tcp-write-after-connect.c | 68 - 3rd/libuv-1.19.2/test/test-tcp-write-fail.c | 115 - .../test/test-tcp-write-queue-order.c | 139 - .../test-tcp-write-to-half-open-connection.c | 141 - 3rd/libuv-1.19.2/test/test-tcp-writealot.c | 180 - 3rd/libuv-1.19.2/test/test-thread-equal.c | 45 - 3rd/libuv-1.19.2/test/test-thread.c | 232 - .../test/test-threadpool-cancel.c | 308 -- 3rd/libuv-1.19.2/test/test-threadpool.c | 76 - 3rd/libuv-1.19.2/test/test-timer-again.c | 141 - 3rd/libuv-1.19.2/test/test-timer-from-check.c | 80 - 3rd/libuv-1.19.2/test/test-timer.c | 330 -- 3rd/libuv-1.19.2/test/test-tmpdir.c | 71 - 3rd/libuv-1.19.2/test/test-tty.c | 390 -- .../test/test-udp-alloc-cb-fail.c | 197 - 3rd/libuv-1.19.2/test/test-udp-bind.c | 93 - .../test/test-udp-create-socket-early.c | 135 - .../test/test-udp-dgram-too-big.c | 91 - 3rd/libuv-1.19.2/test/test-udp-ipv6.c | 198 - .../test/test-udp-multicast-interface.c | 99 - .../test/test-udp-multicast-interface6.c | 103 - .../test/test-udp-multicast-join.c | 150 - .../test/test-udp-multicast-join6.c | 165 - .../test/test-udp-multicast-ttl.c | 94 - 3rd/libuv-1.19.2/test/test-udp-open.c | 204 - 3rd/libuv-1.19.2/test/test-udp-options.c | 137 - .../test/test-udp-send-and-recv.c | 214 - .../test/test-udp-send-hang-loop.c | 99 - .../test/test-udp-send-immediate.c | 149 - .../test/test-udp-send-unreachable.c | 150 - 3rd/libuv-1.19.2/test/test-udp-try-send.c | 121 - 3rd/libuv-1.19.2/test/test-walk-handles.c | 77 - .../test/test-watcher-cross-stop.c | 111 - 3rd/libuv-1.19.2/test/test.gyp | 279 - 3rd/libuv-1.19.2/tools/make_dist_html.py | 124 - 3rd/libuv-1.19.2/uv.gyp | 355 -- 3rd/libuv-1.19.2/vcbuild.bat | 184 - 3rd/libuv.sln | 31 - 418 files changed, 103554 deletions(-) delete mode 100644 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md delete mode 100644 3rd/libuv-1.19.2/.gitignore delete mode 100644 3rd/libuv-1.19.2/.mailmap delete mode 100644 3rd/libuv-1.19.2/AUTHORS delete mode 100644 3rd/libuv-1.19.2/CONTRIBUTING.md delete mode 100644 3rd/libuv-1.19.2/ChangeLog delete mode 100644 3rd/libuv-1.19.2/LICENSE delete mode 100644 3rd/libuv-1.19.2/LICENSE-docs delete mode 100644 3rd/libuv-1.19.2/MAINTAINERS.md delete mode 100644 3rd/libuv-1.19.2/Makefile.am delete mode 100644 3rd/libuv-1.19.2/Makefile.mingw delete mode 100644 3rd/libuv-1.19.2/README.md delete mode 100644 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md delete mode 100644 3rd/libuv-1.19.2/android-configure delete mode 100644 3rd/libuv-1.19.2/appveyor.yml delete mode 100644 3rd/libuv-1.19.2/autogen.sh delete mode 100644 3rd/libuv-1.19.2/checksparse.sh delete mode 100644 3rd/libuv-1.19.2/common.gypi delete mode 100644 3rd/libuv-1.19.2/configure.ac delete mode 100644 3rd/libuv-1.19.2/docs/code/cgi/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/cgi/tick.c delete mode 100644 3rd/libuv-1.19.2/docs/code/detach/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/dns/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/helloworld/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/idle-basic/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/idle-compute/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/interfaces/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/locks/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js delete mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c delete mode 100644 3rd/libuv-1.19.2/docs/code/onchange/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/plugin/hello.c delete mode 100644 3rd/libuv-1.19.2/docs/code/plugin/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/plugin/plugin.h delete mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/test.c delete mode 100644 3rd/libuv-1.19.2/docs/code/progress/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/queue-cancel/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/queue-work/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/ref-timer/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/signal/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/spawn/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/thread-create/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/tty/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/uvcat/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/uvstop/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/uvtee/main.c delete mode 100644 3rd/libuv-1.19.2/docs/code/uvwget/main.c delete mode 100644 3rd/libuv-1.19.2/docs/make.bat delete mode 100644 3rd/libuv-1.19.2/docs/src/api.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/async.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/check.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/conf.py delete mode 100644 3rd/libuv-1.19.2/docs/src/design.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/dll.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/dns.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/errors.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/fs.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/fs_event.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/fs_poll.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/about.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/basics.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/eventloops.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/filesystem.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/introduction.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/networking.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/processes.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/threads.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/guide/utilities.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/handle.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/idle.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/index.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/loop.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/migration_010_100.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/misc.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/pipe.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/poll.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/prepare.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/process.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/request.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/signal.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py delete mode 100644 3rd/libuv-1.19.2/docs/src/static/architecture.png delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-micro.jpg delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-web.jpg delete mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview.jpg delete mode 100644 3rd/libuv-1.19.2/docs/src/static/favicon.ico delete mode 100644 3rd/libuv-1.19.2/docs/src/static/logo.png delete mode 100644 3rd/libuv-1.19.2/docs/src/static/loop_iteration.png delete mode 100644 3rd/libuv-1.19.2/docs/src/stream.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/tcp.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/threading.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/threadpool.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/timer.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/tty.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/udp.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/upgrading.rst delete mode 100644 3rd/libuv-1.19.2/docs/src/version.rst delete mode 100644 3rd/libuv-1.19.2/gyp_uv.py delete mode 100644 3rd/libuv-1.19.2/img/banner.png delete mode 100644 3rd/libuv-1.19.2/img/logos.svg delete mode 100644 3rd/libuv-1.19.2/include/android-ifaddrs.h delete mode 100644 3rd/libuv-1.19.2/include/pthread-barrier.h delete mode 100644 3rd/libuv-1.19.2/include/stdint-msvc2008.h delete mode 100644 3rd/libuv-1.19.2/include/tree.h delete mode 100644 3rd/libuv-1.19.2/include/uv-aix.h delete mode 100644 3rd/libuv-1.19.2/include/uv-bsd.h delete mode 100644 3rd/libuv-1.19.2/include/uv-darwin.h delete mode 100644 3rd/libuv-1.19.2/include/uv-errno.h delete mode 100644 3rd/libuv-1.19.2/include/uv-linux.h delete mode 100644 3rd/libuv-1.19.2/include/uv-os390.h delete mode 100644 3rd/libuv-1.19.2/include/uv-posix.h delete mode 100644 3rd/libuv-1.19.2/include/uv-sunos.h delete mode 100644 3rd/libuv-1.19.2/include/uv-threadpool.h delete mode 100644 3rd/libuv-1.19.2/include/uv-unix.h delete mode 100644 3rd/libuv-1.19.2/include/uv-version.h delete mode 100644 3rd/libuv-1.19.2/include/uv-win.h delete mode 100644 3rd/libuv-1.19.2/include/uv.h delete mode 100644 3rd/libuv-1.19.2/libuv.pc.in delete mode 100644 3rd/libuv-1.19.2/libuv.vcxproj delete mode 100644 3rd/libuv-1.19.2/m4/.gitignore delete mode 100644 3rd/libuv-1.19.2/m4/as_case.m4 delete mode 100644 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 delete mode 100644 3rd/libuv-1.19.2/samples/.gitignore delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/client.c delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/main.c delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/server.c delete mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/util.c delete mode 100644 3rd/libuv-1.19.2/src/fs-poll.c delete mode 100644 3rd/libuv-1.19.2/src/heap-inl.h delete mode 100644 3rd/libuv-1.19.2/src/inet.c delete mode 100644 3rd/libuv-1.19.2/src/queue.h delete mode 100644 3rd/libuv-1.19.2/src/threadpool.c delete mode 100644 3rd/libuv-1.19.2/src/unix/aix-common.c delete mode 100644 3rd/libuv-1.19.2/src/unix/aix.c delete mode 100644 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c delete mode 100644 3rd/libuv-1.19.2/src/unix/async.c delete mode 100644 3rd/libuv-1.19.2/src/unix/atomic-ops.h delete mode 100644 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c delete mode 100644 3rd/libuv-1.19.2/src/unix/core.c delete mode 100644 3rd/libuv-1.19.2/src/unix/cygwin.c delete mode 100644 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c delete mode 100644 3rd/libuv-1.19.2/src/unix/darwin.c delete mode 100644 3rd/libuv-1.19.2/src/unix/dl.c delete mode 100644 3rd/libuv-1.19.2/src/unix/freebsd.c delete mode 100644 3rd/libuv-1.19.2/src/unix/fs.c delete mode 100644 3rd/libuv-1.19.2/src/unix/fsevents.c delete mode 100644 3rd/libuv-1.19.2/src/unix/getaddrinfo.c delete mode 100644 3rd/libuv-1.19.2/src/unix/getnameinfo.c delete mode 100644 3rd/libuv-1.19.2/src/unix/ibmi.c delete mode 100644 3rd/libuv-1.19.2/src/unix/internal.h delete mode 100644 3rd/libuv-1.19.2/src/unix/kqueue.c delete mode 100644 3rd/libuv-1.19.2/src/unix/linux-core.c delete mode 100644 3rd/libuv-1.19.2/src/unix/linux-inotify.c delete mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.c delete mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.h delete mode 100644 3rd/libuv-1.19.2/src/unix/loop-watcher.c delete mode 100644 3rd/libuv-1.19.2/src/unix/loop.c delete mode 100644 3rd/libuv-1.19.2/src/unix/netbsd.c delete mode 100644 3rd/libuv-1.19.2/src/unix/no-fsevents.c delete mode 100644 3rd/libuv-1.19.2/src/unix/no-proctitle.c delete mode 100644 3rd/libuv-1.19.2/src/unix/openbsd.c delete mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.c delete mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.h delete mode 100644 3rd/libuv-1.19.2/src/unix/os390.c delete mode 100644 3rd/libuv-1.19.2/src/unix/pipe.c delete mode 100644 3rd/libuv-1.19.2/src/unix/poll.c delete mode 100644 3rd/libuv-1.19.2/src/unix/posix-hrtime.c delete mode 100644 3rd/libuv-1.19.2/src/unix/posix-poll.c delete mode 100644 3rd/libuv-1.19.2/src/unix/process.c delete mode 100644 3rd/libuv-1.19.2/src/unix/procfs-exepath.c delete mode 100644 3rd/libuv-1.19.2/src/unix/proctitle.c delete mode 100644 3rd/libuv-1.19.2/src/unix/pthread-fixes.c delete mode 100644 3rd/libuv-1.19.2/src/unix/signal.c delete mode 100644 3rd/libuv-1.19.2/src/unix/spinlock.h delete mode 100644 3rd/libuv-1.19.2/src/unix/stream.c delete mode 100644 3rd/libuv-1.19.2/src/unix/sunos.c delete mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c delete mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c delete mode 100644 3rd/libuv-1.19.2/src/unix/tcp.c delete mode 100644 3rd/libuv-1.19.2/src/unix/thread.c delete mode 100644 3rd/libuv-1.19.2/src/unix/timer.c delete mode 100644 3rd/libuv-1.19.2/src/unix/tty.c delete mode 100644 3rd/libuv-1.19.2/src/unix/udp.c delete mode 100644 3rd/libuv-1.19.2/src/uv-common.c delete mode 100644 3rd/libuv-1.19.2/src/uv-common.h delete mode 100644 3rd/libuv-1.19.2/src/uv-data-getter-setters.c delete mode 100644 3rd/libuv-1.19.2/src/version.c delete mode 100644 3rd/libuv-1.19.2/src/win/async.c delete mode 100644 3rd/libuv-1.19.2/src/win/atomicops-inl.h delete mode 100644 3rd/libuv-1.19.2/src/win/core.c delete mode 100644 3rd/libuv-1.19.2/src/win/detect-wakeup.c delete mode 100644 3rd/libuv-1.19.2/src/win/dl.c delete mode 100644 3rd/libuv-1.19.2/src/win/error.c delete mode 100644 3rd/libuv-1.19.2/src/win/fs-event.c delete mode 100644 3rd/libuv-1.19.2/src/win/fs.c delete mode 100644 3rd/libuv-1.19.2/src/win/getaddrinfo.c delete mode 100644 3rd/libuv-1.19.2/src/win/getnameinfo.c delete mode 100644 3rd/libuv-1.19.2/src/win/handle-inl.h delete mode 100644 3rd/libuv-1.19.2/src/win/handle.c delete mode 100644 3rd/libuv-1.19.2/src/win/internal.h delete mode 100644 3rd/libuv-1.19.2/src/win/loop-watcher.c delete mode 100644 3rd/libuv-1.19.2/src/win/pipe.c delete mode 100644 3rd/libuv-1.19.2/src/win/poll.c delete mode 100644 3rd/libuv-1.19.2/src/win/process-stdio.c delete mode 100644 3rd/libuv-1.19.2/src/win/process.c delete mode 100644 3rd/libuv-1.19.2/src/win/req-inl.h delete mode 100644 3rd/libuv-1.19.2/src/win/req.c delete mode 100644 3rd/libuv-1.19.2/src/win/signal.c delete mode 100644 3rd/libuv-1.19.2/src/win/snprintf.c delete mode 100644 3rd/libuv-1.19.2/src/win/stream-inl.h delete mode 100644 3rd/libuv-1.19.2/src/win/stream.c delete mode 100644 3rd/libuv-1.19.2/src/win/tcp.c delete mode 100644 3rd/libuv-1.19.2/src/win/thread.c delete mode 100644 3rd/libuv-1.19.2/src/win/timer.c delete mode 100644 3rd/libuv-1.19.2/src/win/tty.c delete mode 100644 3rd/libuv-1.19.2/src/win/udp.c delete mode 100644 3rd/libuv-1.19.2/src/win/util.c delete mode 100644 3rd/libuv-1.19.2/src/win/winapi.c delete mode 100644 3rd/libuv-1.19.2/src/win/winapi.h delete mode 100644 3rd/libuv-1.19.2/src/win/winsock.c delete mode 100644 3rd/libuv-1.19.2/src/win/winsock.h delete mode 100644 3rd/libuv-1.19.2/stdafx.cpp delete mode 100644 3rd/libuv-1.19.2/stdafx.h delete mode 100644 3rd/libuv-1.19.2/targetver.h delete mode 100644 3rd/libuv-1.19.2/test/benchmark-async-pummel.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-async.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-fs-stat.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-list.h delete mode 100644 3rd/libuv-1.19.2/test/benchmark-loop-count.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-million-async.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-million-timers.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-multi-accept.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-pound.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-pump.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-sizes.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-spawn.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-thread.c delete mode 100644 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c delete mode 100644 3rd/libuv-1.19.2/test/blackhole-server.c delete mode 100644 3rd/libuv-1.19.2/test/dns-server.c delete mode 100644 3rd/libuv-1.19.2/test/echo-server.c delete mode 100644 3rd/libuv-1.19.2/test/fixtures/empty_file delete mode 100644 3rd/libuv-1.19.2/test/fixtures/load_error.node delete mode 100644 3rd/libuv-1.19.2/test/run-benchmarks.c delete mode 100644 3rd/libuv-1.19.2/test/run-tests.c delete mode 100644 3rd/libuv-1.19.2/test/runner-unix.c delete mode 100644 3rd/libuv-1.19.2/test/runner-unix.h delete mode 100644 3rd/libuv-1.19.2/test/runner-win.c delete mode 100644 3rd/libuv-1.19.2/test/runner-win.h delete mode 100644 3rd/libuv-1.19.2/test/runner.c delete mode 100644 3rd/libuv-1.19.2/test/runner.h delete mode 100644 3rd/libuv-1.19.2/test/task.h delete mode 100644 3rd/libuv-1.19.2/test/test-active.c delete mode 100644 3rd/libuv-1.19.2/test/test-async-null-cb.c delete mode 100644 3rd/libuv-1.19.2/test/test-async.c delete mode 100644 3rd/libuv-1.19.2/test/test-barrier.c delete mode 100644 3rd/libuv-1.19.2/test/test-callback-order.c delete mode 100644 3rd/libuv-1.19.2/test/test-callback-stack.c delete mode 100644 3rd/libuv-1.19.2/test/test-close-fd.c delete mode 100644 3rd/libuv-1.19.2/test/test-close-order.c delete mode 100644 3rd/libuv-1.19.2/test/test-condvar.c delete mode 100644 3rd/libuv-1.19.2/test/test-connect-unspecified.c delete mode 100644 3rd/libuv-1.19.2/test/test-connection-fail.c delete mode 100644 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c delete mode 100644 3rd/libuv-1.19.2/test/test-default-loop-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-delayed-accept.c delete mode 100644 3rd/libuv-1.19.2/test/test-dlerror.c delete mode 100644 3rd/libuv-1.19.2/test/test-eintr-handling.c delete mode 100644 3rd/libuv-1.19.2/test/test-embed.c delete mode 100644 3rd/libuv-1.19.2/test/test-emfile.c delete mode 100644 3rd/libuv-1.19.2/test/test-env-vars.c delete mode 100644 3rd/libuv-1.19.2/test/test-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-fail-always.c delete mode 100644 3rd/libuv-1.19.2/test/test-fork.c delete mode 100644 3rd/libuv-1.19.2/test/test-fs-copyfile.c delete mode 100644 3rd/libuv-1.19.2/test/test-fs-event.c delete mode 100644 3rd/libuv-1.19.2/test/test-fs-poll.c delete mode 100644 3rd/libuv-1.19.2/test/test-fs.c delete mode 100644 3rd/libuv-1.19.2/test/test-get-currentexe.c delete mode 100644 3rd/libuv-1.19.2/test/test-get-loadavg.c delete mode 100644 3rd/libuv-1.19.2/test/test-get-memory.c delete mode 100644 3rd/libuv-1.19.2/test/test-get-passwd.c delete mode 100644 3rd/libuv-1.19.2/test/test-getaddrinfo.c delete mode 100644 3rd/libuv-1.19.2/test/test-gethostname.c delete mode 100644 3rd/libuv-1.19.2/test/test-getnameinfo.c delete mode 100644 3rd/libuv-1.19.2/test/test-getsockname.c delete mode 100644 3rd/libuv-1.19.2/test/test-getters-setters.c delete mode 100644 3rd/libuv-1.19.2/test/test-handle-fileno.c delete mode 100644 3rd/libuv-1.19.2/test/test-homedir.c delete mode 100644 3rd/libuv-1.19.2/test/test-hrtime.c delete mode 100644 3rd/libuv-1.19.2/test/test-idle.c delete mode 100644 3rd/libuv-1.19.2/test/test-ip4-addr.c delete mode 100644 3rd/libuv-1.19.2/test/test-ip6-addr.c delete mode 100644 3rd/libuv-1.19.2/test/test-ipc-send-recv.c delete mode 100644 3rd/libuv-1.19.2/test/test-ipc.c delete mode 100644 3rd/libuv-1.19.2/test/test-list.h delete mode 100644 3rd/libuv-1.19.2/test/test-loop-alive.c delete mode 100644 3rd/libuv-1.19.2/test/test-loop-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-loop-configure.c delete mode 100644 3rd/libuv-1.19.2/test/test-loop-handles.c delete mode 100644 3rd/libuv-1.19.2/test/test-loop-stop.c delete mode 100644 3rd/libuv-1.19.2/test/test-loop-time.c delete mode 100644 3rd/libuv-1.19.2/test/test-multiple-listen.c delete mode 100644 3rd/libuv-1.19.2/test/test-mutexes.c delete mode 100644 3rd/libuv-1.19.2/test/test-osx-select.c delete mode 100644 3rd/libuv-1.19.2/test/test-pass-always.c delete mode 100644 3rd/libuv-1.19.2/test/test-ping-pong.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-bind-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-getsockname.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-pending-instances.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-server-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c delete mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c delete mode 100644 3rd/libuv-1.19.2/test/test-platform-output.c delete mode 100644 3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c delete mode 100644 3rd/libuv-1.19.2/test/test-poll-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-poll-closesocket.c delete mode 100644 3rd/libuv-1.19.2/test/test-poll-oob.c delete mode 100644 3rd/libuv-1.19.2/test/test-poll.c delete mode 100644 3rd/libuv-1.19.2/test/test-process-title-threadsafe.c delete mode 100644 3rd/libuv-1.19.2/test/test-process-title.c delete mode 100644 3rd/libuv-1.19.2/test/test-queue-foreach-delete.c delete mode 100644 3rd/libuv-1.19.2/test/test-ref.c delete mode 100644 3rd/libuv-1.19.2/test/test-run-nowait.c delete mode 100644 3rd/libuv-1.19.2/test/test-run-once.c delete mode 100644 3rd/libuv-1.19.2/test/test-semaphore.c delete mode 100644 3rd/libuv-1.19.2/test/test-shutdown-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-shutdown-eof.c delete mode 100644 3rd/libuv-1.19.2/test/test-shutdown-twice.c delete mode 100644 3rd/libuv-1.19.2/test/test-signal-multiple-loops.c delete mode 100644 3rd/libuv-1.19.2/test/test-signal.c delete mode 100644 3rd/libuv-1.19.2/test/test-socket-buffer-size.c delete mode 100644 3rd/libuv-1.19.2/test/test-spawn.c delete mode 100644 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-accept.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-close.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect6-error.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-flags.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-oob.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-open.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-read-stop.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-try-write.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-fail.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c delete mode 100644 3rd/libuv-1.19.2/test/test-tcp-writealot.c delete mode 100644 3rd/libuv-1.19.2/test/test-thread-equal.c delete mode 100644 3rd/libuv-1.19.2/test/test-thread.c delete mode 100644 3rd/libuv-1.19.2/test/test-threadpool-cancel.c delete mode 100644 3rd/libuv-1.19.2/test/test-threadpool.c delete mode 100644 3rd/libuv-1.19.2/test/test-timer-again.c delete mode 100644 3rd/libuv-1.19.2/test/test-timer-from-check.c delete mode 100644 3rd/libuv-1.19.2/test/test-timer.c delete mode 100644 3rd/libuv-1.19.2/test/test-tmpdir.c delete mode 100644 3rd/libuv-1.19.2/test/test-tty.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-bind.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-create-socket-early.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-ipv6.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join6.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-open.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-options.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-send-and-recv.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-send-immediate.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-send-unreachable.c delete mode 100644 3rd/libuv-1.19.2/test/test-udp-try-send.c delete mode 100644 3rd/libuv-1.19.2/test/test-walk-handles.c delete mode 100644 3rd/libuv-1.19.2/test/test-watcher-cross-stop.c delete mode 100644 3rd/libuv-1.19.2/test/test.gyp delete mode 100644 3rd/libuv-1.19.2/tools/make_dist_html.py delete mode 100644 3rd/libuv-1.19.2/uv.gyp delete mode 100644 3rd/libuv-1.19.2/vcbuild.bat delete mode 100644 3rd/libuv.sln diff --git a/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md b/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 543dc9fd..00000000 --- a/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,10 +0,0 @@ - -* **Version**: -* **Platform**: diff --git a/3rd/libuv-1.19.2/.gitignore b/3rd/libuv-1.19.2/.gitignore deleted file mode 100644 index 7536abd5..00000000 --- a/3rd/libuv-1.19.2/.gitignore +++ /dev/null @@ -1,79 +0,0 @@ -*.swp -*.[oa] -*.l[oa] -*.opensdf -*.orig -*.pyc -*.sdf -*.suo -.vs/ -*.VC.db -*.VC.opendb -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 -/android-toolchain - -/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/3rd/libuv-1.19.2/.mailmap b/3rd/libuv-1.19.2/.mailmap deleted file mode 100644 index da421436..00000000 --- a/3rd/libuv-1.19.2/.mailmap +++ /dev/null @@ -1,46 +0,0 @@ -A. Hauptmann -Aaron Bieber -Alan Gutierrez -Andrius Bentkus -Bert Belder -Bert Belder -Bert Belder -Brandon Philips -Brian White -Brian White -Caleb James DeLisle -Christoph Iserlohn -Devchandra Meetei Leishangthem -Fedor Indutny -Frank Denis -Imran Iqbal -Isaac Z. Schlueter -Jason Williams -Justin Venus -Keno Fischer -Keno Fischer -Leith Bade -Leonard Hecker -Maciej Małecki -Marc Schlaich -Michael -Michael Neumann -Nicholas Vavilov -Nick Logan -Rasmus Christian Pedersen -Rasmus Christian Pedersen -Robert Mustacchi -Ryan Dahl -Ryan Emery -Sakthipriyan Vairamani -Sam Roberts -San-Tai Hsu -Santiago Gimeno -Saúl Ibarra Corretgé -Shigeki Ohtsu -Timothy J. Fontaine -Yasuhiro Matsumoto -Yazhong Liu -Yuki Okumura -jBarz -jBarz diff --git a/3rd/libuv-1.19.2/AUTHORS b/3rd/libuv-1.19.2/AUTHORS deleted file mode 100644 index fcb0aac3..00000000 --- a/3rd/libuv-1.19.2/AUTHORS +++ /dev/null @@ -1,332 +0,0 @@ -# Authors ordered by first contribution. -Ryan Dahl -Bert Belder -Josh Roesslein -Alan Gutierrez -Joshua Peek -Igor Zinkovsky -San-Tai Hsu -Ben Noordhuis -Henry Rawas -Robert Mustacchi -Matt Stevens -Paul Querna -Shigeki Ohtsu -Tom Hughes -Peter Bright -Jeroen Janssen -Andrea Lattuada -Augusto Henrique Hentz -Clifford Heath -Jorge Chamorro Bieling -Luis Lavena -Matthew Sporleder -Erick Tryzelaar -Isaac Z. Schlueter -Pieter Noordhuis -Marek Jelen -Fedor Indutny -Saúl Ibarra Corretgé -Felix Geisendörfer -Yuki Okumura -Roman Shtylman -Frank Denis -Carter Allen -Tj Holowaychuk -Shimon Doodkin -Ryan Emery -Bruce Mitchener -Maciej Małecki -Yasuhiro Matsumoto -Daisuke Murase -Paddy Byers -Dan VerWeire -Brandon Benvie -Brandon Philips -Nathan Rajlich -Charlie McConnell -Vladimir Dronnikov -Aaron Bieber -Bulat Shakirzyanov -Brian White -Erik Dubbelboer -Keno Fischer -Ira Cooper -Andrius Bentkus -Iñaki Baz Castillo -Mark Cavage -George Yohng -Xidorn Quan -Roman Neuhauser -Shuhei Tanuma -Bryan Cantrill -Trond Norbye -Tim Holy -Prancesco Pertugio -Leonard Hecker -Andrew Paprocki -Luigi Grilli -Shannen Saez -Artur Adib -Hiroaki Nakamura -Ting-Yu Lin -Stephen Gallagher -Shane Holloway -Andrew Shaffer -Vlad Tudose -Ben Leslie -Tim Bradshaw -Timothy J. Fontaine -Marc Schlaich -Brian Mazza -Elliot Saba -Ben Kelly -Nils Maier -Nicholas Vavilov -Miroslav Bajtoš -Sean Silva -Wynn Wilkes -Andrei Sedoi -Alex Crichton -Brent Cook -Brian Kaisner -Luca Bruno -Reini Urban -Maks Naumov -Sean Farrell -Chris Bank -Geert Jansen -Christoph Iserlohn -Steven Kabbes -Alex Gaynor -huxingyi -Tenor Biel -Andrej Manduch -Joshua Neuheisel -Alexis Campailla -Yazhong Liu -Sam Roberts -River Tarnell -Nathan Sweet -Trevor Norris -Oguz Bastemur -Dylan Cali -Austin Foxley -Benjamin Saunders -Geoffry Song -Rasmus Christian Pedersen -William Light -Oleg Efimov -Lars Gierth -Rasmus Christian Pedersen -Justin Venus -Kristian Evensen -Linus Mårtensson -Navaneeth Kedaram Nambiathan -Yorkie -StarWing -thierry-FreeBSD -Isaiah Norton -Raul Martins -David Capello -Paul Tan -Javier Hernández -Tonis Tiigi -Norio Kobota -李港平 -Chernyshev Viacheslav -Stephen von Takach -JD Ballard -Luka Perkov -Ryan Cole -HungMingWu -Jay Satiro -Leith Bade -Peter Atashian -Tim Cooper -Caleb James DeLisle -Jameson Nash -Graham Lee -Andrew Low -Pavel Platto -Tony Kelman -John Firebaugh -lilohuang -Paul Goldsmith -Julien Gilli -Michael Hudson-Doyle -Recep ASLANTAS -Rob Adams -Zachary Newman -Robin Hahling -Jeff Widman -cjihrig -Tomasz Kołodziejski -Unknown W. Brackets -Emmanuel Odeke -Mikhail Mukovnikov -Thorsten Lorenz -Yuri D'Elia -Manos Nikolaidis -Elijah Andrews -Michael Ira Krufky -Helge Deller -Joey Geralnik -Tim Caswell -Logan Rosen -Kenneth Perry -John Marino -Alexey Melnichuk -Johan Bergström -Alex Mo -Luis Martinez de Bartolome -Michael Penick -Michael -Massimiliano Torromeo -TomCrypto -Brett Vickers -Ole André Vadla Ravnås -Kazuho Oku -Ryan Phillips -Brian Green -Devchandra Meetei Leishangthem -Corey Farrell -Per Nilsson -Alan Rogers -Daryl Haresign -Rui Abreu Ferreira -João Reis -farblue68 -Jason Williams -Igor Soarez -Miodrag Milanovic -Cheng Zhao -Michael Neumann -Stefano Cristiano -heshamsafi -A. Hauptmann -John McNamee -Yosuke Furukawa -Santiago Gimeno -guworks -RossBencina -Roger A. Light -chenttuuvv -Richard Lau -ronkorving -Corbin Simpson -Zachary Hamm -Karl Skomski -Jeremy Whitlock -Willem Thiart -Ben Trask -Jianghua Yang -Colin Snover -Sakthipriyan Vairamani -Eli Skeggs -nmushell -Gireesh Punathil -Ryan Johnston -Adam Stylinski -Nathan Corvino -Wink Saville -Angel Leon -Louis DeJardin -Imran Iqbal -Petka Antonov -Ian Kronquist -kkdaemon -Yuval Brik -Joran Dirk Greef -Andrey Mazo -sztomi -Martin Bark -Dave -Alexis Murzeau -Didiet -Nan Xiang <514580344@qq.com> -Samuel Lorétan -Nándor István Krácser -Katsutoshi Horie -Lukasz Jagiello -Robert Chiras -Kári Tristan Helgason -Krishnaraj Bhat -Enno Boland -Michael Fero -Robert Jefe Lindstaedt -Myles Borins -Tony Theodore -Jason Ginchereau -Nicolas Cavallari -Pierre-Marie de Rodat -Brian Maher -neevek -John Barboza -liuxiaobo -Michele Caini -Bartosz Sosnowski -Matej Knopp -sunjin.lee -Matt Clarkson -Jeffrey Clark -Bart Robinson -Vit Gottwald -Vladimír Čunát -Alex Hultman -Brad King -Philippe Laferriere -Will Speak -Hitesh Kanwathirtha -Eric Sciple -jBarz -muflub -Daniel Bevenius -Howard Hellyer -Chris Araman -Vladimir Matveev -Jason Madden -Jamie Davis -Daniel Kahn Gillmor -Keane -James McCoy -Bernardo Ramos -Juan Cruz Viotti -Gemini Wen -Sebastian Wiedenroth -Sai Ke WANG -Barnabas Gema -Romain Caire -Robert Ayrapetyan -Refael Ackermann -André Klitzing -Matthew Taylor -CurlyMoo -XadillaX -Anticrisis -Jacob Segal -Maciej Szeptuch (Neverous) -Joel Winarske -Gergely Nagy -Kamil Rytarowski -tux.uudiin <77389867@qq.com> -Nick Logan -darobs -Zheng, Lei -Carlo Marcelo Arenas Belón -Scott Parker -Wade Brainerd -rayrase -Pekka Nikander -Ed Schouten -Xu Meng -Matt Harrison -Anna Henningsen -Jérémy Lal -Ben Wijen -elephantp -Felix Yan -Mason X -Jesse Gorzinski -Ryuichi KAWAMATA -Joyee Cheung diff --git a/3rd/libuv-1.19.2/CONTRIBUTING.md b/3rd/libuv-1.19.2/CONTRIBUTING.md deleted file mode 100644 index d9bf0472..00000000 --- a/3rd/libuv-1.19.2/CONTRIBUTING.md +++ /dev/null @@ -1,169 +0,0 @@ -# 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][] 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. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: -- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. -- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. - -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.freenode.net/?channels=libuv -[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html -[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/3rd/libuv-1.19.2/ChangeLog b/3rd/libuv-1.19.2/ChangeLog deleted file mode 100644 index 53ebd01d..00000000 --- a/3rd/libuv-1.19.2/ChangeLog +++ /dev/null @@ -1,3531 +0,0 @@ -2018.02.22, Version 1.19.2 (Stable) - -Changes since version 1.19.1: - -* test: fix incorrect asserts (cjihrig) - -* test: fix a typo in test-fork.c (Felix Yan) - -* build: remove long-obsolete gyp workarounds (Ben Noordhuis) - -* build: split off tests into separate gyp file (Ben Noordhuis) - -* test: check uv_cond_timedwait more carefully (Jamie Davis) - -* include,src: introduce UV__ERR() macro (Mason X) - -* build: add url field to libuv.pc (Ben Noordhuis) - -* doc: mark IBM i as Tier 3 support (Jesse Gorzinski) - -* win,build: correct C2059 errors (Michael Fero) - -* zos: fix timeout for condition variable (jBarz) - -* win: CREATE_NO_WINDOW when stdio is not inherited (Nick Logan) - -* build: fix commmon.gypi comment (Ryuichi KAWAMATA) - -* doc: document uv_timer_start() on an active timer (Vladimír Čunát) - -* doc: add note about handle movability (Bartosz Sosnowski) - -* doc: fix syntax error in loop documentation (Bartosz Sosnowski) - -* osx,stream: retry sending handle on EMSGSIZE error (Santiago Gimeno) - -* unix: delay fs req register until after validation (cjihrig) - -* test: add tests for bad inputs (Joyee Cheung) - -* unix,win: ensure req->bufs is freed (cjihrig) - -* test: add additional fs memory management checks (cjihrig) - - -2018.01.20, Version 1.19.1 (Stable), 8202d1751196c2374ad370f7f3779daef89befae - -Changes since version 1.19.0: - -* Revert "unix,tcp: avoid marking server sockets connected" (Ben Noordhuis) - -* Revert "unix,fs: fix for potential partial reads/writes" (Ben Noordhuis) - -* Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" (Ben Noordhuis) - -* cygwin: fix compilation of ifaddrs impl (Brad King) - - -2018.01.18, Version 1.19.0 (Stable), effbb7c9d29090b2e085a40867f8cdfa916a66df - -Changes since version 1.18.0: - -* core: add getter/setter functions for easier ABI compat (Anna Henningsen) - -* unix: make get(set)_process_title MT-safe (Matt Harrison) - -* unix,win: wait for threads to start (Ben Noordhuis) - -* test: add threadpool init/teardown test (Bartosz Sosnowski) - -* win, process: uv_kill improvements (Bartosz Sosnowski) - -* win: set _WIN32_WINNT to 0x0600 (cjihrig) - -* zos: implement uv_fs_event* functions (jBarz) - -* unix,tcp: avoid marking server sockets connected (Jameson Nash) - -* doc: mark Windows 7 as Tier 1 support (Bartosz Sosnowski) - -* win: map 0.0.0.0 and :: addresses to localhost (Bartosz Sosnowski) - -* build: install libuv.pc unconditionally (Ben Noordhuis) - -* test: remove custom timeout for thread test on ppc (Ben Noordhuis) - -* test: allow multicast not permitted status (Jérémy Lal) - -* test: allow net unreachable status in udp test (Ben Noordhuis) - -* unix: use SA_RESTART when setting our sighandler (Brad King) - -* unix,fs: fix for potential partial reads/writes (Ben Wijen) - -* win,build: do not build executable installer for dll (Bert Belder) - -* win: allow directory symlinks to be created in a non-elevated context (Bert - Belder) - -* zos,test: accept SIGKILL for flaky test (jBarz) - -* win: use RemoveDirectoryW() instead of _wmrmdir() (Ben Noordhuis) - -* unix: fix uv_cpu_info() error on FreeBSD (elephantp) - -* zos,test: decrease pings to avoid timeout (jBarz) - - -2017.12.02, Version 1.18.0 (Stable), 1489c98b7fc17f1702821a269eb0c5e730c5c813 - -Changes since version 1.17.0: - -* aix: fix -Wmaybe-uninitialized warning (cjihrig) - -* doc: remove note about SIGWINCH on Windows (Bartosz Sosnowski) - -* Revert "unix,win: wait for threads to start" (Ben Noordhuis) - -* unix,win: add uv_os_getpid() (Bartosz Sosnowski) - -* unix: remove incorrect assertion in uv_shutdown() (Jameson Nash) - -* doc: fix IRC URL in CONTRIBUTING.md (Matt Harrison) - - -2017.11.25, Version 1.17.0 (Stable), 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 - -Changes since version 1.16.1: - -* unix: avoid malloc() call in uv_spawn() (Ben Noordhuis) - -* doc: clarify the description of uv_loop_alive() (Ed Schouten) - -* win: map UV_FS_O_EXLOCK to a share mode of 0 (Joran Dirk Greef) - -* win: fix build on case-sensitive file systems (Ben Noordhuis) - -* win: fix test runner build with mingw64 (Ben Noordhuis) - -* win: remove unused variable in test/test-fs.c (Ben Noordhuis) - -* zos: add strnlen() implementation (jBarz) - -* unix: keep track of bound sockets sent via spawn (jBarz) - -* unix,win: wait for threads to start (Ben Noordhuis) - -* test: add threadpool init/teardown test (Bartosz Sosnowski) - -* test: avoid malloc() in threadpool test (Ben Noordhuis) - -* test: lower number of tasks in threadpool test (Ben Noordhuis) - -* win: issue memory barrier in uv_thread_join() (Ben Noordhuis) - -* ibmi: add support for new platform (Xu Meng) - -* test: fix test-spawn compilation (Bartosz Sosnowski) - - -2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 - -Changes since version 1.16.0: - -* unix: move net/if.h include (cjihrig) - -* win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) - - -2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb - -Changes since version 1.15.0: - -* win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) - -* unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) - -* win, fs: fix non-symlink reparse points (Wade Brainerd) - -* test: fix -Wstrict-prototypes warnings (Ben Noordhuis) - -* unix, windows: map ENOTTY errno (Ben Noordhuis) - -* unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) - -* unix: do not close invalid kqueue fd after fork (jBarz) - -* zos: reset epoll data after fork (jBarz) - -* zos: skip fork_threadpool_queue_work_simple (jBarz) - -* test: keep platform_output as first test (Bartosz Sosnowski) - -* win: fix non-English dlopen error message (Bartosz Sosnowski) - -* unix,win: add uv_os_getppid() (cjihrig) - -* test: fix const qualification compiler warning (Ben Noordhuis) - -* doc: mark uv_default_loop() as not thread safe (rayrase) - -* win, pipe: null-initialize stream->shutdown_req (Jameson Nash) - -* tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) - -* test: no extra new line in skipped test output (Bartosz Sosnowski) - -* pipe: allow access from other users (Bartosz Sosnowski) - -* unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) - - -2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 - -Changes since version 1.14.1: - -* unix: limit uv__has_forked_with_cfrunloop to macOS (Kamil Rytarowski) - -* win: fix buffer size in uv__getpwuid_r() (tux.uudiin) - -* win,tty: improve SIGWINCH support (Bartosz Sosnowski) - -* unix: use fchmod() in uv_fs_copyfile() (cjihrig) - -* unix: support copying empty files (cjihrig) - -* unix: truncate destination in uv_fs_copyfile() (Nick Logan) - -* win,build: keep cwd when setting build environment (darobs) - -* test: add NetBSD support to test-udp-ipv6.c (Kamil Rytarowski) - -* unix: add NetBSD support in core.c (Kamil Rytarowski) - -* linux: increase thread stack size with musl libc (Ben Noordhuis) - -* netbsd: correct uv_exepath() on NetBSD (Kamil Rytarowski) - -* test: clean up semaphore after use (jBarz) - -* win,build: bump vswhere_usability_wrapper to 2.0.0 (Refael Ackermann) - -* win: let UV_PROCESS_WINDOWS_HIDE hide consoles (cjihrig) - -* zos: lock protect global epoll list in epoll_ctl (jBarz) - -* zos: change platform name to match python (jBarz) - -* android: fix getifaddrs() (Zheng, Lei) - -* netbsd: implement uv__tty_is_slave() (Kamil Rytarowski) - -* zos: fix readlink for mounts with system variables (jBarz) - -* test: sort the tests alphabetically (Sakthipriyan Vairamani) - -* windows: fix compilation warnings (Carlo Marcelo Arenas Belón) - -* build: avoid -fstrict-aliasing compile option (jBarz) - -* win: remove unused variables (Carlo Marcelo Arenas Belón) - -* unix: remove unused variables (Sakthipriyan Vairamani) - -* netbsd: disable poll_bad_fdtype on NetBSD (Kamil Rytarowski) - -* netbsd: use uv__cloexec and uv__nonblock (Kamil Rytarowski) - -* test: fix udp_multicast_join6 on NetBSD (Kamil Rytarowski) - -* unix,win: add uv_mutex_init_recursive() (Scott Parker) - -* netbsd: do not exclude IPv6 functionality (Kamil Rytarowski) - -* fsevents: watch files with fsevents on macos 10.7+ (Ben Noordhuis) - -* unix: retry on ENOBUFS in sendmsg(2) (Kamil Rytarowski) - - -2017.09.07, Version 1.14.1 (Stable), b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 - -Changes since version 1.14.0: - -* fs, win: add support for user symlinks (Bartosz Sosnowski) - -* cygwin: include uv-posix.h header (Joel Winarske) - -* zos: fix semaphore initialization (jBarz) - -* zos: improve loop_count benchmark performance (jBarz) - -* zos, test: flush out the oob data in callback (jBarz) - -* unix,win: check for bad flags in uv_fs_copyfile() (cjihrig) - -* unix: modify argv[0] when process title is set (Matthew Taylor) - -* unix: don't use req->loop in uv__fs_copyfile() (cjihrig) - -* doc: fix a trivial typo (Vladimír Čunát) - -* android: fix uv_cond_timedwait on API level < 21 (Gergely Nagy) - -* win: add uv__once_init() calls (Bartosz Sosnowski) - -* unix,windows: init all requests in fs calls (cjihrig) - -* unix,windows: return UV_EINVAL on NULL fs reqs (cjihrig) - -* windows: add POST macro to fs functions (cjihrig) - -* unix: handle partial sends in uv_fs_copyfile() (A. Hauptmann) - -* Revert "win, test: fix double close in test runner" (Bartosz Sosnowski) - -* win, test: remove surplus CloseHandle (Bartosz Sosnowski) - - -2017.08.17, Version 1.14.0 (Stable), e0d31e9e21870f88277746b6d59cf07b977cdfea - -Changes since version 1.13.1: - -* unix: check for NULL in uv_os_unsetenv for parameter name (André Klitzing) - -* doc: add thread safety warning for process title (Matthew Taylor) - -* unix: always copy process title into local buffer (Matthew Taylor) - -* poll: add support for OOB TCP and GPIO interrupts (CurlyMoo) - -* win,build: fix appveyor properly (Refael Ackermann) - -* win: include filename in dlopen error message (Ben Noordhuis) - -* aix: add netmask, mac address into net interfaces (Gireesh Punathil) - -* unix, windows: map EREMOTEIO errno (Ben Noordhuis) - -* unix: fix wrong MAC of uv_interface_address (XadillaX) - -* win,build: fix building from Windows SDK or VS console (Saúl Ibarra Corretgé) - -* github: fix link to help repo in issue template (Ben Noordhuis) - -* zos: remove nonexistent include from autotools build (Saúl Ibarra Corretgé) - -* misc: remove reference to pthread-fixes.h from LICENSE (Saúl Ibarra Corretgé) - -* docs: fix guide source code example paths (Anticrisis) - -* android: fix compilation with new NDK versions (Saúl Ibarra Corretgé) - -* misc: add android-toolchain to .gitignore (Saúl Ibarra Corretgé) - -* win, fs: support unusual reparse points (Bartosz Sosnowski) - -* android: fix detection of pthread_condattr_setclock (Saúl Ibarra Corretgé) - -* android: remove no longer needed check (Saúl Ibarra Corretgé) - -* doc: update instructions for building on Android (Saúl Ibarra Corretgé) - -* win, process: support semicolons in PATH variable (Bartosz Sosnowski) - -* doc: document uv_async_(init|send) return values (Ben Noordhuis) - -* doc: add Android as a tier 3 supported platform (Saúl Ibarra Corretgé) - -* unix: add missing semicolon (jBarz) - -* win, test: fix double close in test runner (Bartosz Sosnowski) - -* doc: update supported windows version baseline (Ben Noordhuis) - -* test,zos: skip chown root test (jBarz) - -* test,zos: use gid=-1 to test spawn_setgid_fails (jBarz) - -* zos: fix hr timer resolution (jBarz) - -* android: fix blocking recvmsg due to netlink bug (Jacob Segal) - -* zos: read more accurate rss info from RSM (jBarz) - -* win: allow bound/connected socket in uv_tcp_open() (Maciej Szeptuch - (Neverous)) - -* doc: differentiate SmartOS and SunOS support (cjihrig) - -* unix: make uv_poll_stop() remove fd from pollset (Ben Noordhuis) - -* unix, windows: add basic uv_fs_copyfile() (cjihrig) - - -2017.07.07, Version 1.13.1 (Stable), 2bb4b68758f07cd8617838e68c44c125bc567ba6 - -Changes since version 1.13.0: - -* Now working on version 1.13.1 (cjihrig) - -* build: workaround AppVeyor quirk (Refael Ackermann) - - -2017.07.06, Version 1.13.0 (Stable), 8342fcaab815f33b988c1910ea988f28dfe27edb - -Changes since version 1.12.0: - -* Now working on version 1.12.1 (cjihrig) - -* unix: avoid segfault in uv_get_process_title (Michele Caini) - -* build: add a comma to uv.gyp (Gemini Wen) - -* win: restore file pos after positional read/write (Bartosz Sosnowski) - -* unix,stream: return error on closed handle passing (Santiago Gimeno) - -* unix,benchmark: use fd instead of FILE* after fork (jBarz) - -* zos: avoid compiler warnings (jBarz) - -* win,pipe: race condition canceling readfile thread (Jameson Nash) - -* sunos: filter out non-IPv4/IPv6 interfaces (Sebastian Wiedenroth) - -* sunos: fix cmpxchgi and cmpxchgl type error (Sai Ke WANG) - -* unix: reset signal disposition before execve() (Ben Noordhuis) - -* unix: reset signal mask before execve() (Ben Noordhuis) - -* unix: fix POLLIN assertion on server read (jBarz) - -* zos: use stckf builtin for high-res timer (jBarz) - -* win,udp: implements uv_udp_try_send (Barnabas Gema) - -* win,udp: return UV_EINVAL instead of aborting (Romain Caire) - -* freebsd: replace kvm with sysctl (Robert Ayrapetyan) - -* aix: fix un-initialized pointer field in fs handle (Gireesh Punathil) - -* win,build: support building with VS2017 (Refael Ackermann) - -* doc: add instructions for building on Windows (Refael Ackermann) - -* doc: format README (Refael Ackermann) - - -2017.05.31, Version 1.12.0 (Stable), d6ac141ac674657049598c36604f26e031fae917 - -Changes since version 1.11.0: - -* Now working on version 1.11.1 (cjihrig) - -* test: fix tests on OpenBSD (Santiago Gimeno) - -* test: fix -Wformat warning (Santiago Gimeno) - -* win,fs: avoid double freeing uv_fs_event_t.dirw (Vladimir Matveev) - -* unix: remove unused code in `uv__io_start` (Fedor Indutny) - -* signal: add uv_signal_start_oneshot method (Santiago Gimeno) - -* unix: factor out reusable POSIX hrtime impl (Brad King) - -* unix,win: add uv_os_{get,set,unset}env() (cjihrig) - -* win: add uv__convert_utf8_to_utf16() (cjihrig) - -* docs: improve UV_ENOBUFS scenario documentation (cjihrig) - -* unix: return UV_EINVAL for NULL env name (jBarz) - -* unix: filter getifaddrs results consistently (Brad King) - -* unix: factor out getifaddrs result filter (Brad King) - -* unix: factor out reusable BSD ifaddrs impl (Brad King) - -* unix: use union to follow strict aliasing rules (jBarz) - -* unix: simplify async watcher dispatch logic (Ben Noordhuis) - -* samples: update timer callback prototype (Ben Noordhuis) - -* unix: make loops and watchers usable after fork() (Jason Madden) - -* win: free uv__loops once empty (cjihrig) - -* tools: add make_dist_html.py script (Ben Noordhuis) - -* win,sunos: stop handle on uv_fs_event_start() err (cjihrig) - -* unix,windows: refactor request init logic (Ben Noordhuis) - -* win: fix memory leak inside uv__pipe_getname (A. Hauptmann) - -* fsevent: support for files without short name (Bartosz Sosnowski) - -* doc: fix multiple doc typos (Jamie Davis) - -* test,osx: fix flaky kill test (Santiago Gimeno) - -* unix: inline uv_pipe_bind() err_bind goto target (cjihrig) - -* unix,test: deadstore fixes (Rasmus Christian Pedersen) - -* win: fix memory leak inside uv_fs_access() (A. Hauptmann) - -* doc: fix docs/src/fs.rst build warning (Daniel Bevenius) - -* doc: minor grammar fix in Installation section (Daniel Bevenius) - -* doc: suggestions for design page (Daniel Bevenius) - -* doc: libuv does not touch uv_loop_t.data (Ben Noordhuis) - -* github: add ISSUE_TEMPLATE.md (Ben Noordhuis) - -* doc: add link to libuv/help to README (Ben Noordhuis) - -* udp: fix fast path in uv_udp_send() on unix (Fedor Indutny) - -* test: add test for uv_udp_send() fix (Trevor Norris) - -* doc: fix documentation for uv_handle_t.type (Daniel Kahn Gillmor) - -* zos: use proper prototype for epoll_init() (Ben Noordhuis) - -* doc: rename docs to "libuv documentation" (Saúl Ibarra Corretgé) - -* doc: update copyright years (Saúl Ibarra Corretgé) - -* doc: move TOC to a dedicated document (Saúl Ibarra Corretgé) - -* doc: move documentation section up (Saúl Ibarra Corretgé) - -* doc: move "upgrading" to a standalone document (Saúl Ibarra Corretgé) - -* doc: add initial version of the User Guide (Saúl Ibarra Corretgé) - -* doc: removed unused file (Saúl Ibarra Corretgé) - -* doc: update guide/about and mention new maintainership (Saúl Ibarra Corretgé) - -* doc: remove licensing note from guide/about (Saúl Ibarra Corretgé) - -* doc: add warning note to user guide (Saúl Ibarra Corretgé) - -* doc: change license to CC BY 4.0 (Saúl Ibarra Corretgé) - -* doc: remove ubvook reference from README (Saúl Ibarra Corretgé) - -* doc: add code samples from uvbook (unadapted) (Saúl Ibarra Corretgé) - -* doc: update supported linux/glibc baseline (Ben Noordhuis) - -* win: avoid leaking pipe handles to child processes (Jameson Nash) - -* win,test: support stdout output larger than 1kb (Bartosz Sosnowski) - -* win: remove __declspec(inline) from atomic op (Keane) - -* test: fix VC++ compilation warning (Rasmus Christian Pedersen) - -* build: add -Wstrict-prototypes (Jameson Nash) - -* zos: implement uv__io_fork, skip fs event tests (jBarz) - -* unix: do not close udp sockets on bind error (Marc Schlaich) - -* unix: remove FSEventStreamFlushSync() call (cjihrig) - -* build,openbsd: remove kvm-related code (James McCoy) - -* test: fix flaky tcp-write-queue-order (Santiago Gimeno) - -* unix,win: add uv_os_gethostname() (cjihrig) - -* zos: increase timeout for tcp_writealot (jBarz) - -* zos: do not inline OOB data by default (jBarz) - -* test: fix -Wstrict-prototypes compiler warnings (Ben Noordhuis) - -* unix: factor out reusable no-proctitle impl (Brad King) - -* test: factor out fsevents skip explanation (Brad King) - -* test: skip fork fsevent cases when lacking support (Brad King) - -* unix: factor out reusable no-fsevents impl (Brad King) - -* unix: factor out reusable sysinfo memory lookup (Brad King) - -* unix: factor out reusable sysinfo loadavg impl (Brad King) - -* unix: factor out reusable procfs exepath impl (Brad King) - -* unix: add a uv__io_poll impl using POSIX poll(2) (Brad King) - -* cygwin: implement support for cygwin and msys2 (Brad King) - -* cygwin: recognize EOF on named pipe closure (Brad King) - -* cygwin: fix uv_pipe_connect report of ENOTSOCK (Brad King) - -* cygwin: disable non-functional ipc handle send (Brad King) - -* test: skip self-connecting tests on cygwin (Brad King) - -* doc: mark uv_loop_fork() as experimental (cjihrig) - -* doc: add bzoz to maintainers (Bartosz Sosnowski) - -* doc: fix memory leak in tcp-echo-server example (Bernardo Ramos) - -* win: make uv__get_osfhandle() public (Juan Cruz Viotti) - -* doc: use valid pipe name in pipe-echo-server (Bernardo Ramos) - - -2017.02.02, Version 1.11.0 (Stable), 7452ef4e06a4f99ee26b694c65476401534f2725 - -Changes since version 1.10.2: - -* Now working on version 1.10.3 (cjihrig) - -* win: added fcntl.h to uv-win.h (Michele Caini) - -* unix: move function call out of assert (jBarz) - -* fs: cleanup uv__fs_scandir (Santiago Gimeno) - -* fs: fix crash in uv_fs_scandir_next (muflub) - -* win,signal: fix potential deadlock (Bartosz Sosnowski) - -* unix: use async-signal safe functions between fork and exec (jBarz) - -* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) - -* zos: make platform functional (John Barboza) - -* doc: add repitition qualifier to version regexs (Daniel Bevenius) - -* zos: use gyp OS label "os390" on z/OS (John Barboza) - -* aix: enable uv_get/set_process_title (Howard Hellyer) - -* zos: use built-in proctitle implementation (John Barboza) - -* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) - -* win,test: don't write uninitialized buffer to tty (Bert Belder) - -* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) - -* aix: re-enable fs watch facility (Gireesh Punathil) - - -2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 - -Changes since version 1.10.1: - -* Now working on version 1.10.2 (cjihrig) - -* darwin: fix fsync and fdatasync (Joran Dirk Greef) - -* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" - (Santiago Gimeno) - -* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) - -* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) - -* win: fix comment in quote_cmd_arg (Eric Sciple) - -* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) - -* win, tty: fix crash on restarting with pending data (Nicholas Vavilov) - -* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) - -* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) - -* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) - - -2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 - -Changes since version 1.10.0: - -* Now working on version 1.10.1 (cjihrig) - -* win: fix anonymous union syntax (Brad King) - -* unix: use uv__is_closing everywhere (Santiago Gimeno) - -* win: add missing break statement (cjihrig) - -* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) - -* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) - -* doc: add cjihrig alternative GPG ID (cjihrig) - -* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) - - -2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 - -Changes since version 1.9.1: - -* Now working on version 1.9.2 (Saúl Ibarra Corretgé) - -* doc: add cjihrig GPG ID (cjihrig) - -* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) - -* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra - Corretgé) - -* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) - -* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) - -* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) - -* license: libuv is no longer a Node project (Saúl Ibarra Corretgé) - -* license: add license text we've been using for a while (Saúl Ibarra Corretgé) - -* doc: add licensing information to README (Saúl Ibarra Corretgé) - -* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) - -* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) - -* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) - -* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) - -* doc: update docs with AIX related information (Imran Iqbal) - -* test: silence build warnings (Kári Tristan Helgason) - -* doc: add iWuzHere GPG ID (Imran Iqbal) - -* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) - -* build: fix build on DragonFly (Michael Neumann) - -* unix: correctly detect named pipes on DragonFly (Michael Neumann) - -* test: make tap output the default (Ben Noordhuis) - -* test: don't dump output for skipped tests (Ben Noordhuis) - -* test: improve formatting of diagnostic messages (Ben Noordhuis) - -* test: remove unused RETURN_TODO macro (Ben Noordhuis) - -* doc: fix stream typos (Pierre-Marie de Rodat) - -* doc: update coding style link (Imran Iqbal) - -* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) - -* build: check for warnings for -fvisibility=hidden (Imran Iqbal) - -* unix: remove unneeded TODO note (Saúl Ibarra Corretgé) - -* test: skip tty_pty test if pty is not available (Luca Bruno) - -* sunos: set phys_addr of interface_address using ARP (Brian Maher) - -* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) - -* unix: don't convert stat buffer when syscall fails (Ben Noordhuis) - -* win: compare entire filename in watch events (cjihrig) - -* doc: add a note on safe reuse of uv_write_t (neevek) - -* linux: fix potential event loop stall (Ben Noordhuis) - -* unix,win: make uv_get_process_title() stricter (cjihrig) - -* test: close server before initiating new connection (John Barboza) - -* test: account for multiple handles in one ipc read (John Barboza) - -* unix: fix errno and retval conflict (liuxiaobo) - -* doc: add missing entry in uv_fs_type enum (Michele Caini) - -* unix: preserve loop->data across loop init/done (Ben Noordhuis) - -* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) - -* win: simplify memory copy logic in fs.c (Ben Noordhuis) - -* win: fix compilation on mingw (Bartosz Sosnowski) - -* win: ensure 32-bit printf precision (Matej Knopp) - -* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) - -* test: fix OOB buffer access (Saúl Ibarra Corretgé) - -* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) - -* test: fix android build error. (sunjin.lee) - -* win: evaluate timers when system wakes up (Bartosz Sosnowski) - -* doc: add supported platforms description (Saúl Ibarra Corretgé) - -* win: fix lstat reparse point without link data (Jason Ginchereau) - -* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) - -* zos: add support for new platform (John Barboza) - -* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) - -* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) - -* build: GNU/kFreeBSD support (Jeffrey Clark) - -* zos: use PLO instruction for atomic operations (John Barboza) - -* zos: use pthread helper functions (John Barboza) - -* zos: implement uv__fs_futime (John Barboza) - -* unix: expand range of values for usleep (John Barboza) - -* zos: track unbound handles and bind before listen (John Barboza) - -* test: improve tap output on test failures (Santiago Gimeno) - -* test: refactor fs_event_close_in_callback (Julien Gilli) - -* zos: implement uv__io_check_fd (John Barboza) - -* unix: unneccessary use const qualifier in container_of (John Barboza) - -* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) - -* doc: add santigimeno to maintainers (Santiago Gimeno) - -* win: fix typo in type name (Saúl Ibarra Corretgé) - -* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) - -* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) - -* win: add disk read/write count to uv_getrusage (Imran Iqbal) - -* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) - -* test: improve spawn_setuid_setgid test (Santiago Gimeno) - -* test: fix building pty test on Android (Saúl Ibarra Corretgé) - -* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) - -* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) - -* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) - -* doc: update supported fields for uv_rusage_t (Imran Iqbal) - -* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) - -* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) - -* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) - -* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) - -* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) - -* doc: add ABI tracker link to README (Saúl Ibarra Corretgé) - -* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) - -* test: fix fs_fstat on Android (Vit Gottwald) - -* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) - -* doc: add description of uv_handle_type (Vit Gottwald) - -* build: use -pthreads for tests with autotools (Julien Gilli) - -* win: fix leaky fs request buffer (Jason Ginchereau) - -* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) - -* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) - -* win: fix winapi function pointer typedef syntax (Brad King) - -* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) - -* test: make threadpool_cancel_single deterministic (Ben Noordhuis) - -* test: make threadpool saturation reliable (Ben Noordhuis) - -* unix: don't malloc in uv_thread_create() (Ben Noordhuis) - -* unix: don't include CoreServices globally on macOS (Brad King) - -* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) - -* win: remove unused static variables (Ben Noordhuis) - -* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) - -* signal: replace pthread_once with uv_once (Santiago Gimeno) - -* test: fix sign-compare warning (Will Speak) - -* common: fix unused variable warning (Brad King) - - -2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c - -Changes since version 1.9.0: - -* test: handle root home directories (cjihrig) - -* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) - -* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) - -* win: fix var declaration to be C89 compliant (Michael Fero) - -* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) - -* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) - -* Revert "win,build: remove unused build defines" (cjihrig) - -* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) - -* linux: don't abort on malformed /proc/stat (Ben Noordhuis) - -* linux: fix long lines in linux-core.c (Ben Noordhuis) - -* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) - -* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) - -* unix: delay signal handling until after normal i/o (Ben Noordhuis) - -* android: pthread_sigmask() does not set errno (Oguz Bastemur) - -* win: work around sharepoint scandir bug (Ben Noordhuis) - -* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) - -* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) - -* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) - -* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) - -* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) - -* unix: error on realpath if PATH_MAX is undefined (Myles Borins) - -* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) - -* build: bump android ndk version (Kári Tristan Helgason) - -* build: always compile with -fvisibility=hidden (Ben Noordhuis) - -* test: fix -Wformat warnings in platform test (Ben Noordhuis) - -* win: clarify fsevents handling code (Saúl Ibarra Corretgé) - -* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) - -* build, mingw: set LIBS in configure.ac (Tony Theodore) - -* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) - -* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) - -* win: remove unneeded condition (Saúl Ibarra Corretgé) - -* darwin: work around condition variable kernel bug (Ben Noordhuis) - -* darwin: make thread stack multiple of page size (Ben Noordhuis) - -* build,win: rename platform to msbuild_platform (João Reis) - -* gitignore: ignore VS temporary database files (João Reis) - -* test: skip emfile on AIX (Imran Iqbal) - -* unix: use system allocator for scandir() (cjihrig) - -* common: release uv_fs_scandir() array (cjihrig) - -* win: call uv__fs_scandir_cleanup() (cjihrig) - -* win,tty: fix read stop in line mode (João Reis) - -* win,tty: don't duplicate handle for line reads (João Reis) - -* win,tty: restore cursor after canceling line read (Alexis Campailla) - - -2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 - -Changes since version 1.8.0: - -* win: wait for full timeout duration (João Reis) - -* unix: fix support for uClibc-ng (Martin Bark) - -* doc: indicate where new test files need to be added (Dave) - -* test,unix: fix logic error in test runner (Ben Noordhuis) - -* fs: don't nullify req->bufs on EINTR (Dave) - -* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) - -* build: invoke libtoolize with --copy (Ben Noordhuis) - -* test: fixup eintr_handling (Saúl Ibarra Corretgé) - -* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) - -* test,win: fix compilation with shared lib (Alexis Murzeau) - -* test: fix race condition in pipe-close-stdout (Imran Iqbal) - -* unix,win: add uv_os_tmpdir() (cjihrig) - -* ios: fix undefined PTHREAD_STACK_MIN (Didiet) - -* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) - -* unix: report errors for unpollable fds (Ben Noordhuis) - -* win: fix watching root files (Nicholas Vavilov) - -* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) - -* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) - -* test,win: fix compilation warning (Saúl Ibarra Corretgé) - -* test: use uv_loop_close and assert its result (Nan Xiang) - -* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) - -* osx: protected use of potentially undefined macro (Samuel Lorétan) - -* linux: fix compilation with musl (Saúl Ibarra Corretgé) - -* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) - -* doc: add missing link in README (Saúl Ibarra Corretgé) - -* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) - -* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) - -* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) - -* doc: add missing write callback to example (Nándor István Krácser) - -* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) - -* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) - -* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) - -* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) - -* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) - -* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) - -* linux: fix cpu count (Lukasz Jagiello) - -* unix: fix uv__handle_type for AIX (Imran Iqbal) - -* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) - -* win: remove unneeded condition (Saúl Ibarra Corretgé) - -* unix: fix compile error in Android using bionic (Robert Chiras) - -* linux: add braces to multi-statement if (Kári Tristan Helgason) - -* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) - -* unix: add fork-safe open file function (Kári Tristan Helgason) - -* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) - -* linux: remove redundant call to rewind() (Krishnaraj Bhat) - -* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) - -* test: fix poll_bad_fdtype for AIX (Imran Iqbal) - -* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) - -* poll: add UV_DISCONNECT event (Santiago Gimeno) - -* fs: realpath: fix string size before converting (Yuval Brik) - -* win: use native APIs for UTF conversions (cjihrig) - -* doc: clarify uv_loop_close() (Ben Noordhuis) - -* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) - -* win,build: remove unused build defines (Saúl Ibarra Corretgé) - -* win: fix buffer overflow in fs events (Joran Dirk Greef) - -* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) - -* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) - -* test: add missing copyright header (cjihrig) - -* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) - -* unix,win: add uv_get_passwd() (cjihrig) - -* process: fix uv_spawn edge-case (Santiago Gimeno) - -* test: use %ld for printing uid/gid (Ben Noordhuis) - -* aix: fix ahafs implementation (Imran Iqbal) - -* aix: do not store absolute path to ahafs (Imran Iqbal) - -* process: close process pipes safely (Santiago Gimeno) - -* unix: open ttyname instead of /dev/tty (Enno Boland) - -* unix: remove outdated comment (Kári Tristan Helgason) - - -2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 - -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/3rd/libuv-1.19.2/LICENSE b/3rd/libuv-1.19.2/LICENSE deleted file mode 100644 index 28f17339..00000000 --- a/3rd/libuv-1.19.2/LICENSE +++ /dev/null @@ -1,70 +0,0 @@ -libuv is licensed for use as follows: - -==== -Copyright (c) 2015-present libuv project contributors. - -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 parts of libuv originating from the -https://github.com/joyent/libuv repository: - -==== - -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.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/3rd/libuv-1.19.2/LICENSE-docs b/3rd/libuv-1.19.2/LICENSE-docs deleted file mode 100644 index 53883b1c..00000000 --- a/3rd/libuv-1.19.2/LICENSE-docs +++ /dev/null @@ -1,396 +0,0 @@ -Attribution 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution 4.0 International Public License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution 4.0 International Public License ("Public License"). To the -extent this Public License may be interpreted as a contract, You are -granted the Licensed Rights in consideration of Your acceptance of -these terms and conditions, and the Licensor grants You such rights in -consideration of benefits the Licensor receives from making the -Licensed Material available under these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - d. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - e. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - f. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - g. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - h. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - i. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - j. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - k. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material; and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. - diff --git a/3rd/libuv-1.19.2/MAINTAINERS.md b/3rd/libuv-1.19.2/MAINTAINERS.md deleted file mode 100644 index d85deb00..00000000 --- a/3rd/libuv-1.19.2/MAINTAINERS.md +++ /dev/null @@ -1,43 +0,0 @@ - -# Project Maintainers - -libuv is currently managed by the following individuals: - -* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) -* **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)) -* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) - - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) - - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) -* **Fedor Indutny** ([@indutny](https://github.com/indutny)) - - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) -* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) - - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) -* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) - - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) -* **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/3rd/libuv-1.19.2/Makefile.am b/3rd/libuv-1.19.2/Makefile.am deleted file mode 100644 index ae9d96bc..00000000 --- a/3rd/libuv-1.19.2/Makefile.am +++ /dev/null @@ -1,468 +0,0 @@ -# Copyright (c) 2013, Ben Noordhuis -# -# 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-data-getter-setters.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 += -pthreads -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 -libuv_la_SOURCES += src/win/async.c \ - src/win/atomicops-inl.h \ - src/win/core.c \ - src/win/detect-wakeup.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 -if OS390 -test_run_tests_CFLAGS = -else -test_run_tests_CFLAGS = -Wno-long-long -endif - -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. -test_run_tests_CFLAGS += -pthreads -endif - -test_run_tests_LDFLAGS = -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-connect-unspecified.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-eintr-handling.c \ - test/test-embed.c \ - test/test-emfile.c \ - test/test-env-vars.c \ - test/test-error.c \ - test/test-fail-always.c \ - test/test-fs-copyfile.c \ - test/test-fs-event.c \ - test/test-fs-poll.c \ - test/test-fs.c \ - test/test-fork.c \ - test/test-getters-setters.c \ - test/test-get-currentexe.c \ - test/test-get-loadavg.c \ - test/test-get-memory.c \ - test/test-get-passwd.c \ - test/test-getaddrinfo.c \ - test/test-gethostname.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-pipe-set-fchmod.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-poll-oob.c \ - test/test-process-title.c \ - test/test-process-title-threadsafe.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-alloc-cb-fail.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-tmpdir.c \ - test/test-tty.c \ - test/test-udp-alloc-cb-fail.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-hang-loop.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 LINUX -test_run_tests_CFLAGS += -D_GNU_SOURCE -endif - -if SUNOS -test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 -endif - -if OS390 -test_run_tests_CFLAGS += -D_UNIX03_THREADS \ - -D_UNIX03_SOURCE \ - -D_OPEN_SYS_IF_EXT=1 \ - -D_OPEN_SYS_SOCK_IPV6 \ - -D_OPEN_MSGQ_EXT \ - -D_XOPEN_SOURCE_EXTENDED \ - -D_ALL_SOURCE \ - -D_LARGE_TIME_API \ - -D_OPEN_SYS_FILE_EXT \ - -DPATH_MAX=255 \ - -qCHARS=signed \ - -qXPLINK \ - -qFLOAT=IEEE -endif - -if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE \ - -D_XOPEN_SOURCE=500 \ - -D_LINUX_SOURCE_COMPAT \ - -D_THREAD_SAFE \ - -DHAVE_SYS_AHAFS_EVPRODS_H -include_HEADERS += include/uv-aix.h -libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c -endif - -if ANDROID -include_HEADERS += include/android-ifaddrs.h \ - include/pthread-barrier.h -libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c -endif - -if CYGWIN -include_HEADERS += include/uv-posix.h -libuv_la_CFLAGS += -D_GNU_SOURCE -libuv_la_SOURCES += src/unix/cygwin.c \ - src/unix/bsd-ifaddrs.c \ - src/unix/no-fsevents.c \ - src/unix/no-proctitle.c \ - src/unix/posix-hrtime.c \ - src/unix/posix-poll.c \ - src/unix/procfs-exepath.c \ - src/unix/sysinfo-loadavg.c \ - src/unix/sysinfo-memory.c -endif - -if DARWIN -include_HEADERS += include/uv-darwin.h \ - include/pthread-barrier.h -libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 -libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 -libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/darwin.c \ - src/unix/darwin-proctitle.c \ - src/unix/fsevents.c \ - src/unix/kqueue.c \ - src/unix/proctitle.c -test_run_tests_LDFLAGS += -lutil -endif - -if DRAGONFLY -include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/freebsd.c \ - src/unix/kqueue.c \ - src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil -endif - -if FREEBSD -include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/freebsd.c \ - src/unix/kqueue.c \ - src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil -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/procfs-exepath.c \ - src/unix/proctitle.c \ - src/unix/sysinfo-loadavg.c \ - src/unix/sysinfo-memory.c -test_run_tests_LDFLAGS += -lutil -endif - -if MSYS -libuv_la_CFLAGS += -D_GNU_SOURCE -libuv_la_SOURCES += src/unix/cygwin.c \ - src/unix/bsd-ifaddrs.c \ - src/unix/no-fsevents.c \ - src/unix/no-proctitle.c \ - src/unix/posix-hrtime.c \ - src/unix/posix-poll.c \ - src/unix/procfs-exepath.c \ - src/unix/sysinfo-loadavg.c \ - src/unix/sysinfo-memory.c -endif - -if NETBSD -include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/kqueue.c \ - src/unix/netbsd.c \ - src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil -endif - -if OPENBSD -include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ - src/unix/kqueue.c \ - src/unix/openbsd.c \ - src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil -endif - -if SUNOS -include_HEADERS += include/uv-sunos.h -libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 -libuv_la_SOURCES += src/unix/no-proctitle.c \ - src/unix/sunos.c -endif - -if OS390 -include_HEADERS += include/pthread-barrier.h -libuv_la_CFLAGS += -D_UNIX03_THREADS \ - -D_UNIX03_SOURCE \ - -D_OPEN_SYS_IF_EXT=1 \ - -D_OPEN_MSGQ_EXT \ - -D_XOPEN_SOURCE_EXTENDED \ - -D_ALL_SOURCE \ - -D_LARGE_TIME_API \ - -D_OPEN_SYS_SOCK_IPV6 \ - -D_OPEN_SYS_FILE_EXT \ - -DUV_PLATFORM_SEM_T=int \ - -DPATH_MAX=255 \ - -qCHARS=signed \ - -qXPLINK \ - -qFLOAT=IEEE -libuv_la_LDFLAGS += -qXPLINK -libuv_la_SOURCES += src/unix/pthread-fixes.c \ - src/unix/os390.c \ - src/unix/os390-syscalls.c \ - src/unix/proctitle.c -endif - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/3rd/libuv-1.19.2/Makefile.mingw b/3rd/libuv-1.19.2/Makefile.mingw deleted file mode 100644 index 3acf9e14..00000000 --- a/3rd/libuv-1.19.2/Makefile.mingw +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2013, Ben Noordhuis -# -# 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 \ - -Wstrict-prototypes \ - -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/detect-wakeup.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/3rd/libuv-1.19.2/README.md b/3rd/libuv-1.19.2/README.md deleted file mode 100644 index 733171be..00000000 --- a/3rd/libuv-1.19.2/README.md +++ /dev/null @@ -1,332 +0,0 @@ -![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][], 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. - -The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/). - -## Licensing - -libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). -The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-docs file](LICENSE-docs). - -## Community - - * [Support](https://github.com/libuv/help) - * [Mailing list](http://groups.google.com/group/libuv) - * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) - -## Documentation - -### Official 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: - -```bash -$ make help -``` - -Build documentation as HTML: - -```bash -$ make html -``` - -Build documentation as HTML and live reload it when it changes (this requires -sphinx-autobuild to be installed and is only supported on Unix): - -```bash -$ make livehtml -``` - -Build documentation as man pages: - -```bash -$ make man -``` - -Build documentation as ePub: - -```bash -$ 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 - - * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) - — High-level introductory talk about libuv. - * [libuv-dox](https://github.com/thlorenz/libuv-dox) - — Documenting types and methods of libuv, mostly by reading uv.h. - * [learnuv](https://github.com/thlorenz/learnuv) - — 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: - -```bash -$ gpg --keyserver pool.sks-keyservers.net --recv-keys AE9BC059 -``` - -Importing a key from a git blob object: - -```bash -$ git show pubkey-saghul | gpg --import -``` - -### Verifying releases - -Git tags are signed with the developer's key, they can be verified as follows: - -```bash -$ 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: - -```bash -$ 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: - -```bash -$ sh autogen.sh -$ ./configure -$ make -$ make check -$ make install -``` - -### Windows - -Prerequisites: - -* [Python 2.6 or 2.7][] 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` -* One of: - * [Visual C++ Build Tools][] - * [Visual Studio 2015 Update 3][], all editions - including the Community edition (remember to select - "Common Tools for Visual C++ 2015" feature during installation). - * [Visual Studio 2017][], any edition (including the Build Tools SKU). - **Required Components:** "MSbuild", "VC++ 2017 v141 toolset" and one of the - Windows SDKs (10 or 8.1). -* Basic Unix tools required for some tests, - [Git for Windows][] includes Git Bash - and tools which can be included in the global `PATH`. - -To build, launch a git shell (e.g. Cmd or PowerShell), run `vcbuild.bat` -(to build with VS2017 you need to explicitly add a `vs2017` argument), -which will checkout the GYP code into `build/gyp`, generate `uv.sln` -as well as the necesery related project files, and start building. - -```console -> vcbuild -``` - -Or: - -```console -> vcbuild vs2017 -``` - -To run the tests: - -```console -> vcbuild test -``` - -To see all the options that could passed to `vcbuild`: - -```console -> vcbuild help -vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] -Examples: - vcbuild.bat : builds debug build - vcbuild.bat test : builds debug build and runs tests - vcbuild.bat release bench: builds release build and runs benchmarks -``` - - -### Unix - -For Debug builds (recommended) run: - -```bash -$ ./gyp_uv.py -f make -$ make -C out -``` - -For Release builds run: - -```bash -$ ./gyp_uv.py -f make -$ BUILDTYPE=Release make -C out -``` - -Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. - -### OS X - -Run: - -```bash -$ ./gyp_uv.py -f xcode -$ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ - -configuration Release -target All -``` - -Using Homebrew: - -```bash -$ 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: - -```bash -$ source ./android-configure NDK_PATH gyp [API_LEVEL] -$ make -C out -``` - -The default API level is 24, but a different one can be selected as follows: - -```bash -$ source ./android-configure ~/android-ndk-r15b gyp 21 -$ 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: - -```bash -$ ./gyp_uv.py -f ninja -$ ninja -C out/Debug #for debug build OR -$ ninja -C out/Release -``` - - -### Running tests - -Run: - -```bash -$ ./gyp_uv.py -f make -$ make -C out -$ ./out/Debug/run-tests -``` - -## Supported Platforms - -Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). - -### 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/ -[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md -[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png -[x32]: https://en.wikipedia.org/wiki/X32_ABI -[Python 2.6 or 2.7]: https://www.python.org/downloads/ -[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools -[Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ -[Visual Studio 2017]: https://www.visualstudio.com/downloads/ -[Git for Windows]: http://git-scm.com/download/win diff --git a/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md b/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md deleted file mode 100644 index 07719108..00000000 --- a/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md +++ /dev/null @@ -1,73 +0,0 @@ -# Supported platforms - -| System | Support type | Supported versions | Notes | -|---|---|---|---| -| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | -| macOS | Tier 1 | macOS >= 10.7 | | -| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported | -| FreeBSD | Tier 1 | >= 9 (see note) | | -| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | -| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | -| Linux with musl | Tier 2 | musl >= 1.0 | | -| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | -| Android | Tier 3 | NDK >= r15b | | -| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | -| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | -| SunOS | Tier 3 | Solaris 121 and later | | -| Other | Tier 3 | N/A | | - -#### Note on FreeBSD 9 - -While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until -it reaches end of life, in December 2016. - -## Support types - -* **Tier 1**: Officially supported and tested with CI. Any contributed patch - MUST NOT break such systems. These are supported by @libuv/collaborators. - -* **Tier 2**: Officially supported, but not necessarily tested with CI. These - systems are maintained to the best of @libuv/collaborators ability, - without being a top priority. - -* **Tier 3**: Community maintained. These systems may inadvertently break and the - community and interested parties are expected to help with the maintenance. - -## Adding support for a new platform - -**IMPORTANT**: Before attempting to add support for a new platform please open -an issue about it for discussion. - -### Unix - -I/O handling is abstracted by an internal `uv__io_t` handle. The new platform -will need to implement some of the functions, the prototypes are in -``src/unix/internal.h``. - -If the new platform requires extra fields for any handle structure, create a -new include file in ``include/`` with the name ``uv-theplatform.h`` and add -the appropriate defines there. - -All functionality related to the new platform must be implemented in its own -file inside ``src/unix/`` unless it's already done in a common file, in which -case adding an `ifdef` is fine. - -Two build systems are supported: autotools and GYP. Ideally both need to be -supported, but if GYP does not support the new platform it can be left out. - -### Windows - -Windows is treated as a single platform, so adding support for a new platform -would mean adding support for a new version. - -Compilation and runtime must succeed for the minimum supported version. If a -new API is to be used, it must be done optionally, only in supported versions. - -### Common - -Some common notes when adding support for new platforms: - -* Generally libuv tries to avoid compile time checks. Do not add any to the - autotools based build system or use version checking macros. - Dynamically load functions and symbols if they are not supported by the - minimum supported version. diff --git a/3rd/libuv-1.19.2/android-configure b/3rd/libuv-1.19.2/android-configure deleted file mode 100644 index b5c11cd4..00000000 --- a/3rd/libuv-1.19.2/android-configure +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -export TOOLCHAIN=$PWD/android-toolchain -mkdir -p $TOOLCHAIN -API=${3:-24} -$1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.9 \ - --arch=arm \ - --install-dir=$TOOLCHAIN \ - --platform=android-$API \ - --force -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 -export CFLAGS="-D__ANDROID_API__=$API" - -if [[ $2 == 'gyp' ]] - then - ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android -fi diff --git a/3rd/libuv-1.19.2/appveyor.yml b/3rd/libuv-1.19.2/appveyor.yml deleted file mode 100644 index 1b018a59..00000000 --- a/3rd/libuv-1.19.2/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: v1.18.0.build{build} - -init: - - git config --global core.autocrlf true - -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 - -cache: - - C:\projects\libuv\build\gyp diff --git a/3rd/libuv-1.19.2/autogen.sh b/3rd/libuv-1.19.2/autogen.sh deleted file mode 100644 index 271c2ee8..00000000 --- a/3rd/libuv-1.19.2/autogen.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2013, Ben Noordhuis -# -# 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" --copy -"$ACLOCAL" -I m4 -"$AUTOCONF" -"$AUTOMAKE" --add-missing --copy diff --git a/3rd/libuv-1.19.2/checksparse.sh b/3rd/libuv-1.19.2/checksparse.sh deleted file mode 100644 index 27eb529b..00000000 --- a/3rd/libuv-1.19.2/checksparse.sh +++ /dev/null @@ -1,253 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2013, Ben Noordhuis -# -# 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 -src/uv-data-getter-setters.c -" - -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-env-vars.c -test/test-error.c -test/test-fail-always.c -test/test-fs-copyfile.c -test/test-fs-event.c -test/test-fs-poll.c -test/test-fs.c -test/test-getters-setters.c -test/test-get-currentexe.c -test/test-get-loadavg.c -test/test-get-memory.c -test/test-get-passwd.c -test/test-getaddrinfo.c -test/test-gethostname.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-process-title-threadsafe.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-tmpdir.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-udp-send-hang-loop.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-common.c - src/unix/aix.c" - ;; -OS400) - SPARSE_FLAGS="$SPARSE_FLAGS -D_PASE=1" - SOURCES="$SOURCES - src/unix/aix-common.c - src/unix/ibmi.c - src/unix/posix-poll.c - src/unix/no-fsevents.c - src/unix/no-proctitle.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/3rd/libuv-1.19.2/common.gypi b/3rd/libuv-1.19.2/common.gypi deleted file mode 100644 index 572a1633..00000000 --- a/3rd/libuv-1.19.2/common.gypi +++ /dev/null @@ -1,208 +0,0 @@ -{ - 'variables': { - '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' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['uv_library=="static_library"', { - 'RuntimeLibrary': 1, # /MTd static debug - }, { - 'RuntimeLibrary': 3, # /MDd 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', - }, - 'conditions': [ - ['OS != "zos"', { - 'cflags': [ '-O0', '-fwrapv' ] - }], - ['OS == "android"', { - 'cflags': [ '-fPIE' ], - 'ldflags': [ '-fPIE', '-pie' ] - }] - ] - }, - 'Release': { - 'defines': [ 'NDEBUG' ], - 'cflags': [ - '-O3', - ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'target_conditions': [ - ['uv_library=="static_library"', { - 'RuntimeLibrary': 0, # /MT static release - }, { - 'RuntimeLibrary': 2, # /MD DLL 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 - }, - }, - 'conditions': [ - ['OS != "zos"', { - 'cflags': [ - '-fomit-frame-pointer', - '-fdata-sections', - '-ffunction-sections', - ], - }], - ] - } - }, - '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 zos"', { - 'cflags': [ '-pthread' ], - 'ldflags': [ '-pthread' ], - }], - ], - }], - ['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_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics - 'PREBINDING': 'NO', # No -Wl,-prebind - 'USE_HEADERMAP': 'NO', - 'WARNING_CFLAGS': [ - '-Wall', - '-Wendif-labels', - '-W', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - }, - '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/3rd/libuv-1.19.2/configure.ac b/3rd/libuv-1.19.2/configure.ac deleted file mode 100644 index 4074e778..00000000 --- a/3rd/libuv-1.19.2/configure.ac +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) 2013, Ben Noordhuis -# -# 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.19.2], [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 -AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ - CC_CHECK_CFLAGS_APPEND([-pedantic]) -]) -CC_FLAG_VISIBILITY #[-fvisibility=hidden] -CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) -CC_CHECK_CFLAGS_APPEND([-Wall]) -CC_CHECK_CFLAGS_APPEND([-Wextra]) -CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) -CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) -# 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([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([CYGWIN], [AS_CASE([$host_os],[cygwin*], [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([MSYS], [AS_CASE([$host_os],[msys*], [true], [false])]) -AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) -AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) -AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])]) -AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) -AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) -AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" -]) -AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) -AC_CHECK_HEADERS([sys/ahafs_evProds.h]) -AC_CONFIG_FILES([Makefile libuv.pc]) -AC_OUTPUT diff --git a/3rd/libuv-1.19.2/docs/code/cgi/main.c b/3rd/libuv-1.19.2/docs/code/cgi/main.c deleted file mode 100644 index d2e34265..00000000 --- a/3rd/libuv-1.19.2/docs/code/cgi/main.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include -#include -#include - -uv_loop_t *loop; -uv_process_t child_req; -uv_process_options_t options; - -void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) { - fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); - uv_close((uv_handle_t*) req->data, NULL); - uv_close((uv_handle_t*) req, NULL); -} - -void invoke_cgi_script(uv_tcp_t *client) { - size_t size = 500; - char path[size]; - uv_exepath(path, &size); - strcpy(path + (strlen(path) - strlen("cgi")), "tick"); - - char* args[2]; - args[0] = path; - args[1] = NULL; - - /* ... finding the executable path and setting up arguments ... */ - - options.stdio_count = 3; - uv_stdio_container_t child_stdio[3]; - child_stdio[0].flags = UV_IGNORE; - child_stdio[1].flags = UV_INHERIT_STREAM; - child_stdio[1].data.stream = (uv_stream_t*) client; - child_stdio[2].flags = UV_IGNORE; - options.stdio = child_stdio; - - options.exit_cb = cleanup_handles; - options.file = args[0]; - options.args = args; - - // Set this so we can close the socket after the child process exits. - child_req.data = (void*) client; - int r; - if ((r = uv_spawn(loop, &child_req, &options))) { - fprintf(stderr, "%s\n", uv_strerror(r)); - return; - } -} - -void on_new_connection(uv_stream_t *server, int status) { - if (status == -1) { - // error! - return; - } - - uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, client); - if (uv_accept(server, (uv_stream_t*) client) == 0) { - invoke_cgi_script(client); - } - else { - uv_close((uv_handle_t*) client, NULL); - } -} - -int main() { - loop = uv_default_loop(); - - uv_tcp_t server; - uv_tcp_init(loop, &server); - - struct sockaddr_in bind_addr; - uv_ip4_addr("0.0.0.0", 7000, &bind_addr); - uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); - int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection); - if (r) { - fprintf(stderr, "Listen error %s\n", uv_err_name(r)); - return 1; - } - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/cgi/tick.c b/3rd/libuv-1.19.2/docs/code/cgi/tick.c deleted file mode 100644 index 0b498edf..00000000 --- a/3rd/libuv-1.19.2/docs/code/cgi/tick.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -int main() { - int i; - for (i = 0; i < 10; i++) { - printf("tick\n"); - fflush(stdout); - sleep(1); - } - printf("BOOM!\n"); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/detach/main.c b/3rd/libuv-1.19.2/docs/code/detach/main.c deleted file mode 100644 index 3c88fff4..00000000 --- a/3rd/libuv-1.19.2/docs/code/detach/main.c +++ /dev/null @@ -1,31 +0,0 @@ -#include - -#include - -uv_loop_t *loop; -uv_process_t child_req; -uv_process_options_t options; - -int main() { - loop = uv_default_loop(); - - char* args[3]; - args[0] = "sleep"; - args[1] = "100"; - args[2] = NULL; - - options.exit_cb = NULL; - options.file = "sleep"; - options.args = args; - options.flags = UV_PROCESS_DETACHED; - - int r; - if ((r = uv_spawn(loop, &child_req, &options))) { - fprintf(stderr, "%s\n", uv_strerror(r)); - return 1; - } - fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid); - uv_unref((uv_handle_t*) &child_req); - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/dns/main.c b/3rd/libuv-1.19.2/docs/code/dns/main.c deleted file mode 100644 index 77a7005f..00000000 --- a/3rd/libuv-1.19.2/docs/code/dns/main.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include - -uv_loop_t *loop; - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - -void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, NULL); - free(buf->base); - free(client); - return; - } - - char *data = (char*) malloc(sizeof(char) * (nread+1)); - data[nread] = '\0'; - strncpy(data, buf->base, nread); - - fprintf(stderr, "%s", data); - free(data); - free(buf->base); -} - -void on_connect(uv_connect_t *req, int status) { - if (status < 0) { - fprintf(stderr, "connect failed error %s\n", uv_err_name(status)); - free(req); - return; - } - - uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read); - free(req); -} - -void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { - if (status < 0) { - fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status)); - return; - } - - char addr[17] = {'\0'}; - uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16); - fprintf(stderr, "%s\n", addr); - - uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); - uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, socket); - - uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect); - - uv_freeaddrinfo(res); -} - -int main() { - loop = uv_default_loop(); - - struct addrinfo hints; - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = 0; - - uv_getaddrinfo_t resolver; - fprintf(stderr, "irc.freenode.net is... "); - int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints); - - if (r) { - fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); - return 1; - } - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/helloworld/main.c b/3rd/libuv-1.19.2/docs/code/helloworld/main.c deleted file mode 100644 index a31bf88a..00000000 --- a/3rd/libuv-1.19.2/docs/code/helloworld/main.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include - -int main() { - uv_loop_t *loop = malloc(sizeof(uv_loop_t)); - uv_loop_init(loop); - - printf("Now quitting.\n"); - uv_run(loop, UV_RUN_DEFAULT); - - uv_loop_close(loop); - free(loop); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/idle-basic/main.c b/3rd/libuv-1.19.2/docs/code/idle-basic/main.c deleted file mode 100644 index 77ba31cf..00000000 --- a/3rd/libuv-1.19.2/docs/code/idle-basic/main.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -int64_t counter = 0; - -void wait_for_a_while(uv_idle_t* handle) { - counter++; - - if (counter >= 10e6) - uv_idle_stop(handle); -} - -int main() { - uv_idle_t idler; - - uv_idle_init(uv_default_loop(), &idler); - uv_idle_start(&idler, wait_for_a_while); - - printf("Idling...\n"); - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - uv_loop_close(uv_default_loop()); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/idle-compute/main.c b/3rd/libuv-1.19.2/docs/code/idle-compute/main.c deleted file mode 100644 index ff44b694..00000000 --- a/3rd/libuv-1.19.2/docs/code/idle-compute/main.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#include - -uv_loop_t *loop; -uv_fs_t stdin_watcher; -uv_idle_t idler; -char buffer[1024]; - -void crunch_away(uv_idle_t* handle) { - // Compute extra-terrestrial life - // fold proteins - // computer another digit of PI - // or similar - fprintf(stderr, "Computing PI...\n"); - // just to avoid overwhelming your terminal emulator - uv_idle_stop(handle); -} - -void on_type(uv_fs_t *req) { - if (stdin_watcher.result > 0) { - buffer[stdin_watcher.result] = '\0'; - printf("Typed %s\n", buffer); - - uv_buf_t buf = uv_buf_init(buffer, 1024); - uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); - uv_idle_start(&idler, crunch_away); - } - else if (stdin_watcher.result < 0) { - fprintf(stderr, "error opening file: %s\n", uv_strerror(req->result)); - } -} - -int main() { - loop = uv_default_loop(); - - uv_idle_init(loop, &idler); - - uv_buf_t buf = uv_buf_init(buffer, 1024); - uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); - uv_idle_start(&idler, crunch_away); - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/interfaces/main.c b/3rd/libuv-1.19.2/docs/code/interfaces/main.c deleted file mode 100644 index cac12c26..00000000 --- a/3rd/libuv-1.19.2/docs/code/interfaces/main.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int main() { - char buf[512]; - uv_interface_address_t *info; - int count, i; - - uv_interface_addresses(&info, &count); - i = count; - - printf("Number of interfaces: %d\n", count); - while (i--) { - uv_interface_address_t interface = info[i]; - - printf("Name: %s\n", interface.name); - printf("Internal? %s\n", interface.is_internal ? "Yes" : "No"); - - if (interface.address.address4.sin_family == AF_INET) { - uv_ip4_name(&interface.address.address4, buf, sizeof(buf)); - printf("IPv4 address: %s\n", buf); - } - else if (interface.address.address4.sin_family == AF_INET6) { - uv_ip6_name(&interface.address.address6, buf, sizeof(buf)); - printf("IPv6 address: %s\n", buf); - } - - printf("\n"); - } - - uv_free_interface_addresses(info, count); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/locks/main.c b/3rd/libuv-1.19.2/docs/code/locks/main.c deleted file mode 100644 index 2b1f8ca7..00000000 --- a/3rd/libuv-1.19.2/docs/code/locks/main.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include - -uv_barrier_t blocker; -uv_rwlock_t numlock; -int shared_num; - -void reader(void *n) -{ - int num = *(int *)n; - int i; - for (i = 0; i < 20; i++) { - uv_rwlock_rdlock(&numlock); - printf("Reader %d: acquired lock\n", num); - printf("Reader %d: shared num = %d\n", num, shared_num); - uv_rwlock_rdunlock(&numlock); - printf("Reader %d: released lock\n", num); - } - uv_barrier_wait(&blocker); -} - -void writer(void *n) -{ - int num = *(int *)n; - int i; - for (i = 0; i < 20; i++) { - uv_rwlock_wrlock(&numlock); - printf("Writer %d: acquired lock\n", num); - shared_num++; - printf("Writer %d: incremented shared num = %d\n", num, shared_num); - uv_rwlock_wrunlock(&numlock); - printf("Writer %d: released lock\n", num); - } - uv_barrier_wait(&blocker); -} - -int main() -{ - uv_barrier_init(&blocker, 4); - - shared_num = 0; - uv_rwlock_init(&numlock); - - uv_thread_t threads[3]; - - int thread_nums[] = {1, 2, 1}; - uv_thread_create(&threads[0], reader, &thread_nums[0]); - uv_thread_create(&threads[1], reader, &thread_nums[1]); - - uv_thread_create(&threads[2], writer, &thread_nums[2]); - - uv_barrier_wait(&blocker); - uv_barrier_destroy(&blocker); - - uv_rwlock_destroy(&numlock); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js b/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js deleted file mode 100644 index 5df345b7..00000000 --- a/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js +++ /dev/null @@ -1,20 +0,0 @@ -var net = require('net'); - -var PHRASE = "hello world"; -var write = function(socket) { - socket.write(PHRASE, 'utf8'); -} - -for (var i = 0; i < 1000; i++) { -(function() { - var socket = net.connect(7000, 'localhost', function() { - socket.on('data', function(reply) { - if (reply.toString().indexOf(PHRASE) != 0) - console.error("Problem! '" + reply + "'" + " '" + PHRASE + "'"); - else - write(socket); - }); - write(socket); - }); -})(); -} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c deleted file mode 100644 index 25f49612..00000000 --- a/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c +++ /dev/null @@ -1,114 +0,0 @@ -#include -#include -#include -#include -#include - -uv_loop_t *loop; - -struct child_worker { - uv_process_t req; - uv_process_options_t options; - uv_pipe_t pipe; -} *workers; - -int round_robin_counter; -int child_worker_count; - -uv_buf_t dummy_buf; -char worker_path[500]; - -void close_process_handle(uv_process_t *req, int64_t exit_status, int term_signal) { - fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); - uv_close((uv_handle_t*) req, NULL); -} - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - -void on_new_connection(uv_stream_t *server, int status) { - if (status == -1) { - // error! - return; - } - - uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, client); - if (uv_accept(server, (uv_stream_t*) client) == 0) { - uv_write_t *write_req = (uv_write_t*) malloc(sizeof(uv_write_t)); - dummy_buf = uv_buf_init("a", 1); - struct child_worker *worker = &workers[round_robin_counter]; - uv_write2(write_req, (uv_stream_t*) &worker->pipe, &dummy_buf, 1, (uv_stream_t*) client, NULL); - round_robin_counter = (round_robin_counter + 1) % child_worker_count; - } - else { - uv_close((uv_handle_t*) client, NULL); - } -} - -void setup_workers() { - size_t path_size = 500; - uv_exepath(worker_path, &path_size); - strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker"); - fprintf(stderr, "Worker path: %s\n", worker_path); - - char* args[2]; - args[0] = worker_path; - args[1] = NULL; - - round_robin_counter = 0; - - // ... - - // launch same number of workers as number of CPUs - uv_cpu_info_t *info; - int cpu_count; - uv_cpu_info(&info, &cpu_count); - uv_free_cpu_info(info, cpu_count); - - child_worker_count = cpu_count; - - workers = calloc(sizeof(struct child_worker), cpu_count); - while (cpu_count--) { - struct child_worker *worker = &workers[cpu_count]; - uv_pipe_init(loop, &worker->pipe, 1); - - uv_stdio_container_t child_stdio[3]; - child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; - child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe; - child_stdio[1].flags = UV_IGNORE; - child_stdio[2].flags = UV_INHERIT_FD; - child_stdio[2].data.fd = 2; - - worker->options.stdio = child_stdio; - worker->options.stdio_count = 3; - - worker->options.exit_cb = close_process_handle; - worker->options.file = args[0]; - worker->options.args = args; - - uv_spawn(loop, &worker->req, &worker->options); - fprintf(stderr, "Started worker %d\n", worker->req.pid); - } -} - -int main() { - loop = uv_default_loop(); - - setup_workers(); - - uv_tcp_t server; - uv_tcp_init(loop, &server); - - struct sockaddr_in bind_addr; - uv_ip4_addr("0.0.0.0", 7000, &bind_addr); - uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); - int r; - if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { - fprintf(stderr, "Listen error %s\n", uv_err_name(r)); - return 2; - } - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c deleted file mode 100644 index 1c465759..00000000 --- a/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include -#include -#include -#include - -uv_loop_t *loop; -uv_pipe_t queue; - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} write_req_t; - -void free_write_req(uv_write_t *req) { - write_req_t *wr = (write_req_t*) req; - free(wr->buf.base); - free(wr); -} - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - -void echo_write(uv_write_t *req, int status) { - if (status) { - fprintf(stderr, "Write error %s\n", uv_err_name(status)); - } - free_write_req(req); -} - -void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { - if (nread > 0) { - write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); - req->buf = uv_buf_init(buf->base, nread); - uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); - return; - } - - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, NULL); - } - - free(buf->base); -} - -void on_new_connection(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf) { - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) q, NULL); - return; - } - - uv_pipe_t *pipe = (uv_pipe_t*) q; - if (!uv_pipe_pending_count(pipe)) { - fprintf(stderr, "No pending count\n"); - return; - } - - uv_handle_type pending = uv_pipe_pending_type(pipe); - assert(pending == UV_TCP); - - uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, client); - if (uv_accept(q, (uv_stream_t*) client) == 0) { - uv_os_fd_t fd; - uv_fileno((const uv_handle_t*) client, &fd); - fprintf(stderr, "Worker %d: Accepted fd %d\n", getpid(), fd); - uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); - } - else { - uv_close((uv_handle_t*) client, NULL); - } -} - -int main() { - loop = uv_default_loop(); - - uv_pipe_init(loop, &queue, 1 /* ipc */); - uv_pipe_open(&queue, 0); - uv_read_start((uv_stream_t*)&queue, alloc_buffer, on_new_connection); - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/onchange/main.c b/3rd/libuv-1.19.2/docs/code/onchange/main.c deleted file mode 100644 index 40bdaa52..00000000 --- a/3rd/libuv-1.19.2/docs/code/onchange/main.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include - -uv_loop_t *loop; -const char *command; - -void run_command(uv_fs_event_t *handle, const char *filename, int events, int status) { - char path[1024]; - size_t size = 1023; - // Does not handle error if path is longer than 1023. - uv_fs_event_getpath(handle, path, &size); - path[size] = '\0'; - - fprintf(stderr, "Change detected in %s: ", path); - if (events & UV_RENAME) - fprintf(stderr, "renamed"); - if (events & UV_CHANGE) - fprintf(stderr, "changed"); - - fprintf(stderr, " %s\n", filename ? filename : ""); - system(command); -} - -int main(int argc, char **argv) { - if (argc <= 2) { - fprintf(stderr, "Usage: %s [file2 ...]\n", argv[0]); - return 1; - } - - loop = uv_default_loop(); - command = argv[1]; - - while (argc-- > 2) { - fprintf(stderr, "Adding watch on %s\n", argv[argc]); - uv_fs_event_t *fs_event_req = malloc(sizeof(uv_fs_event_t)); - uv_fs_event_init(loop, fs_event_req); - // The recursive flag watches subdirectories too. - uv_fs_event_start(fs_event_req, run_command, argv[argc], UV_FS_EVENT_RECURSIVE); - } - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c deleted file mode 100644 index 4f28fd03..00000000 --- a/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include -#include - -#ifdef _WIN32 -#define PIPENAME "\\\\?\\pipe\\echo.sock" -#else -#define PIPENAME "/tmp/echo.sock" -#endif - -uv_loop_t *loop; - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} write_req_t; - -void free_write_req(uv_write_t *req) { - write_req_t *wr = (write_req_t*) req; - free(wr->buf.base); - free(wr); -} - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - -void echo_write(uv_write_t *req, int status) { - if (status < 0) { - fprintf(stderr, "Write error %s\n", uv_err_name(status)); - } - free_write_req(req); -} - -void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { - if (nread > 0) { - write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); - req->buf = uv_buf_init(buf->base, nread); - uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); - return; - } - - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, NULL); - } - - free(buf->base); -} - -void on_new_connection(uv_stream_t *server, int status) { - if (status == -1) { - // error! - return; - } - - uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t)); - uv_pipe_init(loop, client, 0); - if (uv_accept(server, (uv_stream_t*) client) == 0) { - uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); - } - else { - uv_close((uv_handle_t*) client, NULL); - } -} - -void remove_sock(int sig) { - uv_fs_t req; - uv_fs_unlink(loop, &req, PIPENAME, NULL); - exit(0); -} - -int main() { - loop = uv_default_loop(); - - uv_pipe_t server; - uv_pipe_init(loop, &server, 0); - - signal(SIGINT, remove_sock); - - int r; - if ((r = uv_pipe_bind(&server, PIPENAME))) { - fprintf(stderr, "Bind error %s\n", uv_err_name(r)); - return 1; - } - if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { - fprintf(stderr, "Listen error %s\n", uv_err_name(r)); - return 2; - } - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/hello.c b/3rd/libuv-1.19.2/docs/code/plugin/hello.c deleted file mode 100644 index 7b2861d7..00000000 --- a/3rd/libuv-1.19.2/docs/code/plugin/hello.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "plugin.h" - -void initialize() { - mfp_register("Hello World!"); -} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/main.c b/3rd/libuv-1.19.2/docs/code/plugin/main.c deleted file mode 100644 index 06e581e6..00000000 --- a/3rd/libuv-1.19.2/docs/code/plugin/main.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include - -#include - -#include "plugin.h" - -typedef void (*init_plugin_function)(); - -void mfp_register(const char *name) { - fprintf(stderr, "Registered plugin \"%s\"\n", name); -} - -int main(int argc, char **argv) { - if (argc == 1) { - fprintf(stderr, "Usage: %s [plugin1] [plugin2] ...\n", argv[0]); - return 0; - } - - uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t)); - while (--argc) { - fprintf(stderr, "Loading %s\n", argv[argc]); - if (uv_dlopen(argv[argc], lib)) { - fprintf(stderr, "Error: %s\n", uv_dlerror(lib)); - continue; - } - - init_plugin_function init_plugin; - if (uv_dlsym(lib, "initialize", (void **) &init_plugin)) { - fprintf(stderr, "dlsym error: %s\n", uv_dlerror(lib)); - continue; - } - - init_plugin(); - } - - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/plugin.h b/3rd/libuv-1.19.2/docs/code/plugin/plugin.h deleted file mode 100644 index 21f194e6..00000000 --- a/3rd/libuv-1.19.2/docs/code/plugin/plugin.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UVBOOK_PLUGIN_SYSTEM -#define UVBOOK_PLUGIN_SYSTEM - -// Plugin authors should use this to register their plugins with mfp. -void mfp_register(const char *name); - -#endif diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/main.c b/3rd/libuv-1.19.2/docs/code/proc-streams/main.c deleted file mode 100644 index b8a65212..00000000 --- a/3rd/libuv-1.19.2/docs/code/proc-streams/main.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include - -#include - -uv_loop_t *loop; -uv_process_t child_req; -uv_process_options_t options; - -void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { - fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); - uv_close((uv_handle_t*) req, NULL); -} - -int main() { - loop = uv_default_loop(); - - size_t size = 500; - char path[size]; - uv_exepath(path, &size); - strcpy(path + (strlen(path) - strlen("proc-streams")), "test"); - - char* args[2]; - args[0] = path; - args[1] = NULL; - - /* ... */ - - options.stdio_count = 3; - uv_stdio_container_t child_stdio[3]; - child_stdio[0].flags = UV_IGNORE; - child_stdio[1].flags = UV_IGNORE; - child_stdio[2].flags = UV_INHERIT_FD; - child_stdio[2].data.fd = 2; - options.stdio = child_stdio; - - options.exit_cb = on_exit; - options.file = args[0]; - options.args = args; - - int r; - if ((r = uv_spawn(loop, &child_req, &options))) { - fprintf(stderr, "%s\n", uv_strerror(r)); - return 1; - } - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/test.c b/3rd/libuv-1.19.2/docs/code/proc-streams/test.c deleted file mode 100644 index 7c45c1fd..00000000 --- a/3rd/libuv-1.19.2/docs/code/proc-streams/test.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int main() -{ - fprintf(stderr, "This is stderr\n"); - printf("This is stdout\n"); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/progress/main.c b/3rd/libuv-1.19.2/docs/code/progress/main.c deleted file mode 100644 index 5af01f14..00000000 --- a/3rd/libuv-1.19.2/docs/code/progress/main.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include - -#include - -uv_loop_t *loop; -uv_async_t async; - -double percentage; - -void fake_download(uv_work_t *req) { - int size = *((int*) req->data); - int downloaded = 0; - while (downloaded < size) { - percentage = downloaded*100.0/size; - async.data = (void*) &percentage; - uv_async_send(&async); - - sleep(1); - downloaded += (200+random())%1000; // can only download max 1000bytes/sec, - // but at least a 200; - } -} - -void after(uv_work_t *req, int status) { - fprintf(stderr, "Download complete\n"); - uv_close((uv_handle_t*) &async, NULL); -} - -void print_progress(uv_async_t *handle) { - double percentage = *((double*) handle->data); - fprintf(stderr, "Downloaded %.2f%%\n", percentage); -} - -int main() { - loop = uv_default_loop(); - - uv_work_t req; - int size = 10240; - req.data = (void*) &size; - - uv_async_init(loop, &async, print_progress); - uv_queue_work(loop, &req, fake_download, after); - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c b/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c deleted file mode 100644 index 3f7836cb..00000000 --- a/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include - -#include - -#define FIB_UNTIL 25 -uv_loop_t *loop; -uv_work_t fib_reqs[FIB_UNTIL]; - -long fib_(long t) { - if (t == 0 || t == 1) - return 1; - else - return fib_(t-1) + fib_(t-2); -} - -void fib(uv_work_t *req) { - int n = *(int *) req->data; - if (random() % 2) - sleep(1); - else - sleep(3); - long fib = fib_(n); - fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); -} - -void after_fib(uv_work_t *req, int status) { - if (status == UV_ECANCELED) - fprintf(stderr, "Calculation of %d cancelled.\n", *(int *) req->data); -} - -void signal_handler(uv_signal_t *req, int signum) -{ - printf("Signal received!\n"); - int i; - for (i = 0; i < FIB_UNTIL; i++) { - uv_cancel((uv_req_t*) &fib_reqs[i]); - } - uv_signal_stop(req); -} - -int main() { - loop = uv_default_loop(); - - int data[FIB_UNTIL]; - int i; - for (i = 0; i < FIB_UNTIL; i++) { - data[i] = i; - fib_reqs[i].data = (void *) &data[i]; - uv_queue_work(loop, &fib_reqs[i], fib, after_fib); - } - - uv_signal_t sig; - uv_signal_init(loop, &sig); - uv_signal_start(&sig, signal_handler, SIGINT); - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/queue-work/main.c b/3rd/libuv-1.19.2/docs/code/queue-work/main.c deleted file mode 100644 index 55675ea0..00000000 --- a/3rd/libuv-1.19.2/docs/code/queue-work/main.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include - -#include - -#define FIB_UNTIL 25 -uv_loop_t *loop; - -long fib_(long t) { - if (t == 0 || t == 1) - return 1; - else - return fib_(t-1) + fib_(t-2); -} - -void fib(uv_work_t *req) { - int n = *(int *) req->data; - if (random() % 2) - sleep(1); - else - sleep(3); - long fib = fib_(n); - fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); -} - -void after_fib(uv_work_t *req, int status) { - fprintf(stderr, "Done calculating %dth fibonacci\n", *(int *) req->data); -} - -int main() { - loop = uv_default_loop(); - - int data[FIB_UNTIL]; - uv_work_t req[FIB_UNTIL]; - int i; - for (i = 0; i < FIB_UNTIL; i++) { - data[i] = i; - req[i].data = (void *) &data[i]; - uv_queue_work(loop, &req[i], fib, after_fib); - } - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/ref-timer/main.c b/3rd/libuv-1.19.2/docs/code/ref-timer/main.c deleted file mode 100644 index ad7c8295..00000000 --- a/3rd/libuv-1.19.2/docs/code/ref-timer/main.c +++ /dev/null @@ -1,29 +0,0 @@ -#include - -#include - -uv_loop_t *loop; -uv_timer_t gc_req; -uv_timer_t fake_job_req; - -void gc(uv_timer_t *handle) { - fprintf(stderr, "Freeing unused objects\n"); -} - -void fake_job(uv_timer_t *handle) { - fprintf(stdout, "Fake job done\n"); -} - -int main() { - loop = uv_default_loop(); - - uv_timer_init(loop, &gc_req); - uv_unref((uv_handle_t*) &gc_req); - - uv_timer_start(&gc_req, gc, 0, 2000); - - // could actually be a TCP download or something - uv_timer_init(loop, &fake_job_req); - uv_timer_start(&fake_job_req, fake_job, 9000, 0); - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/signal/main.c b/3rd/libuv-1.19.2/docs/code/signal/main.c deleted file mode 100644 index 1b982c5a..00000000 --- a/3rd/libuv-1.19.2/docs/code/signal/main.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include - -uv_loop_t* create_loop() -{ - uv_loop_t *loop = malloc(sizeof(uv_loop_t)); - if (loop) { - uv_loop_init(loop); - } - return loop; -} - -void signal_handler(uv_signal_t *handle, int signum) -{ - printf("Signal received: %d\n", signum); - uv_signal_stop(handle); -} - -// two signal handlers in one loop -void thread1_worker(void *userp) -{ - uv_loop_t *loop1 = create_loop(); - - uv_signal_t sig1a, sig1b; - uv_signal_init(loop1, &sig1a); - uv_signal_start(&sig1a, signal_handler, SIGUSR1); - - uv_signal_init(loop1, &sig1b); - uv_signal_start(&sig1b, signal_handler, SIGUSR1); - - uv_run(loop1, UV_RUN_DEFAULT); -} - -// two signal handlers, each in its own loop -void thread2_worker(void *userp) -{ - uv_loop_t *loop2 = create_loop(); - uv_loop_t *loop3 = create_loop(); - - uv_signal_t sig2; - uv_signal_init(loop2, &sig2); - uv_signal_start(&sig2, signal_handler, SIGUSR1); - - uv_signal_t sig3; - uv_signal_init(loop3, &sig3); - uv_signal_start(&sig3, signal_handler, SIGUSR1); - - while (uv_run(loop2, UV_RUN_NOWAIT) || uv_run(loop3, UV_RUN_NOWAIT)) { - } -} - -int main() -{ - printf("PID %d\n", getpid()); - - uv_thread_t thread1, thread2; - - uv_thread_create(&thread1, thread1_worker, 0); - uv_thread_create(&thread2, thread2_worker, 0); - - uv_thread_join(&thread1); - uv_thread_join(&thread2); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/spawn/main.c b/3rd/libuv-1.19.2/docs/code/spawn/main.c deleted file mode 100644 index dedfe00c..00000000 --- a/3rd/libuv-1.19.2/docs/code/spawn/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -#include - -uv_loop_t *loop; -uv_process_t child_req; -uv_process_options_t options; - -void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { - fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); - uv_close((uv_handle_t*) req, NULL); -} - -int main() { - loop = uv_default_loop(); - - char* args[3]; - args[0] = "mkdir"; - args[1] = "test-dir"; - args[2] = NULL; - - options.exit_cb = on_exit; - options.file = "mkdir"; - options.args = args; - - int r; - if ((r = uv_spawn(loop, &child_req, &options))) { - fprintf(stderr, "%s\n", uv_strerror(r)); - return 1; - } else { - fprintf(stderr, "Launched process with ID %d\n", child_req.pid); - } - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c deleted file mode 100644 index 5d7b4993..00000000 --- a/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include - -#define DEFAULT_PORT 7000 -#define DEFAULT_BACKLOG 128 - -uv_loop_t *loop; -struct sockaddr_in addr; - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} write_req_t; - -void free_write_req(uv_write_t *req) { - write_req_t *wr = (write_req_t*) req; - free(wr->buf.base); - free(wr); -} - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = (char*) malloc(suggested_size); - buf->len = suggested_size; -} - -void on_close(uv_handle_t* handle) { - free(handle); -} - -void echo_write(uv_write_t *req, int status) { - if (status) { - fprintf(stderr, "Write error %s\n", uv_strerror(status)); - } - free_write_req(req); -} - -void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { - if (nread > 0) { - write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); - req->buf = uv_buf_init(buf->base, nread); - uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); - return; - } - if (nread < 0) { - if (nread != UV_EOF) - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, on_close); - } - - free(buf->base); -} - -void on_new_connection(uv_stream_t *server, int status) { - if (status < 0) { - fprintf(stderr, "New connection error %s\n", uv_strerror(status)); - // error! - return; - } - - uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, client); - if (uv_accept(server, (uv_stream_t*) client) == 0) { - uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); - } - else { - uv_close((uv_handle_t*) client, on_close); - } -} - -int main() { - loop = uv_default_loop(); - - uv_tcp_t server; - uv_tcp_init(loop, &server); - - uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr); - - uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); - int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection); - if (r) { - fprintf(stderr, "Listen error %s\n", uv_strerror(r)); - return 1; - } - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/thread-create/main.c b/3rd/libuv-1.19.2/docs/code/thread-create/main.c deleted file mode 100644 index 70224c1e..00000000 --- a/3rd/libuv-1.19.2/docs/code/thread-create/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -#include - -void hare(void *arg) { - int tracklen = *((int *) arg); - while (tracklen) { - tracklen--; - sleep(1); - fprintf(stderr, "Hare ran another step\n"); - } - fprintf(stderr, "Hare done running!\n"); -} - -void tortoise(void *arg) { - int tracklen = *((int *) arg); - while (tracklen) { - tracklen--; - fprintf(stderr, "Tortoise ran another step\n"); - sleep(3); - } - fprintf(stderr, "Tortoise done running!\n"); -} - -int main() { - int tracklen = 10; - uv_thread_t hare_id; - uv_thread_t tortoise_id; - uv_thread_create(&hare_id, hare, &tracklen); - uv_thread_create(&tortoise_id, tortoise, &tracklen); - - uv_thread_join(&hare_id); - uv_thread_join(&tortoise_id); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c b/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c deleted file mode 100644 index 053e7e59..00000000 --- a/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include - -uv_loop_t *loop; -uv_tty_t tty; -uv_timer_t tick; -uv_write_t write_req; -int width, height; -int pos = 0; -char *message = " Hello TTY "; - -void update(uv_timer_t *req) { - char data[500]; - - uv_buf_t buf; - buf.base = data; - buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%luC\033[42;37m%s", - pos, - (unsigned long) (width-strlen(message))/2, - message); - uv_write(&write_req, (uv_stream_t*) &tty, &buf, 1, NULL); - - pos++; - if (pos > height) { - uv_tty_reset_mode(); - uv_timer_stop(&tick); - } -} - -int main() { - loop = uv_default_loop(); - - uv_tty_init(loop, &tty, 1, 0); - uv_tty_set_mode(&tty, 0); - - if (uv_tty_get_winsize(&tty, &width, &height)) { - fprintf(stderr, "Could not get TTY information\n"); - uv_tty_reset_mode(); - return 1; - } - - fprintf(stderr, "Width %d, height %d\n", width, height); - uv_timer_init(loop, &tick); - uv_timer_start(&tick, update, 200, 200); - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/tty/main.c b/3rd/libuv-1.19.2/docs/code/tty/main.c deleted file mode 100644 index 03b26fbc..00000000 --- a/3rd/libuv-1.19.2/docs/code/tty/main.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include - -uv_loop_t *loop; -uv_tty_t tty; -int main() { - loop = uv_default_loop(); - - uv_tty_init(loop, &tty, 1, 0); - uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL); - - if (uv_guess_handle(1) == UV_TTY) { - uv_write_t req; - uv_buf_t buf; - buf.base = "\033[41;37m"; - buf.len = strlen(buf.base); - uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); - } - - uv_write_t req; - uv_buf_t buf; - buf.base = "Hello TTY\n"; - buf.len = strlen(buf.base); - uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); - uv_tty_reset_mode(); - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c b/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c deleted file mode 100644 index fc2ca0c8..00000000 --- a/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#include -#include - -#include - -uv_loop_t *loop; -uv_udp_t send_socket; -uv_udp_t recv_socket; - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - -void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { - if (nread < 0) { - fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) req, NULL); - free(buf->base); - return; - } - - char sender[17] = { 0 }; - uv_ip4_name((const struct sockaddr_in*) addr, sender, 16); - fprintf(stderr, "Recv from %s\n", sender); - - // ... DHCP specific code - unsigned int *as_integer = (unsigned int*)buf->base; - unsigned int ipbin = ntohl(as_integer[4]); - unsigned char ip[4] = {0}; - int i; - for (i = 0; i < 4; i++) - ip[i] = (ipbin >> i*8) & 0xff; - fprintf(stderr, "Offered IP %d.%d.%d.%d\n", ip[3], ip[2], ip[1], ip[0]); - - free(buf->base); - uv_udp_recv_stop(req); -} - -uv_buf_t make_discover_msg() { - uv_buf_t buffer; - alloc_buffer(NULL, 256, &buffer); - memset(buffer.base, 0, buffer.len); - - // BOOTREQUEST - buffer.base[0] = 0x1; - // HTYPE ethernet - buffer.base[1] = 0x1; - // HLEN - buffer.base[2] = 0x6; - // HOPS - buffer.base[3] = 0x0; - // XID 4 bytes - buffer.base[4] = (unsigned int) random(); - // SECS - buffer.base[8] = 0x0; - // FLAGS - buffer.base[10] = 0x80; - // CIADDR 12-15 is all zeros - // YIADDR 16-19 is all zeros - // SIADDR 20-23 is all zeros - // GIADDR 24-27 is all zeros - // CHADDR 28-43 is the MAC address, use your own - buffer.base[28] = 0xe4; - buffer.base[29] = 0xce; - buffer.base[30] = 0x8f; - buffer.base[31] = 0x13; - buffer.base[32] = 0xf6; - buffer.base[33] = 0xd4; - // SNAME 64 bytes zero - // FILE 128 bytes zero - // OPTIONS - // - magic cookie - buffer.base[236] = 99; - buffer.base[237] = 130; - buffer.base[238] = 83; - buffer.base[239] = 99; - - // DHCP Message type - buffer.base[240] = 53; - buffer.base[241] = 1; - buffer.base[242] = 1; // DHCPDISCOVER - - // DHCP Parameter request list - buffer.base[243] = 55; - buffer.base[244] = 4; - buffer.base[245] = 1; - buffer.base[246] = 3; - buffer.base[247] = 15; - buffer.base[248] = 6; - - return buffer; -} - -void on_send(uv_udp_send_t *req, int status) { - if (status) { - fprintf(stderr, "Send error %s\n", uv_strerror(status)); - return; - } -} - -int main() { - loop = uv_default_loop(); - - uv_udp_init(loop, &recv_socket); - struct sockaddr_in recv_addr; - uv_ip4_addr("0.0.0.0", 68, &recv_addr); - uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); - uv_udp_recv_start(&recv_socket, alloc_buffer, on_read); - - uv_udp_init(loop, &send_socket); - struct sockaddr_in broadcast_addr; - uv_ip4_addr("0.0.0.0", 0, &broadcast_addr); - uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0); - uv_udp_set_broadcast(&send_socket, 1); - - uv_udp_send_t send_req; - uv_buf_t discover_msg = make_discover_msg(); - - struct sockaddr_in send_addr; - uv_ip4_addr("255.255.255.255", 67, &send_addr); - uv_udp_send(&send_req, &send_socket, &discover_msg, 1, (const struct sockaddr *)&send_addr, on_send); - - return uv_run(loop, UV_RUN_DEFAULT); -} diff --git a/3rd/libuv-1.19.2/docs/code/uvcat/main.c b/3rd/libuv-1.19.2/docs/code/uvcat/main.c deleted file mode 100644 index b03b0944..00000000 --- a/3rd/libuv-1.19.2/docs/code/uvcat/main.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include -#include -#include - -void on_read(uv_fs_t *req); - -uv_fs_t open_req; -uv_fs_t read_req; -uv_fs_t write_req; - -static char buffer[1024]; - -static uv_buf_t iov; - -void on_write(uv_fs_t *req) { - if (req->result < 0) { - fprintf(stderr, "Write error: %s\n", uv_strerror((int)req->result)); - } - else { - uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1, on_read); - } -} - -void on_read(uv_fs_t *req) { - if (req->result < 0) { - fprintf(stderr, "Read error: %s\n", uv_strerror(req->result)); - } - else if (req->result == 0) { - uv_fs_t close_req; - // synchronous - uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); - } - else if (req->result > 0) { - iov.len = req->result; - uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write); - } -} - -void on_open(uv_fs_t *req) { - // The request passed to the callback is the same as the one the call setup - // function was passed. - assert(req == &open_req); - if (req->result >= 0) { - iov = uv_buf_init(buffer, sizeof(buffer)); - uv_fs_read(uv_default_loop(), &read_req, req->result, - &iov, 1, -1, on_read); - } - else { - fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result)); - } -} - -int main(int argc, char **argv) { - uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open); - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - uv_fs_req_cleanup(&open_req); - uv_fs_req_cleanup(&read_req); - uv_fs_req_cleanup(&write_req); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/uvstop/main.c b/3rd/libuv-1.19.2/docs/code/uvstop/main.c deleted file mode 100644 index 7aa53b76..00000000 --- a/3rd/libuv-1.19.2/docs/code/uvstop/main.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -int64_t counter = 0; - -void idle_cb(uv_idle_t *handle) { - printf("Idle callback\n"); - counter++; - - if (counter >= 5) { - uv_stop(uv_default_loop()); - printf("uv_stop() called\n"); - } -} - -void prep_cb(uv_prepare_t *handle) { - printf("Prep callback\n"); -} - -int main() { - uv_idle_t idler; - uv_prepare_t prep; - - uv_idle_init(uv_default_loop(), &idler); - uv_idle_start(&idler, idle_cb); - - uv_prepare_init(uv_default_loop(), &prep); - uv_prepare_start(&prep, prep_cb); - - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/uvtee/main.c b/3rd/libuv-1.19.2/docs/code/uvtee/main.c deleted file mode 100644 index 6216c2eb..00000000 --- a/3rd/libuv-1.19.2/docs/code/uvtee/main.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} write_req_t; - -uv_loop_t *loop; -uv_pipe_t stdin_pipe; -uv_pipe_t stdout_pipe; -uv_pipe_t file_pipe; - -void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { - *buf = uv_buf_init((char*) malloc(suggested_size), suggested_size); -} - -void free_write_req(uv_write_t *req) { - write_req_t *wr = (write_req_t*) req; - free(wr->buf.base); - free(wr); -} - -void on_stdout_write(uv_write_t *req, int status) { - free_write_req(req); -} - -void on_file_write(uv_write_t *req, int status) { - free_write_req(req); -} - -void write_data(uv_stream_t *dest, size_t size, uv_buf_t buf, uv_write_cb cb) { - write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); - req->buf = uv_buf_init((char*) malloc(size), size); - memcpy(req->buf.base, buf.base, size); - uv_write((uv_write_t*) req, (uv_stream_t*)dest, &req->buf, 1, cb); -} - -void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { - if (nread < 0){ - if (nread == UV_EOF){ - // end of file - uv_close((uv_handle_t *)&stdin_pipe, NULL); - uv_close((uv_handle_t *)&stdout_pipe, NULL); - uv_close((uv_handle_t *)&file_pipe, NULL); - } - } else if (nread > 0) { - write_data((uv_stream_t *)&stdout_pipe, nread, *buf, on_stdout_write); - write_data((uv_stream_t *)&file_pipe, nread, *buf, on_file_write); - } - - // OK to free buffer as write_data copies it. - if (buf->base) - free(buf->base); -} - -int main(int argc, char **argv) { - loop = uv_default_loop(); - - uv_pipe_init(loop, &stdin_pipe, 0); - uv_pipe_open(&stdin_pipe, 0); - - uv_pipe_init(loop, &stdout_pipe, 0); - uv_pipe_open(&stdout_pipe, 1); - - uv_fs_t file_req; - int fd = uv_fs_open(loop, &file_req, argv[1], O_CREAT | O_RDWR, 0644, NULL); - uv_pipe_init(loop, &file_pipe, 0); - uv_pipe_open(&file_pipe, fd); - - uv_read_start((uv_stream_t*)&stdin_pipe, alloc_buffer, read_stdin); - - uv_run(loop, UV_RUN_DEFAULT); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/code/uvwget/main.c b/3rd/libuv-1.19.2/docs/code/uvwget/main.c deleted file mode 100644 index 40186241..00000000 --- a/3rd/libuv-1.19.2/docs/code/uvwget/main.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include - -uv_loop_t *loop; -CURLM *curl_handle; -uv_timer_t timeout; - -typedef struct curl_context_s { - uv_poll_t poll_handle; - curl_socket_t sockfd; -} curl_context_t; - -curl_context_t *create_curl_context(curl_socket_t sockfd) { - curl_context_t *context; - - context = (curl_context_t*) malloc(sizeof *context); - - context->sockfd = sockfd; - - int r = uv_poll_init_socket(loop, &context->poll_handle, sockfd); - assert(r == 0); - context->poll_handle.data = context; - - return context; -} - -void curl_close_cb(uv_handle_t *handle) { - curl_context_t *context = (curl_context_t*) handle->data; - free(context); -} - -void destroy_curl_context(curl_context_t *context) { - uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb); -} - - -void add_download(const char *url, int num) { - char filename[50]; - sprintf(filename, "%d.download", num); - FILE *file; - - file = fopen(filename, "w"); - if (file == NULL) { - fprintf(stderr, "Error opening %s\n", filename); - return; - } - - CURL *handle = curl_easy_init(); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); - curl_easy_setopt(handle, CURLOPT_URL, url); - curl_multi_add_handle(curl_handle, handle); - fprintf(stderr, "Added download %s -> %s\n", url, filename); -} - -void check_multi_info(void) { - char *done_url; - CURLMsg *message; - int pending; - - while ((message = curl_multi_info_read(curl_handle, &pending))) { - switch (message->msg) { - case CURLMSG_DONE: - curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, - &done_url); - printf("%s DONE\n", done_url); - - curl_multi_remove_handle(curl_handle, message->easy_handle); - curl_easy_cleanup(message->easy_handle); - break; - - default: - fprintf(stderr, "CURLMSG default\n"); - abort(); - } - } -} - -void curl_perform(uv_poll_t *req, int status, int events) { - uv_timer_stop(&timeout); - int running_handles; - int flags = 0; - if (status < 0) flags = CURL_CSELECT_ERR; - if (!status && events & UV_READABLE) flags |= CURL_CSELECT_IN; - if (!status && events & UV_WRITABLE) flags |= CURL_CSELECT_OUT; - - curl_context_t *context; - - context = (curl_context_t*)req; - - curl_multi_socket_action(curl_handle, context->sockfd, flags, &running_handles); - check_multi_info(); -} - -void on_timeout(uv_timer_t *req) { - int running_handles; - curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, &running_handles); - check_multi_info(); -} - -void start_timeout(CURLM *multi, long timeout_ms, void *userp) { - if (timeout_ms <= 0) - timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */ - uv_timer_start(&timeout, on_timeout, timeout_ms, 0); -} - -int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, void *socketp) { - curl_context_t *curl_context; - if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { - if (socketp) { - curl_context = (curl_context_t*) socketp; - } - else { - curl_context = create_curl_context(s); - curl_multi_assign(curl_handle, s, (void *) curl_context); - } - } - - switch (action) { - case CURL_POLL_IN: - uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform); - break; - case CURL_POLL_OUT: - uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform); - break; - case CURL_POLL_REMOVE: - if (socketp) { - uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); - destroy_curl_context((curl_context_t*) socketp); - curl_multi_assign(curl_handle, s, NULL); - } - break; - default: - abort(); - } - - return 0; -} - -int main(int argc, char **argv) { - loop = uv_default_loop(); - - if (argc <= 1) - return 0; - - if (curl_global_init(CURL_GLOBAL_ALL)) { - fprintf(stderr, "Could not init cURL\n"); - return 1; - } - - uv_timer_init(loop, &timeout); - - curl_handle = curl_multi_init(); - curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); - curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); - - while (argc-- > 1) { - add_download(argv[argc], argc); - } - - uv_run(loop, UV_RUN_DEFAULT); - curl_multi_cleanup(curl_handle); - return 0; -} diff --git a/3rd/libuv-1.19.2/docs/make.bat b/3rd/libuv-1.19.2/docs/make.bat deleted file mode 100644 index 10eb94b0..00000000 --- a/3rd/libuv-1.19.2/docs/make.bat +++ /dev/null @@ -1,243 +0,0 @@ -@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 ^` where ^ 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/3rd/libuv-1.19.2/docs/src/api.rst b/3rd/libuv-1.19.2/docs/src/api.rst deleted file mode 100644 index 22f0640f..00000000 --- a/3rd/libuv-1.19.2/docs/src/api.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _api: - -API documentation -================= - -.. toctree:: - :maxdepth: 1 - - 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/3rd/libuv-1.19.2/docs/src/async.rst b/3rd/libuv-1.19.2/docs/src/async.rst deleted file mode 100644 index 02e6a58e..00000000 --- a/3rd/libuv-1.19.2/docs/src/async.rst +++ /dev/null @@ -1,61 +0,0 @@ - -.. _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. - - :returns: 0 on success, or an error code < 0 on failure. - - .. note:: - Unlike other handle initialization functions, it immediately starts the handle. - -.. c:function:: int uv_async_send(uv_async_t* async) - - Wake up the event loop and call the async handle's callback. - - :returns: 0 on success, or an error code < 0 on failure. - - .. 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/3rd/libuv-1.19.2/docs/src/check.rst b/3rd/libuv-1.19.2/docs/src/check.rst deleted file mode 100644 index 36c93cf0..00000000 --- a/3rd/libuv-1.19.2/docs/src/check.rst +++ /dev/null @@ -1,46 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/conf.py b/3rd/libuv-1.19.2/docs/src/conf.py deleted file mode 100644 index c9b4ea38..00000000 --- a/3rd/libuv-1.19.2/docs/src/conf.py +++ /dev/null @@ -1,348 +0,0 @@ -# -*- coding: utf-8 -*- -# -# libuv 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'2014-present, 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 -# " v documentation". -html_title = 'libuv documentation' - -# A shorter title for the navigation bar. Default is the same as html_title. -html_short_title = 'libuv %s 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 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 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 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 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 documentation' -epub_author = u'libuv contributors' -epub_publisher = u'libuv contributors' -epub_copyright = u'2014-present, 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/3rd/libuv-1.19.2/docs/src/design.rst b/3rd/libuv-1.19.2/docs/src/design.rst deleted file mode 100644 index 487d08ba..00000000 --- a/3rd/libuv-1.19.2/docs/src/design.rst +++ /dev/null @@ -1,138 +0,0 @@ - -.. _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 a simple 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. -- A TCP server handle that gets 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 matches, 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 duration calculated - in 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 ends 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 `_. - -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: - - * File system 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/3rd/libuv-1.19.2/docs/src/dll.rst b/3rd/libuv-1.19.2/docs/src/dll.rst deleted file mode 100644 index fb13f908..00000000 --- a/3rd/libuv-1.19.2/docs/src/dll.rst +++ /dev/null @@ -1,44 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/dns.rst b/3rd/libuv-1.19.2/docs/src/dns.rst deleted file mode 100644 index 1d881580..00000000 --- a/3rd/libuv-1.19.2/docs/src/dns.rst +++ /dev/null @@ -1,108 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/errors.rst b/3rd/libuv-1.19.2/docs/src/errors.rst deleted file mode 100644 index 4e30447b..00000000 --- a/3rd/libuv-1.19.2/docs/src/errors.rst +++ /dev/null @@ -1,344 +0,0 @@ - -.. _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. - -When a function which takes a callback returns an error, the callback will never -be called. - -.. 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. - -.. c:function:: int uv_translate_sys_error(int sys_errno) - - Returns the libuv error code equivalent to the given platform dependent error - code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error - codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`). - - If `sys_errno` is already a libuv error, it is simply returned. - - .. versionchanged:: 1.10.0 function declared public. diff --git a/3rd/libuv-1.19.2/docs/src/fs.rst b/3rd/libuv-1.19.2/docs/src/fs.rst deleted file mode 100644 index 87af828a..00000000 --- a/3rd/libuv-1.19.2/docs/src/fs.rst +++ /dev/null @@ -1,538 +0,0 @@ - -.. _fs: - -File system operations -====================== - -libuv provides a wide variety of cross-platform sync and async file system -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 - - File system 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 - - File system 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_REALPATH, - UV_FS_COPYFILE - } 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 file systems (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:`lstat(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_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) - - Copies a file from `path` to `new_path`. Supported `flags` are described below. - - - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with - `UV_EEXIST` if the destination path already exists. The default behavior - is to overwrite the destination if it exists. - - .. warning:: - If the destination path is created, but an error occurs while copying - the data, then the destination path is removed. There is a brief window - of time between closing and removing the file where another process - could access the file. - - .. versionadded:: 1.14.0 - -.. 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. - - .. note:: - AIX: This function only works for AIX 7.1 and newer. It can still be called on older - versions but will return ``UV_ENOSYS``. - - .. versionchanged:: 1.10.0 sub-second precission is supported on Windows - -.. 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 `_. - - .. warning:: - This function has certain platform-specific caveats that were discovered when used in Node. - - * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are - found while resolving the given path. This limit is hardcoded and cannot be sidestepped. - * Windows: while this function works in the common case, there are a number of corner cases - where it doesn't: - - - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) - cannot be resolved. - - Inconsistent casing when using drive letters. - - Resolved path bypasses subst'd drives. - - While this function can still be used, it's not recommended if scenarios such as the - above need to be supported. - - The background story and some more details on these issues can be checked - `here `_. - - .. 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. - -.. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) - - Returns `req->fs_type`. - - .. versionadded:: 1.19.0 - -.. c:function:: ssize_t uv_fs_get_result(const uv_fs_t* req) - - Returns `req->result`. - - .. versionadded:: 1.19.0 - -.. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) - - Returns `req->ptr`. - - .. versionadded:: 1.19.0 - -.. c:function:: const char* uv_fs_get_path(const uv_fs_t* req) - - Returns `req->path`. - - .. versionadded:: 1.19.0 - -.. c:function:: uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) - - Returns `&req->statbuf`. - - .. versionadded:: 1.19.0 - -.. seealso:: The :c:type:`uv_req_t` API functions also apply. - -Helper functions ----------------- - -.. c:function:: uv_os_fd_t uv_get_osfhandle(int fd) - - For a file descriptor in the C runtime, get the OS-dependent handle. - On UNIX, returns the ``fd`` intact. On Windows, this calls `_get_osfhandle `_. - Note that the return value is still owned by the C runtime, - any attempts to close it or to use it after closing the fd may lead to malfunction. - - .. versionadded:: 1.12.0 - -File open constants -------------------- - -.. c:macro:: UV_FS_O_APPEND - - The file is opened in append mode. Before each write, the file offset is - positioned at the end of the file. - -.. c:macro:: UV_FS_O_CREAT - - The file is created if it does not already exist. - -.. c:macro:: UV_FS_O_DIRECT - - File I/O is done directly to and from user-space buffers, which must be - aligned. Buffer size and address should be a multiple of the physical sector - size of the block device. - - .. note:: - `UV_FS_O_DIRECT` is supported on Linux, and on Windows via - `FILE_FLAG_NO_BUFFERING `_. - `UV_FS_O_DIRECT` is not supported on macOS. - -.. c:macro:: UV_FS_O_DIRECTORY - - If the path is not a directory, fail the open. - - .. note:: - `UV_FS_O_DIRECTORY` is not supported on Windows. - -.. c:macro:: UV_FS_O_DSYNC - - The file is opened for synchronous I/O. Write operations will complete once - all data and a minimum of metadata are flushed to disk. - - .. note:: - `UV_FS_O_DSYNC` is supported on Windows via - `FILE_FLAG_WRITE_THROUGH `_. - -.. c:macro:: UV_FS_O_EXCL - - If the `O_CREAT` flag is set and the file already exists, fail the open. - - .. note:: - In general, the behavior of `O_EXCL` is undefined if it is used without - `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can - be used without `O_CREAT` if pathname refers to a block device. If the - block device is in use by the system (e.g., mounted), the open will fail - with the error `EBUSY`. - -.. c:macro:: UV_FS_O_EXLOCK - - Atomically obtain an exclusive lock. - - .. note:: - `UV_FS_O_EXLOCK` is only supported on macOS and Windows. - - .. versionchanged:: 1.17.0 support is added for Windows. - -.. c:macro:: UV_FS_O_NOATIME - - Do not update the file access time when the file is read. - - .. note:: - `UV_FS_O_NOATIME` is not supported on Windows. - -.. c:macro:: UV_FS_O_NOCTTY - - If the path identifies a terminal device, opening the path will not cause - that terminal to become the controlling terminal for the process (if the - process does not already have one). - - .. note:: - `UV_FS_O_NOCTTY` is not supported on Windows. - -.. c:macro:: UV_FS_O_NOFOLLOW - - If the path is a symbolic link, fail the open. - - .. note:: - `UV_FS_O_NOFOLLOW` is not supported on Windows. - -.. c:macro:: UV_FS_O_NONBLOCK - - Open the file in nonblocking mode if possible. - - .. note:: - `UV_FS_O_NONBLOCK` is not supported on Windows. - -.. c:macro:: UV_FS_O_RANDOM - - Access is intended to be random. The system can use this as a hint to - optimize file caching. - - .. note:: - `UV_FS_O_RANDOM` is only supported on Windows via - `FILE_FLAG_RANDOM_ACCESS `_. - -.. c:macro:: UV_FS_O_RDONLY - - Open the file for read-only access. - -.. c:macro:: UV_FS_O_RDWR - - Open the file for read-write access. - -.. c:macro:: UV_FS_O_SEQUENTIAL - - Access is intended to be sequential from beginning to end. The system can - use this as a hint to optimize file caching. - - .. note:: - `UV_FS_O_SEQUENTIAL` is only supported on Windows via - `FILE_FLAG_SEQUENTIAL_SCAN `_. - -.. c:macro:: UV_FS_O_SHORT_LIVED - - The file is temporary and should not be flushed to disk if possible. - - .. note:: - `UV_FS_O_SHORT_LIVED` is only supported on Windows via - `FILE_ATTRIBUTE_TEMPORARY `_. - -.. c:macro:: UV_FS_O_SYMLINK - - Open the symbolic link itself rather than the resource it points to. - -.. c:macro:: UV_FS_O_SYNC - - The file is opened for synchronous I/O. Write operations will complete once - all data and all metadata are flushed to disk. - - .. note:: - `UV_FS_O_SYNC` is supported on Windows via - `FILE_FLAG_WRITE_THROUGH `_. - -.. c:macro:: UV_FS_O_TEMPORARY - - The file is temporary and should not be flushed to disk if possible. - - .. note:: - `UV_FS_O_TEMPORARY` is only supported on Windows via - `FILE_ATTRIBUTE_TEMPORARY `_. - -.. c:macro:: UV_FS_O_TRUNC - - If the file exists and is a regular file, and the file is opened - successfully for write access, its length shall be truncated to zero. - -.. c:macro:: UV_FS_O_WRONLY - - Open the file for write-only access. diff --git a/3rd/libuv-1.19.2/docs/src/fs_event.rst b/3rd/libuv-1.19.2/docs/src/fs_event.rst deleted file mode 100644 index bd076aae..00000000 --- a/3rd/libuv-1.19.2/docs/src/fs_event.rst +++ /dev/null @@ -1,132 +0,0 @@ - -.. _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. - -.. note:: - For AIX, the non default IBM bos.ahafs package has to be installed. - The AIX Event Infrastructure file system (ahafs) has some limitations: - - - ahafs tracks monitoring per process and is not thread safe. A separate process - must be spawned for each monitor for the same event. - - Events for file modification (writing to a file) are not received if only the - containing folder is watched. - - See documentation_ for more details. - - The z/OS file system events monitoring infrastructure does not notify of file - creation/deletion within a directory that is being monitored. - See the `IBM Knowledge centre`_ for more details. - - .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ - .. _`IBM Knowledge centre`: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.2.0/com.ibm.zos.v2r1.bpxb100/ioc.htm - - - - -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 file systems 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 its 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 `size` will be set to - the required size, including the null terminator. - - .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte, - and the buffer is not null terminated. - - .. versionchanged:: 1.9.0 the returned length includes the terminating null - byte on `UV_ENOBUFS`, and the buffer is null terminated - on success. - -.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/fs_poll.rst b/3rd/libuv-1.19.2/docs/src/fs_poll.rst deleted file mode 100644 index 2912bad9..00000000 --- a/3rd/libuv-1.19.2/docs/src/fs_poll.rst +++ /dev/null @@ -1,77 +0,0 @@ - -.. _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 `size` 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. - - .. versionchanged:: 1.9.0 the returned length includes the terminating null - byte on `UV_ENOBUFS`, and the buffer is null terminated - on success. - - -.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/guide.rst b/3rd/libuv-1.19.2/docs/src/guide.rst deleted file mode 100644 index 126e0808..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. _guide: - -User guide -========== - -.. warning:: - The contents of this guide have been recently incorporated into the libuv documentation - and it hasn't gone through thorough review yet. If you spot a mistake please file an - issue, or better yet, open a pull request! - -.. toctree:: - :maxdepth: 2 - - guide/introduction - guide/basics - guide/filesystem - guide/networking - guide/threads - guide/processes - guide/eventloops - guide/utilities - guide/about diff --git a/3rd/libuv-1.19.2/docs/src/guide/about.rst b/3rd/libuv-1.19.2/docs/src/guide/about.rst deleted file mode 100644 index 2de658d5..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/about.rst +++ /dev/null @@ -1,22 +0,0 @@ -About -===== - -`Nikhil Marathe `_ started writing this book one -afternoon (June 16, 2012) when he didn't feel like programming. He had recently -been stung by the lack of good documentation on libuv while working on -`node-taglib `_. Although reference -documentation was present, there were no comprehensive tutorials. This book is -the output of that need and tries to be accurate. That said, the book may have -mistakes. Pull requests are encouraged. - -Nikhil is indebted to Marc Lehmann's comprehensive `man page -`_ about libev which -describes much of the semantics of the two libraries. - -This book was made using `Sphinx `_ and `vim -`_. - -.. note:: - In 2017 the libuv project incorporated the Nikhil's work into the official - documentation and it's maintained there henceforth. - diff --git a/3rd/libuv-1.19.2/docs/src/guide/basics.rst b/3rd/libuv-1.19.2/docs/src/guide/basics.rst deleted file mode 100644 index 91fa6a6d..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/basics.rst +++ /dev/null @@ -1,188 +0,0 @@ -Basics of libuv -=============== - -libuv enforces an **asynchronous**, **event-driven** style of programming. Its -core job is to provide an event loop and callback based notifications of I/O -and other activities. libuv offers core utilities like timers, non-blocking -networking support, asynchronous file system access, child processes and more. - -Event loops ------------ - -In event-driven programming, an application expresses interest in certain events -and respond to them when they occur. The responsibility of gathering events -from the operating system or monitoring other sources of events is handled by -libuv, and the user can register callbacks to be invoked when an event occurs. -The event-loop usually keeps running *forever*. In pseudocode: - -.. code-block:: python - - while there are still events to process: - e = get the next event - if there is a callback associated with e: - call the callback - -Some examples of events are: - -* File is ready for writing -* A socket has data ready to be read -* A timer has timed out - -This event loop is encapsulated by ``uv_run()`` -- the end-all function when using -libuv. - -The most common activity of systems programs is to deal with input and output, -rather than a lot of number-crunching. The problem with using conventional -input/output functions (``read``, ``fprintf``, etc.) is that they are -**blocking**. The actual write to a hard disk or reading from a network, takes -a disproportionately long time compared to the speed of the processor. The -functions don't return until the task is done, so that your program is doing -nothing. For programs which require high performance this is a major roadblock -as other activities and other I/O operations are kept waiting. - -One of the standard solutions is to use threads. Each blocking I/O operation is -started in a separate thread (or in a thread pool). When the blocking function -gets invoked in the thread, the processor can schedule another thread to run, -which actually needs the CPU. - -The approach followed by libuv uses another style, which is the **asynchronous, -non-blocking** style. Most modern operating systems provide event notification -subsystems. For example, a normal ``read`` call on a socket would block until -the sender actually sent something. Instead, the application can request the -operating system to watch the socket and put an event notification in the -queue. The application can inspect the events at its convenience (perhaps doing -some number crunching before to use the processor to the maximum) and grab the -data. It is **asynchronous** because the application expressed interest at one -point, then used the data at another point (in time and space). It is -**non-blocking** because the application process was free to do other tasks. -This fits in well with libuv's event-loop approach, since the operating system -events can be treated as just another libuv event. The non-blocking ensures -that other events can continue to be handled as fast as they come in [#]_. - -.. NOTE:: - - How the I/O is run in the background is not of our concern, but due to the - way our computer hardware works, with the thread as the basic unit of the - processor, libuv and OSes will usually run background/worker threads and/or - polling to perform tasks in a non-blocking manner. - -Bert Belder, one of the libuv core developers has a small video explaining the -architecture of libuv and its background. If you have no prior experience with -either libuv or libev, it is a quick, useful watch. - -libuv's event loop is explained in more detail in the `documentation -`_. - -.. raw:: html - - - -Hello World ------------ - -With the basics out of the way, lets write our first libuv program. It does -nothing, except start a loop which will exit immediately. - -.. rubric:: helloworld/main.c -.. literalinclude:: ../../code/helloworld/main.c - :linenos: - -This program quits immediately because it has no events to process. A libuv -event loop has to be told to watch out for events using the various API -functions. - -Starting with libuv v1.0, users should allocate the memory for the loops before -initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in -custom memory management. Remember to de-initialize the loop using -``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never -close loops since the program quits after the loop ends and the system will -reclaim memory. Production grade projects, especially long running systems -programs, should take care to release correctly. - -Default loop -++++++++++++ - -A default loop is provided by libuv and can be accessed using -``uv_default_loop()``. You should use this loop if you only want a single -loop. - -.. note:: - - node.js uses the default loop as its main loop. If you are writing bindings - you should be aware of this. - -.. _libuv-error-handling: - -Error handling --------------- - -Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. - -.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants - -You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions -to get a ``const char *`` describing the error or the error name respectively. - -I/O read callbacks (such as for files and sockets) are passed a parameter ``nread``. If ``nread`` is less than 0, there was an error (UV_EOF is the end of file error, which you may want to handle differently). - -Handles and Requests --------------------- - -libuv works by the user expressing interest in particular events. This is -usually done by creating a **handle** to an I/O device, timer or process. -Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the -handle is used for. - -.. rubric:: libuv watchers -.. literalinclude:: ../../../include/uv.h - :lines: 197-230 - -Handles represent long-lived objects. Async operations on such handles are -identified using **requests**. A request is short-lived (usually used across -only one callback) and usually indicates one I/O operation on a handle. -Requests are used to preserve context between the initiation and the callback -of individual actions. For example, an UDP socket is represented by -a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t`` -structure that is passed to the callback after the write is done. - -Handles are setup by a corresponding:: - - uv_TYPE_init(uv_loop_t *, uv_TYPE_t *) - -function. - -Callbacks are functions which are called by libuv whenever an event the watcher -is interested in has taken place. Application specific logic will usually be -implemented in the callback. For example, an IO watcher's callback will receive -the data read from a file, a timer callback will be triggered on timeout and so -on. - -Idling -++++++ - -Here is an example of using an idle handle. The callback is called once on -every turn of the event loop. A use case for idle handles is discussed in -:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle -and see how ``uv_run()`` will now block because a watcher is present. The idle -watcher is stopped when the count is reached and ``uv_run()`` exits since no -event watchers are active. - -.. rubric:: idle-basic/main.c -.. literalinclude:: ../../code/idle-basic/main.c - :emphasize-lines: 6,10,14-17 - -Storing context -+++++++++++++++ - -In callback based programming style you'll often want to pass some 'context' -- -application specific information -- between the call site and the callback. All -handles and requests have a ``void* data`` member which you can set to the -context and cast back in the callback. This is a common pattern used throughout -the C library ecosystem. In addition ``uv_loop_t`` also has a similar data -member. - ----- - -.. [#] Depending on the capacity of the hardware of course. diff --git a/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst b/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst deleted file mode 100644 index fd9df5fb..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst +++ /dev/null @@ -1,48 +0,0 @@ -Advanced event loops -==================== - -libuv provides considerable user control over event loops, and you can achieve -interesting results by juggling multiple loops. You can also embed libuv's -event loop into another event loop based library -- imagine a Qt based UI, and -Qt's event loop driving a libuv backend which does intensive system level -tasks. - -Stopping an event loop -~~~~~~~~~~~~~~~~~~~~~~ - -``uv_stop()`` can be used to stop an event loop. The earliest the loop will -stop running is *on the next iteration*, possibly later. This means that events -that are ready to be processed in this iteration of the loop will still be -processed, so ``uv_stop()`` can't be used as a kill switch. When ``uv_stop()`` -is called, the loop **won't** block for i/o on this iteration. The semantics of -these things can be a bit difficult to understand, so let's look at -``uv_run()`` where all the control flow occurs. - -.. rubric:: src/unix/core.c - uv_run -.. literalinclude:: ../../../src/unix/core.c - :linenos: - :lines: 304-324 - :emphasize-lines: 10,19,21 - -``stop_flag`` is set by ``uv_stop()``. Now all libuv callbacks are invoked -within the event loop, which is why invoking ``uv_stop()`` in them will still -lead to this iteration of the loop occurring. First libuv updates timers, then -runs pending timer, idle and prepare callbacks, and invokes any pending I/O -callbacks. If you were to call ``uv_stop()`` in any of them, ``stop_flag`` -would be set. This causes ``uv_backend_timeout()`` to return ``0``, which is -why the loop does not block on I/O. If on the other hand, you called -``uv_stop()`` in one of the check handlers, I/O has already finished and is not -affected. - -``uv_stop()`` is useful to shutdown a loop when a result has been computed or -there is an error, without having to ensure that all handlers are stopped one -by one. - -Here is a simple example that stops the loop and demonstrates how the current -iteration of the loop still takes places. - -.. rubric:: uvstop/main.c -.. literalinclude:: ../../code/uvstop/main.c - :linenos: - :emphasize-lines: 11 - diff --git a/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst b/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst deleted file mode 100644 index 6129303e..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst +++ /dev/null @@ -1,287 +0,0 @@ -Filesystem -========== - -Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the -``uv_fs_t`` struct. - -.. note:: - - The libuv filesystem operations are different from :doc:`socket operations - `. Socket operations use the non-blocking operations provided - by the operating system. Filesystem operations use blocking functions - internally, but invoke these functions in a `thread pool`_ and notify - watchers registered with the event loop when application interaction is - required. - -.. _thread pool: http://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling - -All filesystem functions have two forms - *synchronous* and *asynchronous*. - -The *synchronous* forms automatically get called (and **block**) if the -callback is null. The return value of functions is a :ref:`libuv error code -`. This is usually only useful for synchronous calls. -The *asynchronous* form is called when a callback is passed and the return -value is 0. - -Reading/Writing files ---------------------- - -A file descriptor is obtained using - -.. code-block:: c - - int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) - -``flags`` and ``mode`` are standard -`Unix flags `_. -libuv takes care of converting to the appropriate Windows flags. - -File descriptors are closed using - -.. code-block:: c - - int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) - - -Filesystem operation callbacks have the signature: - -.. code-block:: c - - void callback(uv_fs_t* req); - -Let's see a simple implementation of ``cat``. We start with registering -a callback for when the file is opened: - -.. rubric:: uvcat/main.c - opening a file -.. literalinclude:: ../../code/uvcat/main.c - :linenos: - :lines: 41-53 - :emphasize-lines: 4, 6-7 - -The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the -``uv_fs_open`` callback. If the file is successfully opened, we start reading it. - -.. rubric:: uvcat/main.c - read callback -.. literalinclude:: ../../code/uvcat/main.c - :linenos: - :lines: 26-40 - :emphasize-lines: 2,8,12 - -In the case of a read call, you should pass an *initialized* buffer which will -be filled with data before the read callback is triggered. The ``uv_fs_*`` -operations map almost directly to certain POSIX functions, so EOF is indicated -in this case by ``result`` being 0. In the case of streams or pipes, the -``UV_EOF`` constant would have been passed as a status instead. - -Here you see a common pattern when writing asynchronous programs. The -``uv_fs_close()`` call is performed synchronously. *Usually tasks which are -one-off, or are done as part of the startup or shutdown stage are performed -synchronously, since we are interested in fast I/O when the program is going -about its primary task and dealing with multiple I/O sources*. For solo tasks -the performance difference usually is negligible and may lead to simpler code. - -Filesystem writing is similarly simple using ``uv_fs_write()``. *Your callback -will be triggered after the write is complete*. In our case the callback -simply drives the next read. Thus read and write proceed in lockstep via -callbacks. - -.. rubric:: uvcat/main.c - write callback -.. literalinclude:: ../../code/uvcat/main.c - :linenos: - :lines: 16-24 - :emphasize-lines: 6 - -.. warning:: - - Due to the way filesystems and disk drives are configured for performance, - a write that 'succeeds' may not be committed to disk yet. - -We set the dominos rolling in ``main()``: - -.. rubric:: uvcat/main.c -.. literalinclude:: ../../code/uvcat/main.c - :linenos: - :lines: 55- - :emphasize-lines: 2 - -.. warning:: - - The ``uv_fs_req_cleanup()`` function must always be called on filesystem - requests to free internal memory allocations in libuv. - -Filesystem operations ---------------------- - -All the standard filesystem operations like ``unlink``, ``rmdir``, ``stat`` are -supported asynchronously and have intuitive argument order. They follow the -same patterns as the read/write/open calls, returning the result in the -``uv_fs_t.result`` field. The full list: - -.. rubric:: Filesystem operations -.. literalinclude:: ../../../include/uv.h - :lines: 1084-1195 - -.. _buffers-and-streams: - -Buffers and Streams -------------------- - -The basic I/O handle in libuv is the stream (``uv_stream_t``). TCP sockets, UDP -sockets, and pipes for file I/O and IPC are all treated as stream subclasses. - -Streams are initialized using custom functions for each subclass, then operated -upon using - -.. code-block:: c - - int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb); - int uv_read_stop(uv_stream_t*); - int uv_write(uv_write_t* req, uv_stream_t* handle, - const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); - -The stream based functions are simpler to use than the filesystem ones and -libuv will automatically keep reading from a stream when ``uv_read_start()`` is -called once, until ``uv_read_stop()`` is called. - -The discrete unit of data is the buffer -- ``uv_buf_t``. This is simply -a collection of a pointer to bytes (``uv_buf_t.base``) and the length -(``uv_buf_t.len``). The ``uv_buf_t`` is lightweight and passed around by value. -What does require management is the actual bytes, which have to be allocated -and freed by the application. - -.. ERROR:: - - THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER** - -To demonstrate streams we will need to use ``uv_pipe_t``. This allows streaming -local files [#]_. Here is a simple tee utility using libuv. Doing all operations -asynchronously shows the power of evented I/O. The two writes won't block each -other, but we have to be careful to copy over the buffer data to ensure we don't -free a buffer until it has been written. - -The program is to be executed as:: - - ./uvtee - -We start off opening pipes on the files we require. libuv pipes to a file are -opened as bidirectional by default. - -.. rubric:: uvtee/main.c - read on pipes -.. literalinclude:: ../../code/uvtee/main.c - :linenos: - :lines: 61-80 - :emphasize-lines: 4,5,15 - -The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named -pipes. This is covered in :doc:`processes`. The ``uv_pipe_open()`` call -associates the pipe with the file descriptor, in this case ``0`` (standard -input). - -We start monitoring ``stdin``. The ``alloc_buffer`` callback is invoked as new -buffers are required to hold incoming data. ``read_stdin`` will be called with -these buffers. - -.. rubric:: uvtee/main.c - reading buffers -.. literalinclude:: ../../code/uvtee/main.c - :linenos: - :lines: 19-22,44-60 - -The standard ``malloc`` is sufficient here, but you can use any memory allocation -scheme. For example, node.js uses its own slab allocator which associates -buffers with V8 objects. - -The read callback ``nread`` parameter is less than 0 on any error. This error -might be EOF, in which case we close all the streams, using the generic close -function ``uv_close()`` which deals with the handle based on its internal type. -Otherwise ``nread`` is a non-negative number and we can attempt to write that -many bytes to the output streams. Finally remember that buffer allocation and -deallocation is application responsibility, so we free the data. - -The allocation callback may return a buffer with length zero if it fails to -allocate memory. In this case, the read callback is invoked with error -UV_ENOBUFS. libuv will continue to attempt to read the stream though, so you -must explicitly call ``uv_close()`` if you want to stop when allocation fails. - -The read callback may be called with ``nread = 0``, indicating that at this -point there is nothing to be read. Most applications will just ignore this. - -.. rubric:: uvtee/main.c - Write to pipe -.. literalinclude:: ../../code/uvtee/main.c - :linenos: - :lines: 9-13,23-42 - -``write_data()`` makes a copy of the buffer obtained from read. This buffer -does not get passed through to the write callback trigged on write completion. To -get around this we wrap a write request and a buffer in ``write_req_t`` and -unwrap it in the callbacks. We make a copy so we can free the two buffers from -the two calls to ``write_data`` independently of each other. While acceptable -for a demo program like this, you'll probably want smarter memory management, -like reference counted buffers or a pool of buffers in any major application. - -.. WARNING:: - - If your program is meant to be used with other programs it may knowingly or - unknowingly be writing to a pipe. This makes it susceptible to `aborting on - receiving a SIGPIPE`_. It is a good idea to insert:: - - signal(SIGPIPE, SIG_IGN) - - in the initialization stages of your application. - -.. _aborting on receiving a SIGPIPE: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_SIGPIPE - -File change events ------------------- - -All modern operating systems provide APIs to put watches on individual files or -directories and be informed when the files are modified. libuv wraps common -file change notification libraries [#fsnotify]_. This is one of the more -inconsistent parts of libuv. File change notification systems are themselves -extremely varied across platforms so getting everything working everywhere is -difficult. To demonstrate, I'm going to build a simple utility which runs -a command whenever any of the watched files change:: - - ./onchange [file2] ... - -The file change notification is started using ``uv_fs_event_init()``: - -.. rubric:: onchange/main.c - The setup -.. literalinclude:: ../../code/onchange/main.c - :linenos: - :lines: 26- - :emphasize-lines: 15 - -The third argument is the actual file or directory to monitor. The last -argument, ``flags``, can be: - -.. literalinclude:: ../../../include/uv.h - :lines: 1299, 1308, 1315 - -``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet). -``UV_FS_EVENT_RECURSIVE`` will start watching subdirectories as well on -supported platforms. - -The callback will receive the following arguments: - - #. ``uv_fs_event_t *handle`` - The handle. The ``path`` field of the handle - is the file on which the watch was set. - #. ``const char *filename`` - If a directory is being monitored, this is the - file which was changed. Only non-``null`` on Linux and Windows. May be ``null`` - even on those platforms. - #. ``int flags`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of - both. - #. ``int status`` - Currently 0. - -In our example we simply print the arguments and run the command using -``system()``. - -.. rubric:: onchange/main.c - file change notification callback -.. literalinclude:: ../../code/onchange/main.c - :linenos: - :lines: 9-24 - ----- - -.. [#fsnotify] inotify on Linux, FSEvents on Darwin, kqueue on BSDs, - ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin -.. [#] see :ref:`pipes` diff --git a/3rd/libuv-1.19.2/docs/src/guide/introduction.rst b/3rd/libuv-1.19.2/docs/src/guide/introduction.rst deleted file mode 100644 index f57cdd9c..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/introduction.rst +++ /dev/null @@ -1,75 +0,0 @@ -Introduction -============ - -This 'book' is a small set of tutorials about using libuv_ as -a high performance evented I/O library which offers the same API on Windows and Unix. - -It is meant to cover the main areas of libuv, but is not a comprehensive -reference discussing every function and data structure. The `official libuv -documentation`_ may be consulted for full details. - -.. _official libuv documentation: http://docs.libuv.org/en/v1.x/ - -This book is still a work in progress, so sections may be incomplete, but -I hope you will enjoy it as it grows. - -Who this book is for --------------------- - -If you are reading this book, you are either: - -1) a systems programmer, creating low-level programs such as daemons or network - services and clients. You have found that the event loop approach is well - suited for your application and decided to use libuv. - -2) a node.js module writer, who wants to wrap platform APIs - written in C or C++ with a set of (a)synchronous APIs that are exposed to - JavaScript. You will use libuv purely in the context of node.js. For - this you will require some other resources as the book does not cover parts - specific to v8/node.js. - -This book assumes that you are comfortable with the C programming language. - -Background ----------- - -The node.js_ project began in 2009 as a JavaScript environment decoupled -from the browser. Using Google's V8_ and Marc Lehmann's libev_, node.js -combined a model of I/O -- evented -- with a language that was well suited to -the style of programming; due to the way it had been shaped by browsers. As -node.js grew in popularity, it was important to make it work on Windows, but -libev ran only on Unix. The Windows equivalent of kernel event notification -mechanisms like kqueue or (e)poll is IOCP. libuv was an abstraction around libev -or IOCP depending on the platform, providing users an API based on libev. -In the node-v0.9.0 version of libuv `libev was removed`_. - -Since then libuv has continued to mature and become a high quality standalone -library for system programming. Users outside of node.js include Mozilla's -Rust_ programming language, and a variety_ of language bindings. - -This book and the code is based on libuv version `v1.3.0`_. - -Code ----- - -All the code from this book is included as part of the source of the book on -Github. `Clone`_/`Download`_ the book, then build libuv:: - - cd libuv - ./autogen.sh - ./configure - make - -There is no need to ``make install``. To build the examples run ``make`` in the -``code/`` directory. - -.. _Clone: https://github.com/nikhilm/uvbook -.. _Download: https://github.com/nikhilm/uvbook/downloads -.. _v1.3.0: https://github.com/libuv/libuv/tags -.. _V8: http://code.google.com/p/v8/ -.. _libev: http://software.schmorp.de/pkg/libev.html -.. _libuv: https://github.com/libuv/libuv -.. _node.js: http://www.nodejs.org -.. _libev was removed: https://github.com/joyent/libuv/issues/485 -.. _Rust: http://rust-lang.org -.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv diff --git a/3rd/libuv-1.19.2/docs/src/guide/networking.rst b/3rd/libuv-1.19.2/docs/src/guide/networking.rst deleted file mode 100644 index 8d3c87bf..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/networking.rst +++ /dev/null @@ -1,249 +0,0 @@ -Networking -========== - -Networking in libuv is not much different from directly using the BSD socket -interface, some things are easier, all are non-blocking, but the concepts stay -the same. In addition libuv offers utility functions to abstract the annoying, -repetitive and low-level tasks like setting up sockets using the BSD socket -structures, DNS lookup, and tweaking various socket parameters. - -The ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O. - -.. NOTE:: - - The code samples in this chapter exist to show certain libuv APIs. They are - not examples of good quality code. They leak memory and don't always close - connections properly. - -TCP ---- - -TCP is a connection oriented, stream protocol and is therefore based on the -libuv streams infrastructure. - -Server -++++++ - -Server sockets proceed by: - -1. ``uv_tcp_init`` the TCP handle. -2. ``uv_tcp_bind`` it. -3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new - connection is established by a client. -4. Use ``uv_accept`` to accept the connection. -5. Use :ref:`stream operations ` to communicate with the - client. - -Here is a simple echo server - -.. rubric:: tcp-echo-server/main.c - The listen socket -.. literalinclude:: ../../code/tcp-echo-server/main.c - :linenos: - :lines: 68- - :emphasize-lines: 4-5,7-10 - -You can see the utility function ``uv_ip4_addr`` being used to convert from -a human readable IP address, port pair to the sockaddr_in structure required by -the BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``. - -.. NOTE:: - - There are ``uv_ip6_*`` analogues for the ip4 functions. - -Most of the setup functions are synchronous since they are CPU-bound. -``uv_listen`` is where we return to libuv's callback style. The second -arguments is the backlog queue -- the maximum length of queued connections. - -When a connection is initiated by clients, the callback is required to set up -a handle for the client socket and associate the handle using ``uv_accept``. -In this case we also establish interest in reading from this stream. - -.. rubric:: tcp-echo-server/main.c - Accepting the client -.. literalinclude:: ../../code/tcp-echo-server/main.c - :linenos: - :lines: 51-66 - :emphasize-lines: 9-10 - -The remaining set of functions is very similar to the streams example and can -be found in the code. Just remember to call ``uv_close`` when the socket isn't -required. This can be done even in the ``uv_listen`` callback if you are not -interested in accepting the connection. - -Client -++++++ - -Where you do bind/listen/accept on the server, on the client side it's simply -a matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style -callback of ``uv_listen`` is used by ``uv_tcp_connect``. Try:: - - uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); - uv_tcp_init(loop, socket); - - uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); - - struct sockaddr_in dest; - uv_ip4_addr("127.0.0.1", 80, &dest); - - uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect); - -where ``on_connect`` will be called after the connection is established. The -callback receives the ``uv_connect_t`` struct, which has a member ``.handle`` -pointing to the socket. - -UDP ---- - -The `User Datagram Protocol`_ offers connectionless, unreliable network -communication. Hence libuv doesn't offer a stream. Instead libuv provides -non-blocking UDP support via the `uv_udp_t` handle (for receiving) and -`uv_udp_send_t` request (for sending) and related functions. That said, the -actual API for reading/writing is very similar to normal stream reads. To look -at how UDP can be used, the example shows the first stage of obtaining an IP -address from a `DHCP`_ server -- DHCP Discover. - -.. note:: - - You will have to run `udp-dhcp` as **root** since it uses well known port - numbers below 1024. - -.. rubric:: udp-dhcp/main.c - Setup and send UDP packets -.. literalinclude:: ../../code/udp-dhcp/main.c - :linenos: - :lines: 7-11,104- - :emphasize-lines: 8,10-11,17-18,21 - -.. note:: - - The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP - address ``255.255.255.255`` is a broadcast address meaning that packets - will be sent to all interfaces on the subnet. port ``0`` means that the OS - randomly assigns a port. - -First we setup the receiving socket to bind on all interfaces on port 68 (DHCP -client) and start a read on it. This will read back responses from any DHCP -server that replies. We use the UV_UDP_REUSEADDR flag to play nice with any -other system DHCP clients that are running on this computer on the same port. -Then we setup a similar send socket and use ``uv_udp_send`` to send -a *broadcast message* on port 67 (DHCP server). - -It is **necessary** to set the broadcast flag, otherwise you will get an -``EACCES`` error [#]_. The exact message being sent is not relevant to this -book and you can study the code if you are interested. As usual the read and -write callbacks will receive a status code of < 0 if something went wrong. - -Since UDP sockets are not connected to a particular peer, the read callback -receives an extra parameter about the sender of the packet. - -``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL, -it indicates there is nothing to read (the callback shouldn't do anything), if -not NULL, it indicates that an empty datagram was received from the host at -``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer -provided by your allocator was not large enough to hold the data. *In this case -the OS will discard the data that could not fit* (That's UDP for you!). - -.. rubric:: udp-dhcp/main.c - Reading packets -.. literalinclude:: ../../code/udp-dhcp/main.c - :linenos: - :lines: 17-40 - :emphasize-lines: 1,23 - -UDP Options -+++++++++++ - -Time-to-live -~~~~~~~~~~~~ - -The TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``. - -IPv6 stack only -~~~~~~~~~~~~~~~ - -IPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to -restrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to -``uv_udp_bind`` [#]_. - -Multicast -~~~~~~~~~ - -A socket can (un)subscribe to a multicast group using: - -.. literalinclude:: ../../../include/uv.h - :lines: 594-597 - -where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. - -The concepts of multicasting are nicely explained in `this guide`_. - -.. _this guide: http://www.tldp.org/HOWTO/Multicast-HOWTO-2.html - -Local loopback of multicast packets is enabled by default [#]_, use -``uv_udp_set_multicast_loop`` to switch it off. - -The packet time-to-live for multicast packets can be changed using -``uv_udp_set_multicast_ttl``. - -Querying DNS ------------- - -libuv provides asynchronous DNS resolution. For this it provides its own -``getaddrinfo`` replacement [#]_. In the callback you can -perform normal socket operations on the retrieved addresses. Let's connect to -Freenode to see an example of DNS resolution. - -.. rubric:: dns/main.c -.. literalinclude:: ../../code/dns/main.c - :linenos: - :lines: 61- - :emphasize-lines: 12 - -If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and -your callback won't be invoked at all. All arguments can be freed immediately -after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` -structures are documented in `the getaddrinfo man page `_. The -callback can be ``NULL`` in which case the function will run synchronously. - -In the resolver callback, you can pick any IP from the linked list of ``struct -addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to -call ``uv_freeaddrinfo`` in the callback. - -.. rubric:: dns/main.c -.. literalinclude:: ../../code/dns/main.c - :linenos: - :lines: 42-60 - :emphasize-lines: 8,16 - -libuv also provides the inverse `uv_getnameinfo`_. - -.. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo - -Network interfaces ------------------- - -Information about the system's network interfaces can be obtained through libuv -using ``uv_interface_addresses``. This simple program just prints out all the -interface details so you get an idea of the fields that are available. This is -useful to allow your service to bind to IP addresses when it starts. - -.. rubric:: interfaces/main.c -.. literalinclude:: ../../code/interfaces/main.c - :linenos: - :emphasize-lines: 9,17 - -``is_internal`` is true for loopback interfaces. Note that if a physical -interface has multiple IPv4/IPv6 addresses, the name will be reported multiple -times, with each address being reported once. - -.. _c-ares: http://c-ares.haxx.se -.. _getaddrinfo: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html - -.. _User Datagram Protocol: http://en.wikipedia.org/wiki/User_Datagram_Protocol -.. _DHCP: http://tools.ietf.org/html/rfc2131 - ----- - -.. [#] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#broadcast -.. [#] on Windows only supported on Windows Vista and later. -.. [#] http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1 -.. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv - v0.8.0 and earlier also included c-ares_ as an alternative, but this has been - removed in v0.9.0. diff --git a/3rd/libuv-1.19.2/docs/src/guide/processes.rst b/3rd/libuv-1.19.2/docs/src/guide/processes.rst deleted file mode 100644 index 49df4e93..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/processes.rst +++ /dev/null @@ -1,389 +0,0 @@ -Processes -========= - -libuv offers considerable child process management, abstracting the platform -differences and allowing communication with the child process using streams or -named pipes. - -A common idiom in Unix is for every process to do one thing and do it well. In -such a case, a process often uses multiple child processes to achieve tasks -(similar to using pipes in shells). A multi-process model with messages -may also be easier to reason about compared to one with threads and shared -memory. - -A common refrain against event-based programs is that they cannot take -advantage of multiple cores in modern computers. In a multi-threaded program -the kernel can perform scheduling and assign different threads to different -cores, improving performance. But an event loop has only one thread. The -workaround can be to launch multiple processes instead, with each process -running an event loop, and each process getting assigned to a separate CPU -core. - -Spawning child processes ------------------------- - -The simplest case is when you simply want to launch a process and know when it -exits. This is achieved using ``uv_spawn``. - -.. rubric:: spawn/main.c -.. literalinclude:: ../../code/spawn/main.c - :linenos: - :lines: 6-8,15- - :emphasize-lines: 11,13-17 - -.. NOTE:: - - ``options`` is implicitly initialized with zeros since it is a global - variable. If you change ``options`` to a local variable, remember to - initialize it to null out all unused fields:: - - uv_process_options_t options = {0}; - -The ``uv_process_t`` struct only acts as the handle, all options are set via -``uv_process_options_t``. To simply launch a process, you need to set only the -``file`` and ``args`` fields. ``file`` is the program to execute. Since -``uv_spawn`` uses execvp_ internally, there is no need to supply the full -path. Finally as per underlying conventions, **the arguments array has to be -one larger than the number of arguments, with the last element being NULL**. - -.. _execvp: http://www.kernel.org/doc/man-pages/online/pages/man3/exec.3.html - -After the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process -ID of the child process. - -The exit callback will be invoked with the *exit status* and the type of *signal* -which caused the exit. - -.. rubric:: spawn/main.c -.. literalinclude:: ../../code/spawn/main.c - :linenos: - :lines: 9-12 - :emphasize-lines: 3 - -It is **required** to close the process watcher after the process exits. - -Changing process parameters ---------------------------- - -Before the child process is launched you can control the execution environment -using fields in ``uv_process_options_t``. - -Change execution directory -++++++++++++++++++++++++++ - -Set ``uv_process_options_t.cwd`` to the corresponding directory. - -Set environment variables -+++++++++++++++++++++++++ - -``uv_process_options_t.env`` is a null-terminated array of strings, each of the -form ``VAR=VALUE`` used to set up the environment variables for the process. Set -this to ``NULL`` to inherit the environment from the parent (this) process. - -Option flags -++++++++++++ - -Setting ``uv_process_options_t.flags`` to a bitwise OR of the following flags, -modifies the child process behaviour: - -* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``. -* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``. - -Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on -Windows with ``UV_ENOTSUP``. - -* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of - ``uv_process_options_t.args`` is done on Windows. Ignored on Unix. -* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which - will keep running after the parent process exits. See example below. - -Detaching processes -------------------- - -Passing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or -child processes which are independent of the parent so that the parent exiting -does not affect it. - -.. rubric:: detach/main.c -.. literalinclude:: ../../code/detach/main.c - :linenos: - :lines: 9-30 - :emphasize-lines: 12,19 - -Just remember that the handle is still monitoring the child, so your program -won't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*. - -Sending signals to processes ----------------------------- - -libuv wraps the standard ``kill(2)`` system call on Unix and implements one -with similar semantics on Windows, with *one caveat*: all of ``SIGTERM``, -``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature -of ``uv_kill`` is:: - - uv_err_t uv_kill(int pid, int signum); - -For processes started using libuv, you may use ``uv_process_kill`` instead, -which accepts the ``uv_process_t`` watcher as the first argument, rather than -the pid. In this case, **remember to call** ``uv_close`` on the watcher. - -Signals -------- - -libuv provides wrappers around Unix signals with `some Windows support -`_ as well. - -Use ``uv_signal_init()`` to initialize -a handle and associate it with a loop. To listen for particular signals on -that handler, use ``uv_signal_start()`` with the handler function. Each handler -can only be associated with one signal number, with subsequent calls to -``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to -stop watching. Here is a small example demonstrating the various possibilities: - -.. rubric:: signal/main.c -.. literalinclude:: ../../code/signal/main.c - :linenos: - :emphasize-lines: 17-18,27-28 - -.. NOTE:: - - ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)`` - in that it will process only one event. UV_RUN_ONCE blocks if there are no - pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT - so that one of the loops isn't starved because the other one has no pending - activity. - -Send ``SIGUSR1`` to the process, and you'll find the handler being invoked -4 times, one for each ``uv_signal_t``. The handler just stops each handle, -so that the program exits. This sort of dispatch to all handlers is very -useful. A server using multiple event loops could ensure that all data was -safely saved before termination, simply by every loop adding a watcher for -``SIGINT``. - -Child Process I/O ------------------ - -A normal, newly spawned process has its own set of file descriptors, with 0, -1 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you -may want to share file descriptors with the child. For example, perhaps your -applications launches a sub-command and you want any errors to go in the log -file, but ignore ``stdout``. For this you'd like to have ``stderr`` of the -child be the same as the stderr of the parent. In this case, libuv supports -*inheriting* file descriptors. In this sample, we invoke the test program, -which is: - -.. rubric:: proc-streams/test.c -.. literalinclude:: ../../code/proc-streams/test.c - -The actual program ``proc-streams`` runs this while sharing only ``stderr``. -The file descriptors of the child process are set using the ``stdio`` field in -``uv_process_options_t``. First set the ``stdio_count`` field to the number of -file descriptors being set. ``uv_process_options_t.stdio`` is an array of -``uv_stdio_container_t``, which is: - -.. literalinclude:: ../../../include/uv.h - :lines: 826-834 - -where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be -used. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll -redirect to ``/dev/null``. - -Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``. -Then we set the ``fd`` to ``stderr``. - -.. rubric:: proc-streams/main.c -.. literalinclude:: ../../code/proc-streams/main.c - :linenos: - :lines: 15-17,27- - :emphasize-lines: 6,10,11,12 - -If you run ``proc-stream`` you'll see that only the line "This is stderr" will -be displayed. Try marking ``stdout`` as being inherited and see the output. - -It is dead simple to apply this redirection to streams. By setting ``flags`` -to ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the -parent process, the child process can treat that stream as standard I/O. This -can be used to implement something like CGI_. - -.. _CGI: http://en.wikipedia.org/wiki/Common_Gateway_Interface - -A sample CGI script/executable is: - -.. rubric:: cgi/tick.c -.. literalinclude:: ../../code/cgi/tick.c - -The CGI server combines the concepts from this chapter and :doc:`networking` so -that every client is sent ten ticks after which that connection is closed. - -.. rubric:: cgi/main.c -.. literalinclude:: ../../code/cgi/main.c - :linenos: - :lines: 49-63 - :emphasize-lines: 10 - -Here we simply accept the TCP connection and pass on the socket (*stream*) to -``invoke_cgi_script``. - -.. rubric:: cgi/main.c -.. literalinclude:: ../../code/cgi/main.c - :linenos: - :lines: 16, 25-45 - :emphasize-lines: 8-9,18,20 - -The ``stdout`` of the CGI script is set to the socket so that whatever our tick -script prints, gets sent to the client. By using processes, we can offload the -read/write buffering to the operating system, so in terms of convenience this -is great. Just be warned that creating processes is a costly task. - -.. _pipes: - -Pipes ------ - -libuv's ``uv_pipe_t`` structure is slightly confusing to Unix programmers, -because it immediately conjures up ``|`` and `pipe(7)`_. But ``uv_pipe_t`` is -not related to anonymous pipes, rather it is an IPC mechanism. ``uv_pipe_t`` -can be backed by a `Unix Domain Socket`_ or `Windows Named Pipe`_ to allow -multiple processes to communicate. This is discussed below. - -.. _pipe(7): http://www.kernel.org/doc/man-pages/online/pages/man7/pipe.7.html -.. _Unix Domain Socket: http://www.kernel.org/doc/man-pages/online/pages/man7/unix.7.html -.. _Windows Named Pipe: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx - -Parent-child IPC -++++++++++++++++ - -A parent and child can have one or two way communication over a pipe created by -settings ``uv_stdio_container_t.flags`` to a bit-wise combination of -``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The -read/write flag is from the perspective of the child process. - -Arbitrary process IPC -+++++++++++++++++++++ - -Since domain sockets [#]_ can have a well known name and a location in the -file-system they can be used for IPC between unrelated processes. The D-BUS_ -system used by open source desktop environments uses domain sockets for event -notification. Various applications can then react when a contact comes online -or new hardware is detected. The MySQL server also runs a domain socket on -which clients can interact with it. - -.. _D-BUS: http://www.freedesktop.org/wiki/Software/dbus - -When using domain sockets, a client-server pattern is usually followed with the -creator/owner of the socket acting as the server. After the initial setup, -messaging is no different from TCP, so we'll re-use the echo server example. - -.. rubric:: pipe-echo-server/main.c -.. literalinclude:: ../../code/pipe-echo-server/main.c - :linenos: - :lines: 70- - :emphasize-lines: 5,10,14 - -We name the socket ``echo.sock`` which means it will be created in the local -directory. This socket now behaves no different from TCP sockets as far as -the stream API is concerned. You can test this server using `socat`_:: - - $ socat - /path/to/socket - -A client which wants to connect to a domain socket will use:: - - void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb); - -where ``name`` will be ``echo.sock`` or similar. - -.. _socat: http://www.dest-unreach.org/socat/ - -Sending file descriptors over pipes -+++++++++++++++++++++++++++++++++++ - -The cool thing about domain sockets is that file descriptors can be exchanged -between processes by sending them over a domain socket. This allows processes -to hand off their I/O to other processes. Applications include load-balancing -servers, worker processes and other ways to make optimum use of CPU. libuv only -supports sending **TCP sockets or other pipes** over pipes for now. - -To demonstrate, we will look at a echo server implementation that hands of -clients to worker processes in a round-robin fashion. This program is a bit -involved, and while only snippets are included in the book, it is recommended -to read the full code to really understand it. - -The worker process is quite simple, since the file-descriptor is handed over to -it by the master. - -.. rubric:: multi-echo-server/worker.c -.. literalinclude:: ../../code/multi-echo-server/worker.c - :linenos: - :lines: 7-9,81- - :emphasize-lines: 6-8 - -``queue`` is the pipe connected to the master process on the other end, along -which new file descriptors get sent. It is important to set the ``ipc`` -argument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for -inter-process communication! Since the master will write the file handle to the -standard input of the worker, we connect the pipe to ``stdin`` using -``uv_pipe_open``. - -.. rubric:: multi-echo-server/worker.c -.. literalinclude:: ../../code/multi-echo-server/worker.c - :linenos: - :lines: 51-79 - :emphasize-lines: 10,15,20 - -First we call ``uv_pipe_pending_count()`` to ensure that a handle is available -to read out. If your program could deal with different types of handles, -``uv_pipe_pending_type()`` can be used to determine the type. -Although ``accept`` seems odd in this code, it actually makes sense. What -``accept`` traditionally does is get a file descriptor (the client) from -another file descriptor (The listening socket). Which is exactly what we do -here. Fetch the file descriptor (``client``) from ``queue``. From this point -the worker does standard echo server stuff. - -Turning now to the master, let's take a look at how the workers are launched to -allow load balancing. - -.. rubric:: multi-echo-server/main.c -.. literalinclude:: ../../code/multi-echo-server/main.c - :linenos: - :lines: 9-13 - -The ``child_worker`` structure wraps the process, and the pipe between the -master and the individual process. - -.. rubric:: multi-echo-server/main.c -.. literalinclude:: ../../code/multi-echo-server/main.c - :linenos: - :lines: 51,61-95 - :emphasize-lines: 17,20-21 - -In setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to -get the number of CPUs so we can launch an equal number of workers. Again it is -important to initialize the pipe acting as the IPC channel with the third -argument as 1. We then indicate that the child process' ``stdin`` is to be -a readable pipe (from the point of view of the child). Everything is -straightforward till here. The workers are launched and waiting for file -descriptors to be written to their standard input. - -It is in ``on_new_connection`` (the TCP infrastructure is initialized in -``main()``), that we accept the client socket and pass it along to the next -worker in the round-robin. - -.. rubric:: multi-echo-server/main.c -.. literalinclude:: ../../code/multi-echo-server/main.c - :linenos: - :lines: 31-49 - :emphasize-lines: 9,12-13 - -The ``uv_write2`` call handles all the abstraction and it is simply a matter of -passing in the handle (``client``) as the right argument. With this our -multi-process echo server is operational. - -Thanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty -buffer even when sending handles. - -.. _pointing out: https://github.com/nikhilm/uvbook/issues/56 - ----- - -.. [#] In this section domain sockets stands in for named pipes on Windows as - well. diff --git a/3rd/libuv-1.19.2/docs/src/guide/threads.rst b/3rd/libuv-1.19.2/docs/src/guide/threads.rst deleted file mode 100644 index b6a4fd85..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/threads.rst +++ /dev/null @@ -1,381 +0,0 @@ -Threads -======= - -Wait a minute? Why are we on threads? Aren't event loops supposed to be **the -way** to do *web-scale programming*? Well... no. Threads are still the medium in -which processors do their jobs. Threads are therefore mighty useful sometimes, even -though you might have to wade through various synchronization primitives. - -Threads are used internally to fake the asynchronous nature of all of the system -calls. libuv also uses threads to allow you, the application, to perform a task -asynchronously that is actually blocking, by spawning a thread and collecting -the result when it is done. - -Today there are two predominant thread libraries: the Windows threads -implementation and POSIX's `pthreads`_. libuv's thread API is analogous to -the pthreads API and often has similar semantics. - -A notable aspect of libuv's thread facilities is that it is a self contained -section within libuv. Whereas other features intimately depend on the event -loop and callback principles, threads are complete agnostic, they block as -required, signal errors directly via return values, and, as shown in the -:ref:`first example `, don't even require a running -event loop. - -libuv's thread API is also very limited since the semantics and syntax of -threads are different on all platforms, with different levels of completeness. - -This chapter makes the following assumption: **There is only one event loop, -running in one thread (the main thread)**. No other thread interacts -with the event loop (except using ``uv_async_send``). - -Core thread operations ----------------------- - -There isn't much here, you just start a thread using ``uv_thread_create()`` and -wait for it to close using ``uv_thread_join()``. - -.. _thread-create-example: - -.. rubric:: thread-create/main.c -.. literalinclude:: ../../code/thread-create/main.c - :linenos: - :lines: 26-36 - :emphasize-lines: 3-7 - -.. tip:: - - ``uv_thread_t`` is just an alias for ``pthread_t`` on Unix, but this is an - implementation detail, avoid depending on it to always be true. - -The second parameter is the function which will serve as the entry point for -the thread, the last parameter is a ``void *`` argument which can be used to pass -custom parameters to the thread. The function ``hare`` will now run in a separate -thread, scheduled pre-emptively by the operating system: - -.. rubric:: thread-create/main.c -.. literalinclude:: ../../code/thread-create/main.c - :linenos: - :lines: 6-14 - :emphasize-lines: 2 - -Unlike ``pthread_join()`` which allows the target thread to pass back a value to -the calling thread using a second parameter, ``uv_thread_join()`` does not. To -send values use :ref:`inter-thread-communication`. - -Synchronization Primitives --------------------------- - -This section is purposely spartan. This book is not about threads, so I only -catalogue any surprises in the libuv APIs here. For the rest you can look at -the pthreads `man pages `_. - -Mutexes -~~~~~~~ - -The mutex functions are a **direct** map to the pthread equivalents. - -.. rubric:: libuv mutex functions -.. literalinclude:: ../../../include/uv.h - :lines: 1355-1360 - -The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()`` -functions will return 0 on success, and an error code otherwise. - -If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``, -``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error. -Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other -than* ``EAGAIN`` or ``EBUSY``. - -Recursive mutexes are supported, but you should not rely on them. Also, they -should not be used with ``uv_cond_t`` variables. - -The default BSD mutex implementation will raise an error if a thread which has -locked a mutex attempts to lock it again. For example, a construct like:: - - uv_mutex_init(a_mutex); - uv_mutex_lock(a_mutex); - uv_thread_create(thread_id, entry, (void *)a_mutex); - uv_mutex_lock(a_mutex); - // more things here - -can be used to wait until another thread initializes some stuff and then -unlocks ``a_mutex`` but will lead to your program crashing if in debug mode, or -return an error in the second call to ``uv_mutex_lock()``. - -.. note:: - - Mutexes on Windows are always recursive. - -Locks -~~~~~ - -Read-write locks are a more granular access mechanism. Two readers can access -shared memory at the same time. A writer may not acquire the lock when it is -held by a reader. A reader or writer may not acquire a lock when a writer is -holding it. Read-write locks are frequently used in databases. Here is a toy -example. - -.. rubric:: locks/main.c - simple rwlocks -.. literalinclude:: ../../code/locks/main.c - :linenos: - :emphasize-lines: 13,16,27,31,42,55 - -Run this and observe how the readers will sometimes overlap. In case of -multiple writers, schedulers will usually give them higher priority, so if you -add two writers, you'll see that both writers tend to finish first before the -readers get a chance again. - -We also use barriers in the above example so that the main thread can wait for -all readers and writers to indicate they have ended. - -Others -~~~~~~ - -libuv also supports semaphores_, `condition variables`_ and barriers_ with APIs -very similar to their pthread counterparts. - -.. _semaphores: http://en.wikipedia.org/wiki/Semaphore_(programming) -.. _condition variables: http://en.wikipedia.org/wiki/Condition_variable#Waiting_and_signaling -.. _barriers: http://en.wikipedia.org/wiki/Barrier_(computer_science) - -In addition, libuv provides a convenience function ``uv_once()``. Multiple -threads can attempt to call ``uv_once()`` with a given guard and a function -pointer, **only the first one will win, the function will be called once and -only once**:: - - /* Initialize guard */ - static uv_once_t once_only = UV_ONCE_INIT; - - int i = 0; - - void increment() { - i++; - } - - void thread1() { - /* ... work */ - uv_once(once_only, increment); - } - - void thread2() { - /* ... work */ - uv_once(once_only, increment); - } - - int main() { - /* ... spawn threads */ - } - -After all threads are done, ``i == 1``. - -.. _libuv-work-queue: - -libuv v0.11.11 onwards also added a ``uv_key_t`` struct and api_ for -thread-local storage. - -.. _api: http://docs.libuv.org/en/v1.x/threading.html#thread-local-storage - -libuv work queue ----------------- - -``uv_queue_work()`` is a convenience function that allows an application to run -a task in a separate thread, and have a callback that is triggered when the -task is done. A seemingly simple function, what makes ``uv_queue_work()`` -tempting is that it allows potentially any third-party libraries to be used -with the event-loop paradigm. When you use event loops, it is *imperative to -make sure that no function which runs periodically in the loop thread blocks -when performing I/O or is a serious CPU hog*, because this means that the loop -slows down and events are not being handled at full capacity. - -However, a lot of existing code out there features blocking functions (for example -a routine which performs I/O under the hood) to be used with threads if you -want responsiveness (the classic 'one thread per client' server model), and -getting them to play with an event loop library generally involves rolling your -own system of running the task in a separate thread. libuv just provides -a convenient abstraction for this. - -Here is a simple example inspired by `node.js is cancer`_. We are going to -calculate fibonacci numbers, sleeping a bit along the way, but run it in -a separate thread so that the blocking and CPU bound task does not prevent the -event loop from performing other activities. - -.. rubric:: queue-work/main.c - lazy fibonacci -.. literalinclude:: ../../code/queue-work/main.c - :linenos: - :lines: 17-29 - -The actual task function is simple, nothing to show that it is going to be -run in a separate thread. The ``uv_work_t`` structure is the clue. You can pass -arbitrary data through it using the ``void* data`` field and use it to -communicate to and from the thread. But be sure you are using proper locks if -you are changing things while both threads may be running. - -The trigger is ``uv_queue_work``: - -.. rubric:: queue-work/main.c -.. literalinclude:: ../../code/queue-work/main.c - :linenos: - :lines: 31-44 - :emphasize-lines: 10 - -The thread function will be launched in a separate thread, passed the -``uv_work_t`` structure and once the function returns, the *after* function -will be called on the thread the event loop is running in. It will be passed -the same structure. - -For writing wrappers to blocking libraries, a common :ref:`pattern ` -is to use a baton to exchange data. - -Since libuv version `0.9.4` an additional function, ``uv_cancel()``, is -available. This allows you to cancel tasks on the libuv work queue. Only tasks -that *are yet to be started* can be cancelled. If a task has *already started -executing, or it has finished executing*, ``uv_cancel()`` **will fail**. - -``uv_cancel()`` is useful to cleanup pending tasks if the user requests -termination. For example, a music player may queue up multiple directories to -be scanned for audio files. If the user terminates the program, it should quit -quickly and not wait until all pending requests are run. - -Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set -up a signal handler for termination. - -.. rubric:: queue-cancel/main.c -.. literalinclude:: ../../code/queue-cancel/main.c - :linenos: - :lines: 43- - -When the user triggers the signal by pressing ``Ctrl+C`` we send -``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished. - -.. rubric:: queue-cancel/main.c -.. literalinclude:: ../../code/queue-cancel/main.c - :linenos: - :lines: 33-41 - :emphasize-lines: 6 - -For tasks that do get cancelled successfully, the *after* function is called -with ``status`` set to ``UV_ECANCELED``. - -.. rubric:: queue-cancel/main.c -.. literalinclude:: ../../code/queue-cancel/main.c - :linenos: - :lines: 28-31 - :emphasize-lines: 2 - -``uv_cancel()`` can also be used with ``uv_fs_t`` and ``uv_getaddrinfo_t`` -requests. For the filesystem family of functions, ``uv_fs_t.errorno`` will be -set to ``UV_ECANCELED``. - -.. TIP:: - - A well designed program would have a way to terminate long running workers - that have already started executing. Such a worker could periodically check - for a variable that only the main process sets to signal termination. - -.. _inter-thread-communication: - -Inter-thread communication --------------------------- - -Sometimes you want various threads to actually send each other messages *while* -they are running. For example you might be running some long duration task in -a separate thread (perhaps using ``uv_queue_work``) but want to notify progress -to the main thread. This is a simple example of having a download manager -informing the user of the status of running downloads. - -.. rubric:: progress/main.c -.. literalinclude:: ../../code/progress/main.c - :linenos: - :lines: 7-8,34- - :emphasize-lines: 2,11 - -The async thread communication works *on loops* so although any thread can be -the message sender, only threads with libuv loops can be receivers (or rather -the loop is the receiver). libuv will invoke the callback (``print_progress``) -with the async watcher whenever it receives a message. - -.. warning:: - - It is important to realize that since the message send is *async*, the callback - may be invoked immediately after ``uv_async_send`` is called in another - thread, or it may be invoked after some time. libuv may also combine - multiple calls to ``uv_async_send`` and invoke your callback only once. The - only guarantee that libuv makes is -- The callback function is called *at - least once* after the call to ``uv_async_send``. If you have no pending - calls to ``uv_async_send``, the callback won't be called. If you make two - or more calls, and libuv hasn't had a chance to run the callback yet, it - *may* invoke your callback *only once* for the multiple invocations of - ``uv_async_send``. Your callback will never be called twice for just one - event. - -.. rubric:: progress/main.c -.. literalinclude:: ../../code/progress/main.c - :linenos: - :lines: 10-23 - :emphasize-lines: 7-8 - -In the download function, we modify the progress indicator and queue the message -for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also -non-blocking and will return immediately. - -.. rubric:: progress/main.c -.. literalinclude:: ../../code/progress/main.c - :linenos: - :lines: 30-33 - -The callback is a standard libuv pattern, extracting the data from the watcher. - -Finally it is important to remember to clean up the watcher. - -.. rubric:: progress/main.c -.. literalinclude:: ../../code/progress/main.c - :linenos: - :lines: 25-28 - :emphasize-lines: 3 - -After this example, which showed the abuse of the ``data`` field, bnoordhuis_ -pointed out that using the ``data`` field is not thread safe, and -``uv_async_send()`` is actually only meant to wake up the event loop. Use -a mutex or rwlock to ensure accesses are performed in the right order. - -.. note:: - - mutexes and rwlocks **DO NOT** work inside a signal handler, whereas - ``uv_async_send`` does. - -One use case where ``uv_async_send`` is required is when interoperating with -libraries that require thread affinity for their functionality. For example in -node.js, a v8 engine instance, contexts and its objects are bound to the thread -that the v8 instance was started in. Interacting with v8 data structures from -another thread can lead to undefined results. Now consider some node.js module -which binds a third party library. It may go something like this: - -1. In node, the third party library is set up with a JavaScript callback to be - invoked for more information:: - - var lib = require('lib'); - lib.on_progress(function() { - console.log("Progress"); - }); - - lib.do(); - - // do other stuff - -2. ``lib.do`` is supposed to be non-blocking but the third party lib is - blocking, so the binding uses ``uv_queue_work``. - -3. The actual work being done in a separate thread wants to invoke the progress - callback, but cannot directly call into v8 to interact with JavaScript. So - it uses ``uv_async_send``. - -4. The async callback, invoked in the main loop thread, which is the v8 thread, - then interacts with v8 to invoke the JavaScript callback. - -.. _pthreads: http://man7.org/linux/man-pages/man7/pthreads.7.html - ----- - -.. _node.js is cancer: http://teddziuba.github.io/2011/10/node-js-is-cancer.html -.. _bnoordhuis: https://github.com/bnoordhuis diff --git a/3rd/libuv-1.19.2/docs/src/guide/utilities.rst b/3rd/libuv-1.19.2/docs/src/guide/utilities.rst deleted file mode 100644 index abe6fa8d..00000000 --- a/3rd/libuv-1.19.2/docs/src/guide/utilities.rst +++ /dev/null @@ -1,433 +0,0 @@ -Utilities -========= - -This chapter catalogues tools and techniques which are useful for common tasks. -The `libev man page`_ already covers some patterns which can be adopted to -libuv through simple API changes. It also covers parts of the libuv API that -don't require entire chapters dedicated to them. - -Timers ------- - -Timers invoke the callback after a certain time has elapsed since the timer was -started. libuv timers can also be set to invoke at regular intervals instead of -just once. - -Simple use is to init a watcher and start it with a ``timeout``, and optional ``repeat``. -Timers can be stopped at any time. - -.. code-block:: c - - uv_timer_t timer_req; - - uv_timer_init(loop, &timer_req); - uv_timer_start(&timer_req, callback, 5000, 2000); - -will start a repeating timer, which first starts 5 seconds (the ``timeout``) after the execution -of ``uv_timer_start``, then repeats every 2 seconds (the ``repeat``). Use: - -.. code-block:: c - - uv_timer_stop(&timer_req); - -to stop the timer. This can be used safely from within the callback as well. - -The repeat interval can be modified at any time with:: - - uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat); - -which will take effect **when possible**. If this function is called from -a timer callback, it means: - -* If the timer was non-repeating, the timer has already been stopped. Use - ``uv_timer_start`` again. -* If the timer is repeating, the next timeout has already been scheduled, so - the old repeat interval will be used once more before the timer switches to - the new interval. - -The utility function:: - - int uv_timer_again(uv_timer_t *) - -applies **only to repeating timers** and is equivalent to stopping the timer -and then starting it with both initial ``timeout`` and ``repeat`` set to the -old ``repeat`` value. If the timer hasn't been started it fails (error code -``UV_EINVAL``) and returns -1. - -An actual timer example is in the :ref:`reference count section -`. - -.. _reference-count: - -Event loop reference count --------------------------- - -The event loop only runs as long as there are active handles. This system -works by having every handle increase the reference count of the event loop -when it is started and decreasing the reference count when stopped. It is also -possible to manually change the reference count of handles using:: - - void uv_ref(uv_handle_t*); - void uv_unref(uv_handle_t*); - -These functions can be used to allow a loop to exit even when a watcher is -active or to use custom objects to keep the loop alive. - -The latter can be used with interval timers. You might have a garbage collector -which runs every X seconds, or your network service might send a heartbeat to -others periodically, but you don't want to have to stop them along all clean -exit paths or error scenarios. Or you want the program to exit when all your -other watchers are done. In that case just unref the timer immediately after -creation so that if it is the only watcher running then ``uv_run`` will still -exit. - -This is also used in node.js where some libuv methods are being bubbled up to -the JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per -JS object and can be ref/unrefed. - -.. rubric:: ref-timer/main.c -.. literalinclude:: ../../code/ref-timer/main.c - :linenos: - :lines: 5-8, 17- - :emphasize-lines: 9 - -We initialize the garbage collector timer, then immediately ``unref`` it. -Observe how after 9 seconds, when the fake job is done, the program -automatically exits, even though the garbage collector is still running. - -Idler pattern -------------- - -The callbacks of idle handles are invoked once per event loop. The idle -callback can be used to perform some very low priority activity. For example, -you could dispatch a summary of the daily application performance to the -developers for analysis during periods of idleness, or use the application's -CPU time to perform SETI calculations :) An idle watcher is also useful in -a GUI application. Say you are using an event loop for a file download. If the -TCP socket is still being established and no other events are present your -event loop will pause (**block**), which means your progress bar will freeze -and the user will face an unresponsive application. In such a case queue up and -idle watcher to keep the UI operational. - -.. rubric:: idle-compute/main.c -.. literalinclude:: ../../code/idle-compute/main.c - :linenos: - :lines: 5-9, 34- - :emphasize-lines: 13 - -Here we initialize the idle watcher and queue it up along with the actual -events we are interested in. ``crunch_away`` will now be called repeatedly -until the user types something and presses Return. Then it will be interrupted -for a brief amount as the loop deals with the input data, after which it will -keep calling the idle callback again. - -.. rubric:: idle-compute/main.c -.. literalinclude:: ../../code/idle-compute/main.c - :linenos: - :lines: 10-19 - -.. _baton: - -Passing data to worker thread ------------------------------ - -When using ``uv_queue_work`` you'll usually need to pass complex data through -to the worker thread. The solution is to use a ``struct`` and set -``uv_work_t.data`` to point to it. A slight variation is to have the -``uv_work_t`` itself as the first member of this struct (called a baton [#]_). -This allows cleaning up the work request and all the data in one free call. - -.. code-block:: c - :linenos: - :emphasize-lines: 2 - - struct ftp_baton { - uv_work_t req; - char *host; - int port; - char *username; - char *password; - } - -.. code-block:: c - :linenos: - :emphasize-lines: 2 - - ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton)); - baton->req.data = (void*) baton; - baton->host = strdup("my.webhost.com"); - baton->port = 21; - // ... - - uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup); - -Here we create the baton and queue the task. - -Now the task function can extract the data it needs: - -.. code-block:: c - :linenos: - :emphasize-lines: 2, 12 - - void ftp_session(uv_work_t *req) { - ftp_baton *baton = (ftp_baton*) req->data; - - fprintf(stderr, "Connecting to %s\n", baton->host); - } - - void ftp_cleanup(uv_work_t *req) { - ftp_baton *baton = (ftp_baton*) req->data; - - free(baton->host); - // ... - free(baton); - } - -We then free the baton which also frees the watcher. - -External I/O with polling -------------------------- - -Usually third-party libraries will handle their own I/O, and keep track of -their sockets and other files internally. In this case it isn't possible to use -the standard stream I/O operations, but the library can still be integrated -into the libuv event loop. All that is required is that the library allow you -to access the underlying file descriptors and provide functions that process -tasks in small increments as decided by your application. Some libraries though -will not allow such access, providing only a standard blocking function which -will perform the entire I/O transaction and only then return. It is unwise to -use these in the event loop thread, use the :ref:`libuv-work-queue` instead. Of -course, this will also mean losing granular control on the library. - -The ``uv_poll`` section of libuv simply watches file descriptors using the -operating system notification mechanism. In some sense, all the I/O operations -that libuv implements itself are also backed by ``uv_poll`` like code. Whenever -the OS notices a change of state in file descriptors being polled, libuv will -invoke the associated callback. - -Here we will walk through a simple download manager that will use libcurl_ to -download files. Rather than give all control to libcurl, we'll instead be -using the libuv event loop, and use the non-blocking, async multi_ interface to -progress with the download whenever libuv notifies of I/O readiness. - -.. _libcurl: http://curl.haxx.se/libcurl/ -.. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html - -.. rubric:: uvwget/main.c - The setup -.. literalinclude:: ../../code/uvwget/main.c - :linenos: - :lines: 1-9,140- - :emphasize-lines: 7,21,24-25 - -The way each library is integrated with libuv will vary. In the case of -libcurl, we can register two callbacks. The socket callback ``handle_socket`` -is invoked whenever the state of a socket changes and we have to start polling -it. ``start_timeout`` is called by libcurl to notify us of the next timeout -interval, after which we should drive libcurl forward regardless of I/O status. -This is so that libcurl can handle errors or do whatever else is required to -get the download moving. - -Our downloader is to be invoked as:: - - $ ./uvwget [url1] [url2] ... - -So we add each argument as an URL - -.. rubric:: uvwget/main.c - Adding urls -.. literalinclude:: ../../code/uvwget/main.c - :linenos: - :lines: 39-56 - :emphasize-lines: 13-14 - -We let libcurl directly write the data to a file, but much more is possible if -you so desire. - -``start_timeout`` will be called immediately the first time by libcurl, so -things are set in motion. This simply starts a libuv `timer `_ which -drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it -times out. ``curl_multi_socket_action`` is what drives libcurl, and what we -call whenever sockets change state. But before we go into that, we need to poll -on sockets whenever ``handle_socket`` is called. - -.. rubric:: uvwget/main.c - Setting up polling -.. literalinclude:: ../../code/uvwget/main.c - :linenos: - :lines: 102-140 - :emphasize-lines: 9,11,15,21,24 - -We are interested in the socket fd ``s``, and the ``action``. For every socket -we create a ``uv_poll_t`` handle if it doesn't exist, and associate it with the -socket using ``curl_multi_assign``. This way ``socketp`` points to it whenever -the callback is invoked. - -In the case that the download is done or fails, libcurl requests removal of the -poll. So we stop and free the poll handle. - -Depending on what events libcurl wishes to watch for, we start polling with -``UV_READABLE`` or ``UV_WRITABLE``. Now libuv will invoke the poll callback -whenever the socket is ready for reading or writing. Calling ``uv_poll_start`` -multiple times on the same handle is acceptable, it will just update the events -mask with the new value. ``curl_perform`` is the crux of this program. - -.. rubric:: uvwget/main.c - Driving libcurl. -.. literalinclude:: ../../code/uvwget/main.c - :linenos: - :lines: 81-95 - :emphasize-lines: 2,6-7,12 - -The first thing we do is to stop the timer, since there has been some progress -in the interval. Then depending on what event triggered the callback, we set -the correct flags. Then we call ``curl_multi_socket_action`` with the socket -that progressed and the flags informing about what events happened. At this -point libcurl does all of its internal tasks in small increments, and will -attempt to return as fast as possible, which is exactly what an evented program -wants in its main thread. libcurl keeps queueing messages into its own queue -about transfer progress. In our case we are only interested in transfers that -are completed. So we extract these messages, and clean up handles whose -transfers are done. - -.. rubric:: uvwget/main.c - Reading transfer status. -.. literalinclude:: ../../code/uvwget/main.c - :linenos: - :lines: 58-79 - :emphasize-lines: 6,9-10,13-14 - -Check & Prepare watchers ------------------------- - -TODO - -Loading libraries ------------------ - -libuv provides a cross platform API to dynamically load `shared libraries`_. -This can be used to implement your own plugin/extension/module system and is -used by node.js to implement ``require()`` support for bindings. The usage is -quite simple as long as your library exports the right symbols. Be careful with -sanity and security checks when loading third party code, otherwise your -program will behave unpredictably. This example implements a very simple -plugin system which does nothing except print the name of the plugin. - -Let us first look at the interface provided to plugin authors. - -.. rubric:: plugin/plugin.h -.. literalinclude:: ../../code/plugin/plugin.h - :linenos: - -You can similarly add more functions that plugin authors can use to do useful -things in your application [#]_. A sample plugin using this API is: - -.. rubric:: plugin/hello.c -.. literalinclude:: ../../code/plugin/hello.c - :linenos: - -Our interface defines that all plugins should have an ``initialize`` function -which will be called by the application. This plugin is compiled as a shared -library and can be loaded by running our application:: - - $ ./plugin libhello.dylib - Loading libhello.dylib - Registered plugin "Hello World!" - -.. NOTE:: - - The shared library filename will be different depending on platforms. On - Linux it is ``libhello.so``. - -This is done by using ``uv_dlopen`` to first load the shared library -``libhello.dylib``. Then we get access to the ``initialize`` function using -``uv_dlsym`` and invoke it. - -.. rubric:: plugin/main.c -.. literalinclude:: ../../code/plugin/main.c - :linenos: - :lines: 7- - :emphasize-lines: 15, 18, 24 - -``uv_dlopen`` expects a path to the shared library and sets the opaque -``uv_lib_t`` pointer. It returns 0 on success, -1 on error. Use ``uv_dlerror`` -to get the error message. - -``uv_dlsym`` stores a pointer to the symbol in the second argument in the third -argument. ``init_plugin_function`` is a function pointer to the sort of -function we are looking for in the application's plugins. - -.. _shared libraries: http://en.wikipedia.org/wiki/Shared_library#Shared_libraries - -TTY ---- - -Text terminals have supported basic formatting for a long time, with a `pretty -standardised`_ command set. This formatting is often used by programs to -improve the readability of terminal output. For example ``grep --colour``. -libuv provides the ``uv_tty_t`` abstraction (a stream) and related functions to -implement the ANSI escape codes across all platforms. By this I mean that libuv -converts ANSI codes to the Windows equivalent, and provides functions to get -terminal information. - -.. _pretty standardised: http://en.wikipedia.org/wiki/ANSI_escape_sequences - -The first thing to do is to initialize a ``uv_tty_t`` with the file descriptor -it reads/writes from. This is achieved with:: - - int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable) - -Set ``readable`` to true if you plan to use ``uv_read_start()`` on the stream. - -It is then best to use ``uv_tty_set_mode`` to set the mode to *normal* -which enables most TTY formatting, flow-control and other settings. Other_ modes -are also available. - -.. _Other: http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t - -Remember to call ``uv_tty_reset_mode`` when your program exits to restore the -state of the terminal. Just good manners. Another set of good manners is to be -aware of redirection. If the user redirects the output of your command to -a file, control sequences should not be written as they impede readability and -``grep``. To check if the file descriptor is indeed a TTY, call -``uv_guess_handle`` with the file descriptor and compare the return value with -``UV_TTY``. - -Here is a simple example which prints white text on a red background: - -.. rubric:: tty/main.c -.. literalinclude:: ../../code/tty/main.c - :linenos: - :emphasize-lines: 11-12,14,17,27 - -The final TTY helper is ``uv_tty_get_winsize()`` which is used to get the -width and height of the terminal and returns ``0`` on success. Here is a small -program which does some animation using the function and character position -escape codes. - -.. rubric:: tty-gravity/main.c -.. literalinclude:: ../../code/tty-gravity/main.c - :linenos: - :emphasize-lines: 19,25,38 - -The escape codes are: - -====== ======================= -Code Meaning -====== ======================= -*2* J Clear part of the screen, 2 is entire screen -H Moves cursor to certain position, default top-left -*n* B Moves cursor down by n lines -*n* C Moves cursor right by n columns -m Obeys string of display settings, in this case green background (40+2), white text (30+7) -====== ======================= - -As you can see this is very useful to produce nicely formatted output, or even -console based arcade games if that tickles your fancy. For fancier control you -can try `ncurses`_. - -.. _ncurses: http://www.gnu.org/software/ncurses/ncurses.html - ----- - -.. [#] I was first introduced to the term baton in this context, in Konstantin - Käfer's excellent slides on writing node.js bindings -- - http://kkaefer.github.com/node-cpp-modules/#baton -.. [#] mfp is My Fancy Plugin - -.. _libev man page: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_OR_BOTH diff --git a/3rd/libuv-1.19.2/docs/src/handle.rst b/3rd/libuv-1.19.2/docs/src/handle.rst deleted file mode 100644 index cdfb76bf..00000000 --- a/3rd/libuv-1.19.2/docs/src/handle.rst +++ /dev/null @@ -1,264 +0,0 @@ - -.. _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. - -Libuv handles are not movable. Pointers to handle structures passed to -functions must remain valid for the duration of the requested operation. Take -care when using stack allocated handles. - -Data types ----------- - -.. c:type:: uv_handle_t - - The base libuv handle type. - -.. c:type:: uv_handle_type - - The kind of the libuv handle. - - :: - - typedef enum { - UV_UNKNOWN_HANDLE = 0, - UV_ASYNC, - UV_CHECK, - UV_FS_EVENT, - UV_FS_POLL, - UV_HANDLE, - UV_IDLE, - UV_NAMED_PIPE, - UV_POLL, - UV_PREPARE, - UV_PROCESS, - UV_STREAM, - UV_TCP, - UV_TIMER, - UV_TTY, - UV_UDP, - UV_SIGNAL, - UV_FILE, - UV_HANDLE_TYPE_MAX - } uv_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 allocate memory and fill the supplied - :c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length, - a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the - :c:type:`uv_read_cb` callback. - - A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, - not related in any way to the pending data to be read. The user is free to allocate the amount - of memory they decide. - - As an example, applications with custom allocation schemes such as using freelists, allocation - pools or slab based allocators may decide to use a different size which matches the memory - chunks they already have. - - Example: - - :: - - static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; - } - -.. 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:: uv_handle_type uv_handle_t.type - - The :c:type:`uv_handle_type`, indicating the type of the underlying handle. 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. - -.. c:function:: uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) - - Returns `handle->loop`. - - .. versionadded:: 1.19.0 - -.. c:function:: void* uv_handle_get_data(const uv_handle_t* handle) - - Returns `handle->data`. - - .. versionadded:: 1.19.0 - -.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data) - - Sets `handle->data` to `data`. - - .. versionadded:: 1.19.0 - -.. c:function:: uv_handle_type uv_handle_get_type(const uv_handle_t* handle) - - Returns `handle->type`. - - .. versionadded:: 1.19.0 - -.. c:function:: const char* uv_handle_type_name(uv_handle_type type) - - Returns the name for the equivalent struct for a given handle type, - e.g. `"pipe"` (as in :c:type:`uv_pipe_t`) for `UV_NAMED_PIPE`. - - If no such handle type exists, this returns `NULL`. - - .. versionadded:: 1.19.0 - -.. _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/3rd/libuv-1.19.2/docs/src/idle.rst b/3rd/libuv-1.19.2/docs/src/idle.rst deleted file mode 100644 index 1f51c4a1..00000000 --- a/3rd/libuv-1.19.2/docs/src/idle.rst +++ /dev/null @@ -1,54 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/index.rst b/3rd/libuv-1.19.2/docs/src/index.rst deleted file mode 100644 index 5ec2beb5..00000000 --- a/3rd/libuv-1.19.2/docs/src/index.rst +++ /dev/null @@ -1,62 +0,0 @@ - -Welcome to the libuv 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 `_! - -.. _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 - - -Documentation -------------- - -.. toctree:: - :maxdepth: 1 - - design - api - guide - upgrading - - -Downloads ---------- - -libuv can be downloaded from `here `_. - - -Installation ------------- - -Installation instructions can be found in `the README `_. - diff --git a/3rd/libuv-1.19.2/docs/src/loop.rst b/3rd/libuv-1.19.2/docs/src/loop.rst deleted file mode 100644 index 86a99adf..00000000 --- a/3rd/libuv-1.19.2/docs/src/loop.rst +++ /dev/null @@ -1,236 +0,0 @@ - -.. _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 and does not - touch this field. - - -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) - - Releases all internal loop resources. Call this function only when the loop - has finished executing and all open handles and requests have been closed, - or it will return UV_EBUSY. After this function returns, the user can 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. - - .. warning:: - This function is not thread safe. - -.. 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 referenced active handles, active - requests or closing handles 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`. - -.. c:function:: int uv_loop_fork(uv_loop_t* loop) - - .. versionadded:: 1.12.0 - - Reinitialize any kernel state necessary in the child process after - a :man:`fork(2)` system call. - - Previously started watchers will continue to be started in the - child process. - - It is necessary to explicitly call this function on every event - loop created in the parent process that you plan to continue to - use in the child, including the default loop (even if you don't - continue to use it in the parent). This function must be called - before calling :c:func:`uv_run` or any other API function using - the loop in the child. Failure to do so will result in undefined - behaviour, possibly including duplicate events delivered to both - parent and child or aborting the child process. - - When possible, it is preferred to create a new loop in the child - process instead of reusing a loop created in the parent. New loops - created in the child process after the fork should not use this - function. - - This function is not implemented on Windows, where it returns ``UV_ENOSYS``. - - .. caution:: - - This function is experimental. It may contain bugs, and is subject to - change or removal. API and ABI stability is not guaranteed. - - .. note:: - - On Mac OS X, if directory FS event handles were in use in the - parent process *for any event loop*, the child process will no - longer be able to use the most efficient FSEvent - implementation. Instead, uses of directory FS event handles in - the child will fall back to the same implementation used for - files and on other kqueue-based systems. - - .. caution:: - - On AIX and SunOS, FS event handles that were already started in - the parent process at the time of forking will *not* deliver - events in the child process; they must be closed and restarted. - On all other platforms, they will continue to work normally - without any further intervention. - - .. caution:: - - Any previous value returned from :c:func:`uv_backend_fd` is now - invalid. That function must be called again to determine the - correct backend file descriptor. - -.. c:function:: void* uv_loop_get_data(const uv_loop_t* loop) - - Returns `loop->data`. - - .. versionadded:: 1.19.0 - -.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data) - - Sets `loop->data` to `data`. - - .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/migration_010_100.rst b/3rd/libuv-1.19.2/docs/src/migration_010_100.rst deleted file mode 100644 index bb6ac1a8..00000000 --- a/3rd/libuv-1.19.2/docs/src/migration_010_100.rst +++ /dev/null @@ -1,244 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/misc.rst b/3rd/libuv-1.19.2/docs/src/misc.rst deleted file mode 100644 index 07908c98..00000000 --- a/3rd/libuv-1.19.2/docs/src/misc.rst +++ /dev/null @@ -1,519 +0,0 @@ - -.. _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. - - .. c:member:: size_t uv_buf_t.len - - Total bytes in the buffer. - - .. 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_pid_t - - Cross platform representation of a `pid_t`. - - .. versionadded:: 1.16.0 - -.. 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 (X) */ - uint64_t ru_idrss; /* integral unshared data size (X) */ - uint64_t ru_isrss; /* integral unshared stack size (X) */ - uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */ - uint64_t ru_majflt; /* page faults (hard page faults) */ - uint64_t ru_nswap; /* swaps (X) */ - uint64_t ru_inblock; /* block input operations */ - uint64_t ru_oublock; /* block output operations */ - uint64_t ru_msgsnd; /* IPC messages sent (X) */ - uint64_t ru_msgrcv; /* IPC messages received (X) */ - uint64_t ru_nsignals; /* signals received (X) */ - uint64_t ru_nvcsw; /* voluntary context switches (X) */ - uint64_t ru_nivcsw; /* involuntary context switches (X) */ - } uv_rusage_t; - - Members marked with `(X)` are unsupported on Windows. - See :man:`getrusage(2)` for supported fields on Unix - -.. 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; - -.. c:type:: uv_passwd_t - - Data type for password file information. - - :: - - typedef struct uv_passwd_s { - char* username; - long uid; - long gid; - char* shell; - char* homedir; - } uv_passwd_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. You *must* call `uv_setup_args` - before calling this function. If `buffer` is `NULL` or `size` is zero, - `UV_EINVAL` is returned. If `size` cannot accommodate the process title and - terminating `NULL` character, the function returns `UV_ENOBUFS`. - - .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. - -.. c:function:: int uv_set_process_title(const char* title) - - Sets the current process title. You *must* call `uv_setup_args` before - calling this function. On platforms with a fixed size buffer for the process - title the contents of `title` will be copied to the buffer and truncated if - larger than the available space. Other platforms will return `UV_ENOMEM` if - they cannot allocate enough space to duplicate the contents of `title`. - - .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. - -.. 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. - See :c:type:`uv_rusage_t` for more details. - -.. c:function:: uv_pid_t uv_os_getpid(void) - - Returns the current process ID. - - .. versionadded:: 1.18.0 - -.. c:function:: uv_pid_t uv_os_getppid(void) - - Returns the parent process ID. - - .. versionadded:: 1.16.0 - -.. 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: ``_ - - .. 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:macro:: UV_IF_NAMESIZE - - Maximum IPv6 interface identifier name length. Defined as - `IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows. - - .. versionadded:: 1.16.0 - -.. c:function:: int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) - - IPv6-capable implementation of :man:`if_indextoname(3)`. When called, - `*size` indicates the length of the `buffer`, which is used to store the - result. - On success, zero is returned, `buffer` contains the interface name, and - `*size` represents the string length of the `buffer`, excluding the NUL - terminator byte from `*size`. On error, a negative result is - returned. If `buffer` is not large enough to hold the result, - `UV_ENOBUFS` is returned, and `*size` represents the necessary size in - bytes, including the NUL terminator byte into the `*size`. - - On Unix, the returned interface name can be used directly as an - interface identifier in scoped IPv6 addresses, e.g. - `fe80::abc:def1:2345%en0`. - - On Windows, the returned interface cannot be used as an interface - identifier, as Windows uses numerical interface identifiers, e.g. - `fe80::abc:def1:2345%5`. - - To get an interface identifier in a cross-platform compatible way, - use `uv_if_indextoiid()`. - - Example: - - :: - - char ifname[UV_IF_NAMESIZE]; - size_t size = sizeof(ifname); - uv_if_indextoname(sin6->sin6_scope_id, ifname, &size); - - .. versionadded:: 1.16.0 - -.. c:function:: int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) - - Retrieves a network interface identifier suitable for use in an IPv6 scoped - address. On Windows, returns the numeric `ifindex` as a string. On all other - platforms, `uv_if_indextoname()` is called. The result is written to - `buffer`, with `*size` indicating the length of `buffer`. If `buffer` is not - large enough to hold the result, then `UV_ENOBUFS` is returned, and `*size` - represents the size, including the NUL byte, required to hold the - result. - - See `uv_if_indextoname` for further details. - - .. versionadded:: 1.16.0 - -.. 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, and stores it in `buffer`. If the - current working directory is too large to fit in `buffer`, this function - returns `UV_ENOBUFS`, and sets `size` to the required length, including the - null terminator. - - .. versionchanged:: 1.1.0 - - On Unix the path no longer ends in a slash. - - .. versionchanged:: 1.9.0 the returned length includes the terminating null - byte on `UV_ENOBUFS`, and the buffer is null terminated - on success. - - -.. 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 `size` is set - to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the - required length for `buffer`, including the null byte. - - .. warning:: - `uv_os_homedir()` is not thread safe. - - .. versionadded:: 1.6.0 - -.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) - - Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. - On all other operating systems, `uv_os_tmpdir()` uses the first environment - variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. - If none of these are found, the path `"/tmp"` is used, or, on Android, - `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When - `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. - On success `size` is set to the string length of `buffer` (which does not - include the terminating null). On `UV_ENOBUFS` failure `size` is set to the - required length for `buffer`, including the null byte. - - .. warning:: - `uv_os_tmpdir()` is not thread safe. - - .. versionadded:: 1.9.0 - -.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) - - Gets a subset of the password file entry for the current effective uid (not - the real uid). The populated data includes the username, euid, gid, shell, - and home directory. On non-Windows systems, all data comes from - :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no - meaning, and shell is `NULL`. After successfully calling this function, the - memory allocated to `pwd` needs to be freed with - :c:func:`uv_os_free_passwd`. - - .. versionadded:: 1.9.0 - -.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) - - Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. - - .. versionadded:: 1.9.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 - -.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size) - - Retrieves the environment variable specified by `name`, copies its value - into `buffer`, and sets `size` to the string length of the value. When - calling this function, `size` must be set to the amount of storage available - in `buffer`, including the null terminator. If the environment variable - exceeds the storage available in `buffer`, `UV_ENOBUFS` is returned, and - `size` is set to the amount of storage required to hold the value. If no - matching environment variable exists, `UV_ENOENT` is returned. - - .. warning:: - This function is not thread safe. - - .. versionadded:: 1.12.0 - -.. c:function:: int uv_os_setenv(const char* name, const char* value) - - Creates or updates the environment variable specified by `name` with - `value`. - - .. warning:: - This function is not thread safe. - - .. versionadded:: 1.12.0 - -.. c:function:: int uv_os_unsetenv(const char* name) - - Deletes the environment variable specified by `name`. If no such environment - variable exists, this function returns successfully. - - .. warning:: - This function is not thread safe. - - .. versionadded:: 1.12.0 - -.. c:function:: int uv_os_gethostname(char* buffer, size_t* size) - - Returns the hostname as a null-terminated string in `buffer`, and sets - `size` to the string length of the hostname. When calling this function, - `size` must be set to the amount of storage available in `buffer`, including - the null terminator. If the hostname exceeds the storage available in - `buffer`, `UV_ENOBUFS` is returned, and `size` is set to the amount of - storage required to hold the value. - - .. versionadded:: 1.12.0 diff --git a/3rd/libuv-1.19.2/docs/src/pipe.rst b/3rd/libuv-1.19.2/docs/src/pipe.rst deleted file mode 100644 index bdaeeba9..00000000 --- a/3rd/libuv-1.19.2/docs/src/pipe.rst +++ /dev/null @@ -1,113 +0,0 @@ - -.. _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. - -.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags) - - Alters pipe permissions, allowing it to be accessed from processes run by - different users. Makes the pipe writable or readable by all users. Mode can - be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This - function is blocking. - - .. versionadded:: 1.16.0 diff --git a/3rd/libuv-1.19.2/docs/src/poll.rst b/3rd/libuv-1.19.2/docs/src/poll.rst deleted file mode 100644 index aba89158..00000000 --- a/3rd/libuv-1.19.2/docs/src/poll.rst +++ /dev/null @@ -1,121 +0,0 @@ - -.. _poll: - -:c:type:`uv_poll_t` --- Poll handle -=================================== - -Poll handles are used to watch file descriptors for readability, -writability and disconnection 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. - -.. note:: - On AIX, watching for disconnection is not supported. - -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, - UV_DISCONNECT = 4, - UV_PRIORITIZED = 8 - }; - - -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 made up of - UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. 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. - - The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band - messages. - - The UV_DISCONNECT event is optional in the sense that it may not be - reported and the user is free to ignore it, but it can help optimize the shutdown - path because an extra read or write call might be avoided. - - 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. - - .. note:: - Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set - on the `events` field in the callback. - - .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. - .. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event. - -.. 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/3rd/libuv-1.19.2/docs/src/prepare.rst b/3rd/libuv-1.19.2/docs/src/prepare.rst deleted file mode 100644 index aca58155..00000000 --- a/3rd/libuv-1.19.2/docs/src/prepare.rst +++ /dev/null @@ -1,46 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/docs/src/process.rst b/3rd/libuv-1.19.2/docs/src/process.rst deleted file mode 100644 index ecc3cbf3..00000000 --- a/3rd/libuv-1.19.2/docs/src/process.rst +++ /dev/null @@ -1,231 +0,0 @@ - -.. _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. - -.. c:function:: uv_pid_t uv_process_get_pid(const uv_process_t* handle) - - Returns `handle->pid`. - - .. versionadded:: 1.19.0 - -.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/request.rst b/3rd/libuv-1.19.2/docs/src/request.rst deleted file mode 100644 index 54d9a2f3..00000000 --- a/3rd/libuv-1.19.2/docs/src/request.rst +++ /dev/null @@ -1,109 +0,0 @@ - -.. _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. - -.. c:function:: void* uv_req_get_data(const uv_req_t* req) - - Returns `req->data`. - - .. versionadded:: 1.19.0 - -.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data) - - Sets `req->data` to `data`. - - .. versionadded:: 1.19.0 - -.. c:function:: uv_req_type uv_req_get_type(const uv_req_t* req) - - Returns `req->type`. - - .. versionadded:: 1.19.0 - -.. c:function:: const char* uv_req_type_name(uv_req_type type) - - Returns the name for the equivalent struct for a given request type, - e.g. `"connect"` (as in :c:type:`uv_connect_t`) for `UV_CONNECT`. - - If no such request type exists, this returns `NULL`. - - .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/signal.rst b/3rd/libuv-1.19.2/docs/src/signal.rst deleted file mode 100644 index 24354e4f..00000000 --- a/3rd/libuv-1.19.2/docs/src/signal.rst +++ /dev/null @@ -1,78 +0,0 @@ - -.. _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. - -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. - -.. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. - -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_start_oneshot(uv_signal_t* signal, uv_signal_cb cb, int signum) - - .. versionadded:: 1.12.0 - - Same functionality as :c:func:`uv_signal_start` but the signal handler is reset the moment - the signal is received. - -.. 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/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py b/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py deleted file mode 100644 index 1d1dc379..00000000 --- a/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py +++ /dev/null @@ -1,46 +0,0 @@ -# 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/3rd/libuv-1.19.2/docs/src/static/architecture.png b/3rd/libuv-1.19.2/docs/src/static/architecture.png deleted file mode 100644 index 81e8749f2495741d4b4c2c5dd8a6bca8803d8818..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206767 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

|<0@v3w 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 aM1obxbA2B^pWMfP?%y@PQ+oUP>;DChUmDi{ diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg deleted file mode 100644 index 439f58109369c37760ce8f9b4710711c17993d8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19328 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 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg deleted file mode 100644 index ffb21ff22457dac44441fb7e83272c72fbc4d59e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12655 zcmb_>2UwF!*8iJ82vvG7LArG5AX24^2qGXTNRt{m(us9+Ip9@erurAz3k%Q38eu5q=%o6iH-)h#SKetcpm@-$N&=HJOJ3* z`+6B((>4XbqNk94O+)go+_!Rqq0)m+36g&NnMStV@9jl#U2c(As$a5;Qmjlw_6nB95 z(OrK>5EESnanxNG#{dwIfSAwSAL#;OEQlG9j<&u4Kumc`_j9y&2C*cFDSb>$G(oHk z0Hl;of5CQt!G4Z`pqv1p>FE{Z+dTP`X7>UBY9axEW#Ug7Up4?xKLmj4{=ewMbh=)g{rtR?BqRa? z0>oV$?Zrly^~Z}0$vjW|Hl&j1i@^a8~66adl9Ot1y=w|TovW(J(@JafeI@9Q4KVEb?1fA0&~C; zum+%kec%`ZfxsbD5PAqJ1OefPh(M$u3J?{D7UVL-1abp%8{!1J^mpqx+vs0362stz@PnnG_uouJ;(VCX|= z0`xgF2U-lRhJJ+hK)*rfpli@QB7lg3h>7Sdkr`1i{z%{uH^U0pOcr8cal$$ z?@&-s@K7jH7*n`V+@p9-@t)!{#XQ9!B^{+Or6%P~N`J}($^yz(%5lmaDk>@gDm5xg zDnF_OszR!Esu?Qm8TvEgXY|fEoI#z*I8%LQ=*%WH88tt(I<+-*Fm)<*1$965It>|( z0F5S%EloI022CB!7|k9nJ?(i~BU&VF9PK;WZrT+(IGq5U7M%m#L%LkLcDhA+B6?nW zO?rF!2>Lhlo%Bl#Bn*NKdJL`%u?!^)eGF(uIz|~rGsZy148|tLIVK_|0VX{rccw(9 za;8zHBW6x!b!JEA$IPY7L(B&(>?~?5jw~@OWh~!Vj##-_wOHL)lUQq5r`d?vgxQSQ z0@yOyI@#9Q8Q3qd+q1{8m$OfBKskgtOgKU~ayfcA_BgpXbvV5^UvRc_u5&SQsd2e- zJ>_cVT1C(!R1hwRr-&BBFK$L|b#8a==iD9K=(8MWb@klZ&vl*$JY_u7 zyyUzJymxq?^0x7!`4D`De4%_rd=va+{0jWe{Av7M{09Pp0_FnI0yP3Ff-Hi1g294C zf>T0NLaIXELODVs=Sa>eoO3((>fC@ZR9IHnSvW(uUj!;5C*mUVN@P$JCaNgvA(|sP zCPpcyE_PR}NNir5N&K?-1MwR1O$j~;ONk_jE(yG(tfaf-8_CJ@bm#TYKR921ep^ad z%3dl%YDAh!T3Z?=T`P@|5s`6}$&~pnOD}6E8!g)=dm<+<=Ob4tw<^yke_Q^g{FnlR z!c~Phh0lsGMGZxiVx!`rlAMyCQn}LB1+fcm7v5c1Q5IBoRDPqpc#-F#?Zwv@=Tx{= zZmVRg%&DGLwN=egT~Omyb5P4yTUI}(?y6p_zNsOp;iFNdaiFQB8K&8KiRhBfrI<^7 zT69|1wbHd_w0X3hw2QRSIfZQoSGG|_bOy3lq1>uqM#W;e|W%?`{jnJ1giSx8ufS@hgsyWw)9))H=MW|?of zXQgHJ%xdYT?9Hf~qqhWa1>WkmX0vv;ZnB}av9+nV4ZCfA``vAvt&wex?Vg>U-Ag;P zy{3Jd{hEWC!&8S<$BT~1j>~s0-buc*;&jm|#c9=9)j8F9-9^(S-38;S>zd_y;AZ4j z;6`vacP~SdB5xz>Jm@^!JUTqNJOe!ky+pjCyym=>yq|faeGGi^eIdTLd~5v}z+kG^ zU&uewfBvq@-Hf}~0JDIKK-xf$z}_I?pvOVW!P>!jA;cl}A#I^&L+^*qhpC6X4u^!> zg}0%2Q4di|_jK;Py-$AM?f%yXk`Iy}>_(VJ)Ia2Wc<`hmmLSA7$TYhZ*Nr6Yf z+*^~k9fk6Rh3`1tB^E)8{EJqLZx#=fTq>z86)SyR##9#j9(eEn{?~`wA4ba!%G)Xw zDoQK)D_>U8SH)CAs)MT0HO@72wKr-9>-6i|>Mzt+HHbG9G@fnDXku(iY$k7h*i2{% zZrN+~YF+>6^l`Dxrfss_qJ5;pxTCMrp!4%5?N9Ap>Rm0LFMe+9R_d<%qVT1rN3N&3 zSGKq6tL)dRKDoZ?e);~|0mXs(LFK{bA=ROe!MO&bkFg_TR|DzDrsKQ($>+{)4yhV-OL;e+w2`2?>ITTxcd6}-wg;13XXUf85RBL zaZGZ`(`Tt^&tIhH)C)>XOhgPn)e8a*I8~gM7qtm|EY?=JCuF|GZxEB!Os2|-|<^9+AaBYxV8Ue3^mV%_DBr*85B}= zDOPdqd7kRfy$gw0i|Ur?2-QUFAOWCY8asX;-m+*D*TSr!Oo<|teiW5~3ZA*WEfzmrNVWWK|GjG74ED9(%RvQ#P-&?`Qh)hRD7 z^EkZ6FRRhkj{T~H@)HHAAZz`68o42Xvn5AvSQi2S-`vrw6Ol;4DTVIhlaBuo!3jeE z*i`53CJ4Y?>M@)fI-bmIAxkXyb4rFLu)sq*<6##TW4eo6 z*_=98D@FF38?%faT=8}hTfV3Ozu?x&+@uSTV7uueu8{m$r7aL($m ziOVgqgUS5n1OgEK`J|ZuM8>+Ee3!-&fcRjl$bsha%Ep_>RM{u?194-E5^V@(>_K}t zMdc8lFEABBgMD!)DLrsAeO`mZ_EN&5jXtB^Gt&3G07Sv4HTx*eWu7`xsWb&c-#G(M zm>8YeUJw(%plxVuIRzviqCb0)eV$P3zdB`?$A01FC#m|TM5mlu1XikdoNo+wQ3<$svB`wZ9#$K$>#-bLjt7X+@LjdRW4}o7xJbL`5bxG!4 zk7*UI!pW6=(W17e6No z;&bo8fZ!#@#lnS8i6^ET%!=$rh&0Vx%h92Fo~5GilOKn$^a!o2oy=p=VG4T;kYO|U zBb>;5KlAte7YkwRMq{E(>QbHFEdJ)ez4nV|$XIs;YJSx6%;6suy_O%GyY5aXu0J8vMxjpt^x zczG9IW9<^E`=y)DSH?%g(Spl#0B-enWBvUww``)6ue+3e8mQp2d}=SHt)zh8J`PTp zO}dDf6r;>Enkb2Dc1o!U?0-=cJ{7!i_+gA=H=9}tK@?6)l!Y~)Ve3B$iP@bL5iykO z8#8)e{h;p?=_rfsV~sbux#aKQp!}qEvsd`w{?Kb^>rBl3LHU+<2Y< za8G6(lg<)=)tglV1N`rewHPS>C%^Ou?eKWfqd_1;HF_gJ=~B07bSB4=&QH~SSKL0f z{aDWpLDlH^+U2TBoS$@F|GOC-;fails(8$gHm8;v;SMMyK_sFs>U!Yp5&N+^R{k0W z5m{2zL_Xv8)kfbb?Q^_=GFp=B_En|#6UA`8$lDM;^JQ<$B@=g_RRKklpsw0H&mfiA zAK+%kYiX5uv=o&M8@ezyXiq@ff+2kKd>?z8ut>k|@8^qn2pXGjH%(aDFNFjtWpz(|9YY3qZYX z5U94R4G~-HUBD5Mjd^%)ChLgohM5gwrjsw2Kc^cOtH8S<{a$#p`Q5u4z5^As-wdzs zUh-Fo9l%Ql+FK9FY}}dE!lt>vdNr=cEVn7;=-=CSJXZX;UzUQG#EGgXVmu!=hM;#k zXC$z;i%471$`j4&iLFX`9XqT0gSw-+CnkwXqZ_^G3m&F)(_J+O>uX1FEd#yEV;TH1 z3hO_1$KAxrnRF@A|1U=e{O>K&nvmwDgialJ?LOGur=gMtNwLlcHlrY}ikv$n7{x ze_~=mrp{pbMzTzTn~$a;(Pzw?81hYXk-7kf(Dntycv>qn0)5}rX+i!WNt%n)2mJTJ z4aBjT{LpfRX|48zcw8VAlAV}__z5ttL46C0IhO8F5nWN?!&J8{Qm{{7EXglV_+nw! zZlX)MgrK|BcgDlY%bZd&S3wcQ6tQoIwMQ1O1}`;NESlC=G#NbSl}}pQ z=Vd#nypt)4Ys~pMi8C}FOs^Awuj6>8JMZpJ_HToJ+UD^=LA%l8bh(0T7q-NRsuGW1 z>{QiuNDZ>NCOuv)M03JComy|6#g=j1O?lzgS4Lc+RAb??zYbbhl<60meCIdof{>0L zw!`^#RR+h;Zw>wWVZh<@$TAT2QefWBw(&QDUVUF&;jIWeazHBEIDDTZk1l%XFz z#9?$f)hzV}8Q^HCb2s4Ex>2Fvt^n!T>L`(rz}yEjvZRk<7>(6hfiw3^zv=s2OI@?c zvPnx~$ar{@so&_?W)oLN?o$7Fdn=bJTCM_fMS?lhbflSoHPIKm?ek~#gfJN<&+1}c7Gs{hBV6eZP6C-l| z<$uLAEcIY2gW=+coceBAArgsnM`l-)*E|>+;-l?k&}HPk zD#-w8B^oNoxkoNkYTj9YfaBelJJ5O%oz~NRM1LYg^e(44WDGC2qQW%HH>#{t^4)pD zuA4(UD+zUj<$wpvPKR#{pA+$oEXY4&-yxu2*L$6%LRZOWtS5OHOQ z1=#env54XyU+b;9cU*C}hG>fc>PBk5A4Ca80|5x8Vx+)_n)(qWa#K7{(u%j%EK@E1 z>~;7S=cA4L;}*LlZ|bl`E{;g=kdQE>ixUGb0@YHfM;TA%g(qn z<5%ivrIXSR3tRE~a{K93jnyjrQDo^0-xhQ{*BcPEy^@P8iZ|n=j>byNV^D29Hiy6J z%5Dyo;%D=}TQ95lof8Ppm6?Q|Fc|Be328@cQ`HfG_wfV(|E%X0mG2A-0eFJ!KY8d$ z0Cr0)SDfj-gXakegRvIy?<(U?z=mom0cca53u8J6|2k3W?X*T&aAZEnoTlgKc5&pz z_ZW*4n0G~ByI!r0_yVawV(HjNR-7}@w#_G{ljwNA3?#eBh(EiP#a4+#jpbA$9n%Ac zXKI1tw|uTb)#0pVFJ!jvWl~k9jv0-F8mK;MWOo+`2@^D~GNd*H8V*OFRM?<%l&q&cv6Hy8X`iR* z0r+|XkfBP6b3*SJVVn~D5D1-xx1xI+vK!(^52s;#N|A11b=cBzJ2w!pwUQUb?k&Ayet+KwMD!(N@9mEOSx9CsSlzR4Y$jVw9jMN3~h z$-=X{sZOS)r9a)zSviK6;*@~L_}Ew4SXx;S|Ppf-I0 ze^Q1u0cTKazWK=GrRqjHD4lbW!O?NI+mz{%1lE2>8qefuw3|5EV%*F*9ahuIMb^}} zbwRH(O{F2{+KHP4o=%l&5C8Rd`<57>SX{Qh!pemU?~rCAuHC;8xBeE)rv53K8M`>2 zct|ou0KRJz00N-DR2p?(>_LoBwyhS!Rmi`oaQ?-fvJZhGodI=SDFssoSqJv^CnA`{ z1?orPJX3*N<`{U??zB;dJks9Pk39>k|7O^|GH8MRg^7i!f~QO)N`QR z(KA*HTp+sO5dm;xzo=u0X^F>~9vnrMJybTZxA&xKlgJ7_Nb1Sg-S^t6mga8^;Y{NV zpCf`R4n=gfRP+C=%5PKQnQ~E~OOi{gs~X}Td2Ny+TB4lPadtx0XEnZEooWccp#Bt1b=T z+%VT?H|`f=tKBw47CeeLOA^xFj<5EOS^C{Ir_=M!XSXUmYjAt}7LU~|^GtZ3GMY(l zwpx6%f1zsw_9oOB%^X=pO@poJ2&Zx@dg0IhpK^@p)_4H;Vou%?Yz5kS1&yUrW%M{AiE@6Y#%zBQr8&9P;*P-F9|4yLTkjCcv zz0ujF!)N{Ap<1?vXTjai>aeNiDp@cB)^fX;CX~(Ca;DbyrJIT@ZCo}OvL|nd3bQHJ zMf9ew_hl?Tv(;@c#+=w3%V5_QysOZ6QZT+2NT*K{#afhUSHzMw?WMRW?W>I$f-bzz zuA8h(ozgFxK%o0tAT2A*Ap{^oBnvNIS?PIimUtIwWAJTvT51*afsZ!D#;YizD1;>) z6~rPQz~PCO%}A@Q6PE*)w+M|vEk^$T&RPFQw(v95DPSK#hD|uW5Sno=uRni8@W{NQ z1zmY4xS@RFwrNARk`$QMKCv8KP@6i$zNS~gWzj0e;wNn36c_iiSrc4|3Y7#P=UEXw z0kA$t06GWY9WAWkO5p>RMjfxDY@(h_&0@K}jOk|XQwvF1Hy)+5`*OkFl%2EkD%m#j zTyoIG+u^E40yX#FVxt$f*t$HK?``cSMmM`N&3d$aXs)V%HA7L5Y|JspouKfeCPBG6 z;3Q9X0(zKr1J%x9i5k@Z)`EtqV(V4s6U0xh5P-=sutX!LYBCoS6e8RwNOZ>*VeN$H7w=x#$`0t+!10Cx-BnHDcLL8HG(^j;oX?wNAIOg$g`GZ$Fi=~ ztEraU`UkuCH_fBQb&Svlk9G~iZ4hp3iQh|e8Z5Nl>HL&ZxJ@<{_<1?uRhOknK!AYo zm)@hFF+y*oGtphR2oKacFNy%<`HX4a{HN%bxSCuj=YAxZQ=jJ5|EjWB3p5=O^hiK?#5|-<4n| z=N{@R95QcqEu0#ootSrMGZA1J*4fnZeA2wvdE8v^eK+Ibs_ObGrhcV$%u+DAlc&wH{`hU>@S!FVDgRMzY;=Dc6atk*hoBS(P{iT-BXz=}bb#VXbRGt^kvEqJTk~~RDprxKt7nVPjHei1EjQ$x z$@BT3ESHqjqo|jv(Lp-M*i*mZ?#0yd!82yvv$X1hM5HPOQuf?D)6PvD#++_Z4Y^0! z7UKGc?%g%{qqcGMXR|qKJ1LuM(jsW9-iPWLzpi04f}|#m=U5 zZwuT-v`b8!B?m+)B>goxG9;1U+4jZ;wwdnuV5hUZScs~L(*RfeA5s$Wc6II_9~W#F@4BkN_#QV(abzP zy}9KWf!*o!?x&7X;Rsd2aF{gc3D1V5d-F>1oJaoh(eGk=xo3Jc5HPznwyw1xvLQZp zsTr$|PT$hLAJOh4)|A^$@A0hs?KS70L5W1gLx=_UC$2O5N2rf2E9Z8XHpT%OtJdV+ydUw3Hv5jxGm3Ta9ze@-1 zW%xfwfOT7xsLyiC_%<*$Ju(;blOb~lQxGC>LxVZvzpm2$vBL!}0SB%3mo5!C98-=x z0hi!_b*9f)7>2f#zBODbME6c@{Vnm;+yq(CzBYkYz(-H^FbK>RoE~36Ef|&B#V1aRvEHT^YoxQD=_r>k*GExnw`=*RrgC| zL3*K|F6%I2?FAT3xTv<(BAA^M7hjock0|Tp1m^7b^^Ipt9qnFCghc`e$BU1)e+0amGb`WhR}CctdM_V|<*>KEtSkEGt;HH-|ybY;C^8&iL zLzig3mVYr&+lH|Qy+ZV+Uh7SEm^XcR(~}h6S14W>f=Id< zBU+pqIy0`kM~0Sc%l?{Z5;NUf*6#C%KFnRyv~}(6^M+nixGnDG z-6iv8y%fF@jS~#M8!U0Mrvrk3oaK{WI9l|ll4C=ha+MpEV250|pw*<9BAfXLYnoBL z&4-eX1PQ(uFETxote^oPgitB3fz z-)1N7ED7)9z0m{T&bbjFly6RwYX^^RdbS?!wWosv~$Cd||j^5ViGA z6$DMps$1rBUuPe+xJ}ayx2Ky&HVbyXQ|HPI?XJ=-zQeQC{V>Ro$n&Jgu`oId*)cQ;t0uK~zN&-d zaOAv^Y4EDGGbQE6vO)7Jzn0~40>E>4agQC>KUIdkvb(-(bNnk21Y27D$KSAqg@I-J z<>h0_(%CCEbe_4f%~FDPO}hH~Ulm$*j+L&O zqAXvCKm%0uz*VKG_z#{{wm;AwuU@0NPuoHOhU(m2XB&XGi9#&k8wTLtREVZ&<@=W5 zvSNRWv-QJw9xv3!s6R`VBbG{9QRiv2!86pfW@e!yom&n@vT)afv*J9OJLhd^W|q0Y z&~*9aG|6ZMQ#$E26;8B7T%-E@XLIAR^~#=%A_X=w58?{G%bzK|!?&-f9nvp*#C9`e zl-CY5eAqL>o%6h}y36l8``dF7=)7j)UGQiZ0biOmgIV!H(RQrWNrSTbe8!q5#ma~A zP}|f!PpYg(erseKNbYk5{ob_aU*_$G`;jmwkKW`pqI75Mvl{Sknb`SMe&NXCqw#VXIRU~2@zoa?qY|_p6#DYae8%26nk7HI|hsGMsyTT`gCB_p236c_m-I7Ov4x>Ua#@C~5ChD#`dt0r!tmovumW)@FuP$6uFQ>KVgB zQ7HnJuHoR7=Ba52fQDH-0SMCrGZ3@XM0D<4UsB=sUzSD@y9QzUtY*4=?dKEJe2R(a zq|T6Dj1RZOBKGGonJo*maI8)zg3RBBR3-17Yp{D7b4{dxY0Y(K@!Xon{M3wJQh2iD zX|-zlC3~$WRI5YfG4vZVJOl1H+~L@Jt+CQ&Xhm$J>1c22-jdVA2pC%YH}^$9woEIf zBa;OKk6vhCqMI2vbgp#(F_;28 zeQ+WHV9ELD`vdilI!&Wn*2~JkcSUG?gD>XH&?be*ckv1S;peOmJxXd+oLE0e_el?o z4WrPRE2y2tMI)TR9s++JJjCh|I4pJ;jMSQRz)alucHM;WO`CrrgYBEq1VBXvJha+8 zjS0XagN3*Y_V3+XsZ*QOi(Px~AJ&tiHEHEJH?11!+}&Q>(9;7PKXY%xiOmgl|6@=1 N?>yyS+aZMU{|8A0VY&bS diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip deleted file mode 100644 index 17aedace14faf8f2990df3232565328901209d5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71160 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 - - - - Template: White (2014-02-28 09:41) - M6.2.2-1878-1 - - diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier deleted file mode 100644 index ddb18f01..00000000 --- a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier +++ /dev/null @@ -1 +0,0 @@ -F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA \ No newline at end of file diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist deleted file mode 100644 index 74bc69317de4fc4ae87da8c71d1615385d70d1f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmYc)$jK}&F)+B!$i&RT%Er#Y$;HjX%NJ3UT9#RynV%Pylb@WJlNytfpIn-onpYAU z>gf_)mRbao1G6)WeM@snG6NFRQ{x2$(=u~X-SUfa6HCG%Y9fm>5{ptnD&qyz4Xmup z3`|U&4UCL+jhsv!bxoX{O?55Y%*}M23@scDT}@4m%q)yTQ}g2eeBuRE+{`RpEuCE~ zbzNQE40TP6fZ8lw98GkADjm(;Tn!D4oE(A5h%u8h)KJez&wxln88{fk859`Q8B7=) l75HPbcg8&-~3o|P_8#_BY8yg!t2RA1> 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

2KUY7yz-7_`p(lc`HgEPC5(QDJ#Lr#t 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 Y>c{6t4Sw{%j~@8Z1FJo-=6lco0p?d?5&!@I diff --git a/3rd/libuv-1.19.2/docs/src/static/favicon.ico b/3rd/libuv-1.19.2/docs/src/static/favicon.ico deleted file mode 100644 index 2c40694cd282ff3d0db2c495c23f3beca40c17fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 zcmeI3J!oE47{^bE(6L>dlR?3;f?AMDoTP|gC(+GON^N!X18j$O66~NjsaQd=(xSMC zL)z#dI2x#nOSZwR!m3x7+NM_xVsKV)SFb<|EpaeeASlj(+q}%U2&yoPD*;Lm&Ey_UhK~ z_4og5Xr+DRP_sk!#l?%;Y8ZWV*^pfGuZHnl8XJu9Yiq#y(Ek|pp24Oo_K^744vEX% z&VG-&+OikQSk~Z?A1-gL|EIsK{O26#L%+nJ84qMmd3jchtG#hWC&Nw%vpc1cK(nJjju2B;@Lx= zdb$)`edHiu4|NQ8|RdXF;=Y~_aQds zM-KRv4+sy(@ZfC92gKI6;H2E;6K(qX-UX~%j0>mIj{8FYL$I_j$2@PzKi(Uqj$`zO z#4L5N(?>*Nx>uvT*8k+fg{fl8rQ8qrD`mB~$cC=BvHB2S^BB zo_6@a7e4Xb##oy-YQyg-4(0Y@Zd<>ncpwkI?I z#(nm2&Rk}dLs#8nOwJ%bGaw_^Z@yn{`_@$KJMZd%`rc^{L%16&qPZZ8yy&yXqHe8E zp4v^DL$+J0`R4$#?Y4)|~%PII2w6MbC!=E%c&^QfI|YuvXc=!{*1Y4?qsL2`h* z$o-C7&RrON*x$_I{LppiJ7@Zwgz&bZi%;^2d%G)#^1eckdtnIwS=8R#;7=cfx8p9} zQLZlb%I^mM$iuvbtO1gd?cjn{}^(OGIzMtu55|%vU*fmf#WDj|cBmZ3E&ULE z^DEBxoq?V3_c`Snao@w)J2O5Htv$MtTiLJ8Ps<-ZzF*?kddj;CIdjfw6M5D+I$xWc zhQGY!fnWQebuQ(MwWVLXOObWGTVP`@;#mIJ;fE&YSX18%)QRXmF?Jtf*EjFnSpH>g zJddJ&XMw)QMPI~mOn)r@Xj{7voZk&B*MxEA-}y5>b8-Dk``zH!=QGwGJ^1uJznGg9 z|1$TION}?{8}*_O`a|A9*KPP*J_HMHIpwG&wQL$C-RQE%*QsQ_U2XFL*_t?GB)|p zoTFdrz*D)r%G#KV^AR(r&U;7R5&a!b^kMysGZx8@XQ0nP@+p19c=pHC-WnK_JFI=lYsh%FxQ85$b^U(; zyvsXi2xoM5o45Q$;<>lsOiqr6az+ok?5p#43dY+lgu~eV!XCTR_3p~Qe5cL4mf+UW zmb(1x$@eO7H!864g(1E`#3$lv{^Anj&Bm9F=&$E59)YX*%ShmI{=yP?CV$TeB#Hb_ z`=8LKQ_5!f8%mqFnE#H7@%+D--L>Nu^WRyOxXOI~8?33Y;%}S(z@z1r`L%pA%3o~Y ik^kAsb9poGOsuT~U&vzKIyJc*jGI?B>sZ!zWBd=1T7Db= diff --git a/3rd/libuv-1.19.2/docs/src/static/logo.png b/3rd/libuv-1.19.2/docs/src/static/logo.png deleted file mode 100644 index eaf1eee577b6774c345d5e21be51130a23b16627..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33545 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 W3*P8um*8Y!7&$3rXpMwP!2bZAf*ghb diff --git a/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png b/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png deleted file mode 100644 index e769cf338b4456ea688b0abf888b646a4253e0eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80528 zcmc$^^;;WJ*EWh3*V5uvoECSd6o(e6;qLA(fl{mlD-t|7rFbcY;_eWvxCeKFCImR) z`Ofpc-*x_h^TT8&bM4uC&ziN@TKm557;Q}zB77QrG&D3KHC4s;XlNLyYm7}?Y}6f> z1o~1mG<WDWV{)Vy)v(nVHxwXaewaLD?L#>(@x!bkbJ!c*ONz7sjtk`JyO8-QqL)a;|Fj79$^->Ey zU=3ZQatTHX2vX$Z6;v=od#atTO1ED%52l0IH}h%q$EaI`bAip;E17KTg+Q!)qja`4 z+rl6m>(-BInP^+roKsUb*>BPKpJkYi?6BuM#Rw`rqdty-VW8or^hmUL5XZtL>~hik zN^Cd3Va2Ffl#tD)+i&d-*dWg8KEN#mUZr%uTaWg83%U4B7|%}`TJ4&qgwCe#oMD%A zR7rPqq(8H52XCKWWeE9jCo>Rm`{|7R5Rxko%++6YI;`Mpr9iu4HOQi`YfJrv_S+fz z_11cY)(I0D>)FC;J&+NQS(Sjo+v>VlM23%#(6j(4>UE~5Vf)5Ny1@H&j zTI?#5sy!0~1MYVaj08sCT-M*pGk@5=B22LIU@PFJE?oWU)QRyl5yvYJUpS1HAA{SB zh%Qvf4ReJF?Q5tiDP|fbuPTQ9Yph@LvU4aG6qrNz33qTqn+^*Y$I|>F>V|EErQ1Q| zMnD*<@)|#~Q-dFUCCnc8%PHye0{Neb6h$N%Z)Qko4RHMxcoJkn_4n6oQSvtm)Inf;2pV0XlDLP!0uHiLBzvtOF zlpTxf>Wvh##0_1P>$In6+!3Z-$+)iva4{#8^>As=6yGH3v7(c`a735i6OzZtjZ^|*yYE=wY59U)z z76P4vpo5jkm}$m-Ey4r`9yT1G|H{!@R@oKi={?hM?(zMY~(|n=<3HOOmXS!q#W^QHf2>1WCGa#tPGT1WM zsW;(I%{U(UXv0<)E0JGWbyUhTAzQRuE>mgwqfXDZP_u4~-1s}Mp_qJwQNst{H(DBe zdVHqUIw$$EI^arhQM*dJAz-LuoN2)@ISJH-Sx(?GawX) zBaowZO09G?M}LfKjA*QofROT(a+-(AW5RvCkgSd}{b?~3YH)xUc{dxk z_n$y|eiXBj2Pc ztI;$C#v7!9PlPm{2%+(FgeMg*w{Qjfp?~8izYsrPEFKFbMTMSb)r5h`0hQP|3JnTh zcaG|?-tfl4&D{93V9u?7$6 zjF4?#Y-Vn{4AT#u58j4|*ogRg+qU`KMJ52H!Q+-}_uY&gnU=wF;|Uv&mdp~qqN z;>a>QqiX>STx&a4$~*U(FRfQ}LkzTp5zir&-;H1{<+6-2fq3bNLw(0lgWKLC0)yi-fsM_T0uSeNp>n-vVsNA+n!dNOeC%E+}@-A+Mp*c6r^f1JJ zul~fjbCp{7D~sfCX)cf^_oqh*>%`GO{Ow@=C0#V{6w(Q^R!)E~^G8r5^=qlQIBv4Qz!kOP9OWW=iC(ff5&({ z<)9uJ$9t#zpF#i6eHwf?;s5oQ1NDg4n`E;89k&KmQs7?DV$iV_9Dn_SSAa=Q-=e86_d4uPh;yX%42 z_Sklz4x4mv`=V=mtA4;O5dYC|_CfCK{O`byZCe--d+b68|0YNeRS|GTJ5Sy#F%d=FxB4pR zdr0yUMr66R{jDcwVc>Yq+Wj5}s|!(>>+$$PeyY9PXTv-FwlDsG4P9Hko%$f6DZc?^ zstWmlljZTWr7avBp0d!Mc!FGWu9hFIbct?Xk=| z|Jag|_irAp)MTo^5Za+gPkGkzr2g;OMhc^rO-ti6qmr34urF2viH#|DVmW!Q^4PXL zO2H7*=D9Fd6E?$5lL7lBd3#WZGSOa>bB`$b-NqAF!6TLBqPsZMYPbu2h-|y4e?cnM zvP;S7my}>SOF=26yt!cY9`Gzo)ahya6WiYl{4~=${Q+!80IW&v-G@N&-y&;q?2IreAzN!#Z_@GHwKbxA7Ja^a`CcIR}I$6=5ET_QD!CV3#J<~xcN+uQ;Vxe$(V8Td5LYdSL?2a4-AIay@b{$ z&oNA`wm&Y{_G_12jpIcptS_3wVst;Mw#m~<2|wmei+3mO>!Pe92gWOdM6Rn|z7kS} zXjObb+%kpT5ltxW9z)`bY$t{0)+D$TnhKmh`7G)st0DJ z&&y5E3&=>f=&+bc0Q-D?qDmWLtI^*e>aud@ATTqp_ic>(-iayJ@k+ZAH4U+ZwEJE6&WUJ?3L?4eF=54NkkGh6T z8F~NvWGO^cA4CZD9FtJWZJ+aYi`!dIfH|)lv=KM#Js@V=UH&XMls}ntNp>9O8(Kz% z#Zj#gSn~Ed3Ba#zJJT`KJAX(muAWYC`Q}KHNq-)ghY+cnyAuQ@w&(O6@$5-b%nQPs20h%5~ed z$U#M2{3mX&hGic|m&Wx-53q$qGm?N)H;gxDp!y>PuJT{r2MqjAc^VwBSE+(!I%HCp6eRbZrUzvy9QU5Bl;BFd+MAz2(dmK78Po~^^^{t($S*1^v5h+I^Q03 zOw+Rn(T(8NP5HzaupU7vT3*%UP*y6~*B=xY-v6sp?g6gVVp)d{O>O4^oV|(xBDufG zTASJzr)J)wY)`OPcdaDN8OYs!87plg?l(4L5_t5O%WCzWH2;CIkY1J=+#3M6yOmDu zn6d*F_O||NDVUSJKFl9N&dhcz3Y96EiIV=1vN``f1vHm@4Mz~Y;;4jwZB5*p)J^cv z|5IMw*5tn}1fHk!8kZmKX1J<}wBKVyuHjglF;|Mr=oR{3)q#ygo0g#r*P$Yx$DUHb z&4X!WIQuX>vRs<%&zojjs}A33k0Fb9z<`i*lO+&Z5`CS{S@TArEFAjHI&^m#so$O_qmWZyAyV8WA%ipa`6gH{-L{u33tp=|k)?8Xd$q9k zbs|^0G?Rcmn3J1a2x?3*vG^8wD8oe_jtC=SJSvk&bk1xu4pFpS(@pF+CJqI9kc{V> zIALFAaH;#=We33qiLy94u`r_%-^Zj@;bYqZ3H~E`_q9l!_HC__d+1(&V+^uBj6W%; z4?>JuQ6t1-8N-B3W;iyJUs?DfsS|hk-4TV{NKRL(Zyz`ij(5ydA<^x3SBtcwN+wB;%!fZ!HUg%dq>~kY}-}+D0%MbS6JUz2T%Y8w3RM| zPlDQ}D;ib;EXDg_(>HO?CH<(T`LS=lKzsQ@-0L3hZ^h1)ZOF%DZx6Roui;aN3d_Q- zDBO>B=C(8XBHt`}MS%g9xZQdZ>?$z8+m3_@c7&ij%2iWhE9J`>Y?#l~qmbK7HDvm_ zhg{2P<)%+eG{LWjWhhwoa{9wC(_MwFOgVhSR`vrhvI!{wc)A>Xy-W-1K|?11mZs{O z_#gf?SEz`Lw%5U?Q|`lmRWTlPQOL-1okpZPGMY5Prg_di78 z(%@Z57{5d|1?VFUek=ie#CHLAP9TFchcP~$TXNG2;iw)|SxvaNcT!M7qO>B&30ZuB zNrE}Qd?JhZBn~G=z-%Pj#wW9d+vl8Iv z$^<8|rbr8F?X?ebZ8m0qF9lnJPi z=GA?pq^Hx}+$$Y0b|0EXc#CjMa?oe*QAeuu59Vpv(m~IJ24wej5**UgZ0tMzR>t*9 z`=i(5>c+sGBkw$Rdti0IjuA9vba(Mf0scA0vxfFNXKudBBq0D-AQ=@Z@fAB| zlZCFkAOGFqeU?BshWr;^3T_B2*%Nr*q0shB-{y0gvClkgn+L2xsO1k%NS-@^xcm!U^l(Sc+aCJ2r8TS{i$W8a7`q?z}8QAM) zBzG)-bEgS`HFrabm@nP05y9QW>T@w-hXC%>nv6tyKmWe+grw6=4!OVUOx)I|mV`B( zbr2aqXuMO8K(6K zS{5ZV_|1wZ_m8Z-USwRq_Ba(16@YZoWah-aaBI?YDr3~?F0nvkwb^u`w(xfvIjV8V zeT`?xSHRzRqAy+A;Dtl8L@p*3-T`nQqf!~W^^EjjH3jqW-0v@bY8l$9TsGf0yOZ%= zIt(qkjK&5alDc1%x454xm&Ce@wDYTk9HVAR$rsM%+9=-UW=3v09TQ?TN1i97i4VTe z^R$f&lOa3&X-h;$U2On%d)xgkVuZ>p#Y+O)q@=yjCFip)op*282N2;I6;{Qi5N!vD zaaU%GOY4Qh+v*u#?JWW{8%3|8-Zr8w$8YBSw31Xa?j>aQDHB>jAh7sVA{ArV{io0R z*4(ls*3yAyr$PteXE+Rp@_QcK_WYQIAt}imBD|4>tA1tf@8QY$$s$zj$)ATV7*KnV zfCT#zaShxX3L76E?KX7pR%+@56CRd?-+oiw0{j`2NZw%43IRQsGUb+9c%1F7&)zMZ zF{jld=*xh?FZ1)%Ox|bIupTl9_Ukqb@uS~U>KW3`Nf`t)ZP2qpCHu`NVYd<`$wriM zRwD#)2VVjAqgpYEor=h;iB!IU33l#r`9Z5C5Wy%I;Rg5Ujk2@B?z%3xm0oZ-H-QpHD zeHRCU1(fFkIg)^`A?1ur+a)V|8p32H2cNA;?R4W7p#}zKGh4R$a3O*lqoitXK}4}m zyr0%Al;b?($cf23i@BJ#m0!^P!&_^nL)MW8tF24a#aXd_><;S0l_(=fnR8S zv6tb$Y`eTHGudjJLx8q&nDKGJK^QTz@qSaR6{{E1plafer9eF)mQK(MacF_;^_L7R z!l!h8Ve)jL8a)FE2=4kdqg>9gBt~1g#O~f8-0uDxOXWAzWoJnn{alz^%*HwHk@>PL z-uFEjkpb^Fymrqc@Q?Sj00D4=F7eHGV(&NJX*dK;$02k$5X~3wY<29M`MK3;%BG~S zJcKMyYDQ9QsL>@krSy>|r!AaM?>QZfHp^a-P-Ck~YPBVRTm!r_E7m<-&@prO6ug6! z?dERM+0VqW*`U-|`hrY!)^Sn&0QOy6&%29KIUXElctofvMqX67gW14`S-*3p!)cki zX95iLmlBHK?lA7b^3(l{)AcERkvL-)+#G__pt9gLn#6>PJ(XNUNih(nZ46W(DQ&Z7F6`!GG?~_ow|;7)Irr9~ z#a;Wd^NW7T0L$nf3%FnnTvk%4ovbqz?ay0eV7EZVAG4TeuJq9JeiGh`Rd$ z5k$Ym7Z;K@seC|{tyL+^+r8IFacuFeLRn?JsXa;Syon5U+WqvB9VS-mLON;L2P+n4 z4czTw*^ee5*{Su-ZV9wQxsHDb!X+o}%}V`-%NavZc*fj~J$#g4sEtgP%=!aosp<^; ze7>y3fKeump^>DdtOBmE^$+0K@*oKyKHLB+&(BdWzfF_d zMxg-z1++{(B*mp9I-=U0xAG%E?WJ#SU$t4KYvwEM`o+?5-VmxsxnO_kd;Z zKblO9FDqoV7bg9V+#gkj@1PH;Bv9iKKfqB{$|qSNVIHf-`_m}76!d%dgg_(sn{Ge5 z7K_YH@-5u+2=rUrJSt-yPzL_cC^re%K2r=F`b8>`cYmHzR%B~xGFEv^eeJ&Y;T%XqEW=AYSS4&Bn&LK#RhGDep{E|SJvw!vyp zQG)Y2GnraoKwK9?f^WlJdn&n4m|4r%zdl5bAApS=wp7T^-{5ic(gH_iv=AW8y6>%L z-F!ivF0LAV38!pXd$QFdRZ=sr+P^3}wG#BHV-}AtD>l}CZzmfa`y=uAI;|hJSR1=p zNmxUm&rjFi6Uqd;7I|i&{I3PYVOKzgTWawiQDYCuV5AkiR0Sr$H)%UwGQy3Mr@%nB zH%tph$Dz~KWML(e9ki0eY(AOi99SF7S3d;W`g8-5SOF^^C1gmuqZK93tPj((*%NI>B2Z^0wCmop{Uwt+xZV z_9I>Sh=b0*$gweA2vrU6LtX~H7k@y<{I(Nnn~HF&7O+Z($K0A#gzr%w7i^pMYkh8? z8Fm9Oxg{ixZRXu`I;07bQ3Z!@#Kno7m5ECU?tS#i_*DY6rpc-g#%7AY+ah>^jXfr4 zc4{5a=F>tgWDWU+p>p<%u46&mb*HFbr@7@w@br%a;nTKD+ws2FX5VsxGKhD0GKmrn zkvo7VRA_Eq+dYNDf|y&@Xq)^jD>F%3o^P>3hWgirve@J2aob$h5?`RcOwEjY8d|C1 zcM41{O!3S7d%`}a^h1vgUh5eQBd!l#RCI*nR4=LCQ|Y!$)D;(kxm~kSI8iDXs>`2Hs<`KjeOH&;X`o+ z1Dd@V)n3fTK-T>P9gaxyJ*yyB(wl#-A-YckkZI?O$6g=W76;-Ob9^&h)XTuQBN!Nj zXf5>3)Cv8dFfz(J=ySFqZ+Kua+-p_u%957w|ZcrY0gWW8vY za`3-@I6bIvTP}rIgg{_$6|5oE|K%mvJ{TyLHp*{d^xeK(0~U}Fio<&eOZ>?eU^?{h12B5As}1G zUUbP1*8tvG0Q-qtdddGh>?Km`S^bIu$7*9={(UYoV_J;Fj+@UMY9k0ZpeegIA2S_+ z$|UKo(z<_V4=Hqhx$(lsg1me0XLu}&P}P1skBVn zqQ1+QfGNje7TCorxm|djL~4`4s(E?)Wo4P)+w1$;J)6e%N0|RV_~D8s&li3Z9LlXG zWb2IWwHTOUV`0b;R5%Nt-P3x;kcI?b6mdM~+z%AwzB~ya4*2v?b&UR{Muq_Or)@ zDw*taguszrv~OxF=OUS_%kMa|{!5t{rv+h!&FLt$=gjyq{Sz#cdx(vq$r7b=%;@1e za}3n{KKt-!w1;aqJIA#Je_Av`10zBkV_ssX`nUh-l{?_JZ1F?nE$t&petS=3y+@6N z9~g*zM*k8X;!LHOf%}=qG%EGo-4ik3H;p)5`p>*)w3ks*{Lgk1)8Bz@i~UXLRg8Py zdSYakV)Ug-5Q>m-2meYzM~{oJ<1FeVMN@ZWuAw3w=S<{{WVT8Z`id&0gs`00rKE7J zN` zyVjP5E7bl=gpPYYGCLAQ8D{^z!!Q15CGl%P$M65;LNDkZcO=C2?CJl#L->f75stNv zWd0BTDf7rc%pFNfI|}X=zh&kR zd>l7W&sG!FTKffQT!b*`OE)8Yj!qiI2z z##jdqzS$0jy^4#-5BU1)mnZIHl@{fqOu-xV{Nr^4a0rBLLwXXbCl zCF}*hIdlsZ^U;p%56=-}Z3xU#Gz;KVP zkuL+R@33qb!cb0F@Zxp9k{*pzp7p(e z3gn7273-Mly^2_MD?REq{Wb0%pc~Lf%SW1@Un%Ld@ z0i+rh0vA2knAhg%Tw`=nX!+uMLc>-&z2RhK|GV+sri-nqK08w*)N3i`iQ$gyQ9qF) zkYvNw<6Y?sHpIb@dTO=Hy*ckr#Y@H_S06v}cvF-_PS+r^1Jh)(=th2E%hkJC8hnLaOF{Wfe7+ z6vk$uDd!qlRP6l#i;L)m0O0_RWmp3Ph}A>li&UZuFAHh~Q8kM%>KI?m%@oM}smmBI z%|6UnBY%e=tnxxdv6@}nk-x<_l4Me>D};@9yTnB_q#x&r@qfzoy_$Mnt*MKAyZ?c4 zNc~QjhMNRlqJg#j6yuK?h?d{Yz4mB&D-PnxqY@xgT&?q^wj)-VS7F+hy*s93nl$}` z5WW|?7n87yB&*S)AZC!%3;RuP_@dRKUtO_QR9|s^hXEh3)TV<3&)ak z%*U#6o2;7H9g%ucFT3~N1sGusGEU?6w8_s)ltcAPmM$cOFYLe#zZHf)Yy zL>FmbmBe>gh&|g?JOrjk+SXW6bczv`TSZxwVlo0+HkH0Hip^e@@#*p^0avP##z@>b zUZ_X-QQYJ|=UQF?h-ZqficA?YW1QpNep26?IG0HButAm@JrKj8V$B6LlfFl^BiQ+0 zbPmCpkMabgzc-DiG5D7ycdcXAsKtnAhXx3DgdL+ksY5n@&SwD$E2?b~;fuVS{jH1m z%@`M96dC=aM2;+-4kOlCIZQK*0E*@aX2ZE=8UL}E9VGS4>LQEb<6lW4`2NVJU?3(T z$I2#u0k^L)n2-ZQC=3lkO9@#+F`UAGZ2NpH4TVlb@2&ic1oY=c{|@e3a*wBZ*mO3d zmPEQVMy$1R7&as#sbf)yNROqnV3CU|Z3r|JrEGH1F!;My#pHsII5_Uf(0Z8YDN5BO z6ceh9q5M+$jZAm{`9N=n;VlnkP_{6_k-n?sQ_2^U>dV5~L?MEL98~92Vfu{zhn)Kv zSg{T*If}G#(s$uMAYRo%1U_psLiWt#j#zdY(zaB1Vk>@@2f7&EfpvsQ39G|?_9@9Y zaY5cJTJxeSA1{*XPu8DAyfQ|me_%pK#Te%t`ndS=Iz$rb7q=>2_Ah3ASBwE4b#*2{ zch?7b9&AI_@vY%S%@>bi4Xl6|H0MwseOf$dJ<++Y@=L~rzH<1Gs;vR|>OT`DJG$V& zIKmxi%Fj#c$nrpHEL?5y4Aisa=R-lfod4+eb%RR)`i8waJJR-5w+yx;(`0$Z zHrAPL#&5PbtTbA>#&<%0d2f{1*{yZ1MUC^c~WsPW>o zlrb|uJ(it9eUe$gAHK36`%M)9{VGM&+f9`Rr-P{yJ(ocrHkcZDSOi)68TAuMbZn6s zENJQHXA$Bw4i^divGn)>(7`{&^CyUDJi3fjGBI1KXq3yor9fZ!qTEF!wp26z_RU+4 zKUusXAVQe2J4)XrkT5?!tH;Eb_Cjxe*yqz~1R;qKhLCLGYn<0nMZL!d4BHksqNlw-c-6>@s2ni+S;)=#FAz>qQuss^kdn$Q%$OhX6#B5R7NAR|~a= z&cms6qdowh84~hK-J6F**BvJ-bl67B|2U{_4?$;JNI4>EcYgcR4W$#2pTJ?Xp-A^$ zS4Y)eQW!!GoZ|!1e4Qe4QZ#lKo-CV#u7L^yn);VTNpb^-wG0i?rAx15c_tb>clH;5 zC?{XMZH@`C1{(S3`ZH}q`pm~#GYF*Wl9c+JCdIN z8frl=)0Q*0Yl&k9#SYrA%r@U(ZoeW=_^=X0NUnRpiD_Ee;vTv4Q+Cb*=-&Iw04$&P zC{)QRjFD+QTHaAxEtuxrnHIx-6qS8S91ffQwMm)v4b z5Qk6j@eTbsE6_xRoB#JT(~`kYp(%4Y4Ff((V4m5&=^t4yMN#(K>6Y;s+M-XMhGo3Y z+lj;=ii;nd$9fpY4arJ2oidoY;cYvceALwh{C|EkAvUi-zD-_^IU)D}STfkjMJL1KM6i@yjt>vY=3)I^`lTQ8+QaBL&$=YpGOU9;gGFa zaLh@lV&Kcv(;5B}hZ%M{tV@xr$?#EP1N+^o{u43L8S!r_?NjY2rgpRwhjHoTUwS?4 zcFD5FbAuTY0g1d<<7@GabqA&Dy~=6Egsz? zOsKOpeZ4r%k}vJXY6PfnVfN3!wrF-_T2Pf1R0| zfmoEd$RtHX7FJMkmPBbCm(arL7__OR4@EVhVf5EY8>5FhC0@U5IWRtPm_dn%wzv2I z{{DR(%*$Q4r$%mP+-9t&R|n^qy}fRm83vp6gERJ|_b8>ztn}TU79R&K0|0qut%c{> zjS>q%vi_r2A(lEE4?53U<rGb?n)}5RBh-8m`03)WiNdPwr-2o3Me0VtsC3kV0EB%EMvWYx$%NR|@ zm(1^=1*;y)>Z=rTIlzEj%^CCYN9_nN1a@HhfcRVw2|o5D(y+Tdtka_Duf%2Z{6o4s z55ypfB>sjT+wk?KI6SqC_Brg57T98tChU;=tAr#~clfF9c?z2*M|B!o+csA@??)3J z4WrQyY2rDkMmL!#y>E+i4U+#y9X{QRQvct7pAA#@7BGp$Lmjl{jZw0^(Z`4>*m{SO z1hsl~Bm_(sW^%}$#cb`aaB+x7J@aE|7=%j120`na2X+o!eqtJc{0qgHHlM z)R@P!$+;Ir-;3de!)S;|v6lQ(F0nn?9SMlN=!zfIX3@EUM_ECpzB9d|+hh4vj z?9T}04$VnulgnhNEKF|~W;4$ra_u9NBUxhAhj->S?5ON+tM`n% z&K5mr$?en!>; z$Ldxee`xkli6FKRFsy#Yp!}_xrJWf!fB7j&Hd7#RJ|d){LM!D6uKueTypp44Mq0I~ zSb^zYpIn;zJI#>*?A}Kmare7a#+iH7033`tLK-UN{&3ST_bvbGQSY?d)m>&wrBE=+ zxnz^&JVYC;)1<+-?^@eSu@w;^U+Yss4~JRY!wTp^;8X+`zV7~|X*rxg^N7xiYQSB& z`Dbk3E<6t5#{i$D+q(a0G|kXO-|wFP7ItVW*E}C^P?`0}m0R0?(TavMfB6$8A9_Yc zKTKH^$KdgpS+bI~WdGjGGk$q-Rm>O6^|MHhOb;zAmkM8)PV&`?jlK9;^1$5bfJEe_ zVL_GK=0Sq+r3#rFyfa?I2s`Fi67T~$oZ>DVCAcdpznW=it8e)$5O>5bmdbeD*e~Ms z$7`k{^*Z@L@aYdsXGMbsP*n{~aQw=DMq<*!e#3)A0>E0eVQzf z(TalaR`%E*5;)|No@yS>FT_v9j@q;HVg)#G-o!9u^kRp%6Tc#dIuz9O>NN;3?=+&3C3vd+`D1-ta)082SAC;h6BV7cAVq6^j6*{h;Kxd1i|L(M1-#2;~izh@=2(OwKGm0(`n@ zN^{-$Q{rY6rK7cF9w<2_5Yx)=!1yb2?!DUrVzmggHl^f3JXxDZx;F^Fcsr`{H56tVOKbD5Sh?A

h;W9L;UN-Cm?1%)wWsReo#VCM9pCk*Z87D}bb{S0!ubB^|KeSmr4R*N z+XTb)FyDN_Cq_Xknl*KU6`e=6zlbNV_ZAD@Xy8n6ysu;G8#!HvxjiQRi+j4Oyjpwy z58t=(c%<;(ZzHutg>>P{jVai4d~~ZFDbJz1dR!c#3@sMmhbu+V?XeJqmdQ=qM~?X0 zSNRxQ7JZ2s1LZDJT9HP7q?iw33+< zn3M(B20$nA^AQi=4zj0eaRhLtjn`r8y%*^dGE|=@yU3Zy$hP1r38V|(t zx&-wI(a=_J=iKEcT1)^MD6e0??$S%+q7!p}f{MVJZp3Qp{mfBv97sj*+pmi!fR9CQ zN_odRi2tQel` zWvFAZEnq_ouW(l1Nwqd&6beY=Vn+vQFU{m#*sjX{q{Rz>fM*&gu~|ur!MKQ4Yq;W=e6Vh>L)#>WY%3^Ut_mj9acnEoM9oD2Lt{k zO=u35rJ#riR`F;LQf>elmRq5f*wPoGkcBPU>Yo;0cF`k@~HHu9}3 zq~)tczvcF=scXiTctU`XzZ8*Cx#S^<3(NnKY_d+cn1j8atr7-QASgZm`Q~dLRDs<< z?$4)bhQ=a5f8yJ>nf8UwmW|x*4n5^N5y18oJLs#grAN7mpZEg+kt#v7m_&QD z1odxggOA^Qnf?q=09z!g2KU(_-yfQ?MAAxu4$ZEuO(|>3f%t&tk`gELW zxsja<@P2#EwcxX*!dbxi$d1H19($b!;@fl9sat$dyicGP@Djk`OeWu+C~+;|7yI#j zzrU2kunay1;9T^r_uaYBC@^+CH-9t)oG#m5Q4{7^?)+v@K&P1&qCbl#j;!_C5R})>bQLF2yG)QXs2SJ0oOo4IP3U5bN&CE0oGFO}~#^$!0^_^N8?B zmw?(gOk#}`y~X+rcLoNjtPeK$(d^XpxD!+^P>e8p8nT#6GX}~uSJ&P8qG+l? z+Rl>_-ui<$+FNt41wwZ?XBxwQ{P=+^8^E~pS?>#RdbS4D7%+GYQ=%KwKxYTM~WnoA-gH6|L1UDF<$ZUaF%i4WJ5vXD9%i@PhnMTR zFMw2Nu)sip`T^{lD|NU5?k9I+Mx3)=aOuk6CSHok{Kk$zr#B$jV4-IiXKDR<>NPGi zJn-*8js6XI_0bV-FV>!H@(N&8qKWuWg~Ito;8gJ~JofGO^LuNXWaTVYlG?9RtSO+5 zrrEi=IDnoZWvT_j__-Cnwjfhln*X~qay>BQg%&x~u~(3lmDO$>f`JshqD4my2ph$a zh}>Zmy|{aU&!iln!NlEJZxvqM-`#n=iE^BVy>iPFT;N|_h$sZQ5o~vd7}NXj6?rY2 z;r`BwPG9lDI=xio<#}CebQJ`pOn6Nxb!XQ)hKsscQYZnd2YkUc)QIJy(I>aOp>cus zFnZD-Ke1P2lBir}(OwIm$CkfA#Y&;Dn7Q3lD;+m13?QV%4Ej7$D?V zuQGR^g{|YXp}9l(5$)^1hZqjty9NzjPdC6tUZt?MJ3p)qUPk*7pB+ve{@Dmm_t+&; z@==Pr0%F{}agOIMz^SS&JXmpf-jUjmnav%krg_YuH6rY0Q`B;EzvG>+w0bPC@c_ZE zB(h)wF$C!7u4ptSl1C=qh+p8n1PT~)%8~15OC*-$AZa21-)d0R^!(k~@|KdYhm}q7 zi$`gvUlnyJ=iHq`Pcs=d^4a?P9z4IstFEUkRDASzz#lYKdnJb`9pEGSAihR-B`xKl<9lk65Dz$nPK<3swKRaL3b?s02>!L5R zvCK=2?xeSw{nUJ_EZM5(xJScd1p7BH^QwhDSb{C6m*Pa+P?}!3r))*4vpokykR3lu@zpE&Rfx46cWv=eT`a9QC!%(Xw}Pi0|&xO`zKUtTFmw0B>FK$47| zqFU5vy%gqRCrEyR8$Q1~h$a}|vB1icnAVtU}j4?t1rOdIQ*vJ?XFpJx*lxN}qJ;7TF}#>DJx`YWNeaY%7SjY=%8V0CO-P4aw4N(r1aU8jIqmqJsYMzjCGkT(wu zdNo`rm~TJ5vYyQ(3uBJE62IYJLcDyOe%2Jmd}B@9&>08VcF1=oe`RT=Kb7(V z3#^VOn??i|V{75rNTa!RV+hM94l`Pf%7XYnb8H@{5oxhCyD(-O--3g(q zT;Nd(phqKv&jWZAU!JwdeNI%@)5J1wXh8A>H|xJTnv5uKi11@2 ztB#UgV9I;lup69w+wPHd9$LUrMO~#{&J{ zNP!=Zi{<|0q+J*WVj92suUiRbhYEh4zJ2j-nu;Jlb(vFN?8SC>Z`cRG7p#*7C5wck+4BlXg%?o3_q z-gBV)uKekPpj$5R5@#;{Frfy)Qtyeu*Rm#P3x#=X1N)RX%Z7gg4WA9^BRD zzi4jkzP+(Y*lYP%4EM?}0`~aQD`w}8a^~HkVDIJ0?~%iajj62HL9Bbp?{VtMVU(or zF&0M(eTrFRXPaG|CB4$u08CIQNAoHc?!&PF+;hR(k2p_kFw?Nm1o*AFI)oJ$3I+;h zKBj!!Lt)=D#cVYV}Z{`R2#i``E!d4`m4u(g5v#M2sAI;$egayG=^J$0-J912k$Sn(WP2# z(F8hF3Jtg)eC*xBP(v(RFR>8{bRgIE)YQ&RXd8AR?*XE_Zx$bnA34m^Twf;)_d^AK ztq%SDo*?0FzOhV&Xv&z-m3kJyZUCY-p*n;+oA=2j78udO8ht$%G7@59{6CPjkzs$5 z8=XF6ug^1j_rkWW4&Swhl;iw-jkMH|y(BG-!cajqoyOt}0K^&Ewv6Wr_`Yp<%(v`d zc1!CWeqI~01Of%9;JsJ^F9--g+-&@+@9?zu|32{d)*tNc?)Z z7@m{YKT0NON(pypHomtLGWR=k!|fQ8tdsz&$JEWLxu{@yqbo9cH_#qg zMEeCm&P_jHu?nsKN_`M^GWQP0rSgN+;C|8qgSP$ zXwixf+NGW6>u8x|1q>ltn|aN}7`QSlJ<6}a5CBNgcTPSXBJZw!cmj@g7I+JIa6mF@ zIbq~~9LC<-r>9xtnKsf}`SOAuZHBZ{w_!RB4s)QfjRUetD%nG|40`OYX^O&jFI422 z;K~t0k#%J>$1kS_2dUi39tCxJ;i9qPSCM29M=+2mpz9zgXBGtvd>|61{5ncbe-ikm zxGf$zB84NtO@rLF^v>05!vSgNcbd|JZeFx19XG38@!n#+a zP{u6iCXWFJH2uj4HIjqw2I!1{#rE{b#E0^l%%%GX7~MkS&@K)C*|5>Ir=LM(28|_~ zgWmE=83^PVeDcm5?wl+xXh78Z9-@goHAszn6tJrvasVqLH~iUJxaHL_fSn&>;M(Qv z>Uu+4yW-rkpvIJX6FtSUI~tBAUG+)?GSJjTm!-5ppr=*Hb$s-@eLT*(v`HVY#Qh`c*DFU!F2j?>zjBG1^{^y z_dWp&RdLljUD=U7o()a8dW2zUz)q;z3*(2S^F(RHt4`n7)Af|!QHN%p-+axSoR5hx zh|pfRb-IdfA)=>wz(&2z!3A~~K;*rG101wr*eLf1*p6W8AX316dH7Eg+JpmQ7S8Zp z9ni|afXX3eUtAInhs(zw{F_v#=Mwxu`fpe z=WD1d$U*I+-M*P)3iYQy9#a&f6F|9I6YwN^iL8NILnz?@|K{=Z)>!3u5bB`_hQX}{ zFk?j0z#~xJy)Pi1BU~2XxrFpvew-?%#R5_g(2A!=_W)LK*lnl)k+>~OytHI%LrouG zgx1yf-U?4*2_m2W0#m4r#CyQReA}|wULOR*65wi_jZy>!A1(018g7+$mx7+;MG@Wp zocpEu6TLTpgoFJ<|B9{WEfAA{K>#Qbs^}sc$JHxi2s*Ba@!8ff!tBo1)4RNH(519KI*HW8@F6fRz;{wDm~WBXnK+C$6!tM@y3Tewp3~qu@Oz)RC^vk`L_eJu zrpxZDj&Nnc>IS|esA`il!9WfFBHj1$ucoP)3;WxXB?;Mb)@#TEIC$QP0fgyqDG#(m zJ>fS3W*8K~P7)n##jYQLPAs~I44!y_OJfgSM?<5AK~WL(i7r?{k_Sq>hL1`F8&G^5!0frocd26I8%!iUjiu=)rMh^>dz^a!6|9}LdeL7-cU~54I2V8bM2B!EgDqAys*W#pe_4LCJ$RI0=may0{Nr&?f`E!6%>vgZ3Fh zUS_Bm%Tvk=C#trRwiz|A2FK+!S*3S5(!=qy@s+O&m#3HcAy zQCpVU(Ta9l98tyYzM5o?YLB$#32o-V;1|hQkD_Hc)T&GBdv!?uA&JY!RMft>oLO?R z#0pzTvtN+PR8mz@bC@E_TsK7#Y$8o&fATdn5z6f5SZ90S%;g@R3M$mcEsl67xSuXE z{;}{_+adyx`EQ00G4bIwIi=Y8bqf3(<2N*TLBSlP1lT52uILC^oRNG~0yVV)H9ORjJ6cnbFP;{f^q#!$#d-9D2S z7;UnG3Dch__SQ~E*HZ!n>6}2lFZrYh3(Icd@WkGbqifSoh6VQCz&XSe>+gQo{&uCC zhZ?=H2F5yetT3|O&xW_Wv>Sqm5Z+Hf$p!IqC!s(Y;inQwx;ERI^BPNyB(Eg9vTM;V z0)=FUqS=(VOQSd9yX$MM(y_SOmz+%Dfc`Z7ODrdC=xIM{uxm{&vSMZwlr^VEUC~y$H9fWavXHU_<4Nc3sW2+?ECGgS@QhY|)iN#z z#;rb!)RUtWx)*#+$yf=UE)3sFu^?rY58JbueP6SEoA(;&AolkF3PL_eZKFNm5cbU; zXN~mD3)NwY*HcSi6y#u|ycQP)FQ%5~1rP4UhCJqYJ41LS^^oxdcl4AUw5_3EFP2by59x7O(5VPwpwx* zz4NV6#bsemBrOMe0Y=1)UCvN14p;`r%)P0%q#jMq2;8QLJ)`w5 zStuDFFo#z7U_C+>n)a1jlX?G}f0Smc1>IwzX``JGsnlyr-TnS@iyg*#oP?*(XV{&u zlU(=b;f4fThL4dxh}(Sf-M1sE5eZ!l0%dY86PI#I_)x%#KQ`X&(i9^=xf5jwf$9f@ zxk`_Pu+YY&$$S~bXmqO~Seq)cA51BsH9*ffC7Mqy05{;P8(Nb3hd4}GDrwvDmcc5) zBVRAEQNAlC!0%z~7q3)Ccn)3uAJ3DjoqIsk4uA&< zG`NtPQIXp-bYXT~>^L@IueKqehmqU4?OOJ>{N@!5FDB28Y>s&74)Q9ke-yfZwZoZp z*q!JMtue_LWH^*6z+C01I$APfg8ZK&{kGshfdHBXNIRf2DqyHtg&5BPT%vGs!Q3Y(W1!S@B%4I9=c>T}C}h59ATpjT-3869H+$nFe*~)b#HNG& zcCP5b|A(nBfrk41{(p~sDf^PhI`(BsMV1UwcCr_;giu7OD9enkMA<`S%Ni+5g;EBQ zt&$M3i&VC;Z)4_nr_cBN&;Ojx>6~=Td!G06+~?lceZ5|{%kBWe+C`UF#zY=MLfVgW zsxbSvd->?RedNwr*dQ|g@Q1jKFJk8Lr`|86@lDbLW+aP(vD~-IPi+C_L~)*_XjA?l z-GuI*_{EL#{N?fe>i}MO_a;=Oz(?2M>gXUH4g9DwT0>@j2Q;7IKINuRXu5qIQ2m=| zfrHjOwIi}2!b?rTQtO?e4*}&d+NVz^L)PkgA~}YJ^W+9ALYTN56KjYhKL?dDGu(PK zN#5OD78j3Hzq)^Kk7wToi-3u5#y$aoYWGVtxk|S&F9m>GF7t#A?-^E4vw>5o% z)|-e&r##yNsNnK%`42;cb4F*Ei?*Gk%n>BJqvRjAso>|Jww_uMPj)u4_DA@rgi%D; zU1{V;B48*#-2KhmooSFfdBnhzg}Qy9cr&P2_>U@AH)`ot`OT4mr1$6Ot=C7;sK6ub z0jsc^q4je+yuJ!ws0)-$($crf?{>p3a%E7r9`prynE+#>rcl!?Ai0j=DDbA_en+D8&{J*ZaTMaRhZxy5zl|gADP$D70#T zYszy@{50fnP@F&lsCFkuhPDysf3qHT4D@Ec`=T@gr8hq^Y_)(lt|Z~yrK9MDU3`wLf@Ih^gWpD#oozS-lAnSN|aJ!LtK zbPcSH{KvA)4Ci;Z&eH$#suAN0I&Hl-f6nDsddOtWdU8uPisFsAMzv1x&CjYZ z`wbZt$tf;>Th&yjIA6H1V6eah`D^2RcQSt5*=x`DHC5~r$Sxysd3!iI7Fr^3$gzyc zjY7D?sZF}tPcNJFT|2USa7G^nOnG6C!b>3HcAXbvN8ZJIGILH>7@u-8mJOtBkFJ@j zb8dS4^zeQMcglz^+cf3jt;uVW2#uL|$$c_o4+IAI9BLs2@W+=~=?)H9OlW@V75_xK zilz$ep^{7NJnt*~=(lI$X;)Ee6w)xte^MUVY)Ox~`jGA0<!n&=p0Oi<(+ZLU@r_-q-rH_b%JL-&B2?X()ldmO%Y0x&r%&fBtyli++F!QOGfW|Gke!1VK`gRJHcyt~fwG2cdB} zV1dIi_8e23X=r?n?_*pTQ3U#8Z#^bKg?g}QsR5@vz2WP{*6r`+G9AJ3(kz@7x#kEd zxh~w@oui?SYeXfhd%!ZiUG%z!`)M*xEyX-LUJ5U!;cR4#usFXOs!OxtA_C1RbR}9u zF*t%WF8Qf|!=HI*ir`C@7lzoJ$)Y2x3O!T6SoG3|d4k6-1Q(hC((WhlZRzpF-Xm}Q zwRgFD!*hliveoqTyx`sK@nJGhzIwKa8EH7Y*G0Ez$M$bu((Yh3@|E6M^fe1|;#ufW zBY|TIN=hI>LBr*MtS?vEi)P5#EB(+^zA02{Wo)?xkN+clUy*EuR$s?&l}kD1UBS?* zV1c8g1{*1Z;po#)ikA64aq%mjsDmi&s)La7x*n-E(SG|mWC&@y{_rzw-^YL(4kQOK zAGaZJFYO~ zSDsA&gX!11QmZgQhgT>@1=$_^YDmiPwAOh+n4NrhLgCuaY-RbwD$dSEQQbcV4JVS5 z6NjLjJCWp)%hTyq0esX)BaiFHqNAenf>?jd^!I%437>=nvGGX3T@9k0OpS}zYtMpJ ziqq+SoY=$zHmKNlv;xVqcG!sr>AIIKJ6^`dFyV_?#(Cg?>0vc@?*J^`rv0)yg5H zMkZcvza==Ox;NLfY3Ms9x~u4w9dayd`Qi`BvJ* zOPi*z%da?^=EwE$d=uJib@+>++s&3reWgkBu+><=v~>D?Eh8nnKz;=LlH@CI_2)pi+5xpUspfibgP6Dq>y6$rsn1o zaTtcC(HdYLOPgil%{FLyFCGP!p+Xw=!=G#8@I#l%Gc=dWK|!)%#tm!S>Z$N^DK0PqE0T6BEWwZ1GF1ed(-yy|6j6tPG*~kH^@Px@mUx(}K507s| z3K$t20VYwL2;WjOtk#?=_&qp64Y?tBUopqv*oEYtBZzD|r5yf={g)9JHwUzXr0x8E zq>f^I3?C(BO$f zI&RW%aYk>jaU*DcD(Y~`E$(C!s!XT|W$=bHCSFKqWW)`PkUTRszqb&MsU4PzR~f)t zUMoMQ%Y`JJ>WG~A9(TW*k+G$5Wz$V7PH&;u@}zKMPIfjQ^WRJ7!^|o3%$?QII}~C=By)$6UvA7ej}JP!o!}#o)$=P0 zQ=g#{?>XM~6fl;(7`a-EdSw_iL>4W)Z+M*^Aa3yWiAN`N{O+?Hc9vN+Wu&Il2X$7h zqePGTyTcwj#XLz7I@-oB*vFoJ#9v(^eZVj9$hopxE{mh@4~=2J@kE2@mc7n7nod{0 zRm0mDVS*qH>Lf;L)P6UKufJha)k7QAKqBit@x0l5XDhGg3@JqbNHyzP1kP*kJ;Ul| z4rz*TK6`PXV)qQwkgiViGWkqoScBDZxRv>-WP@+$_kB7=k)`_q1Oo`9sazTaMcl+| z87dI%T1l1iX+pDNC0HK{UqpJ%_O_J+UlPRAmiB zdHXjO$IOH1=>Twqo(1UcpxLSquqbsSB=3P||IOM!yRf+TBXGu^goa6Yn=VpU!oxQD zNNL;+5ggDQYh>;QYfR2(!I_6nS9tyR1IoLnE;s+;w?^S2w?#8c}e&e4Mu)e8x<@VOl*Du< z(?O!O*uysp6DzhIi_)@PaB2Ktm|hCy!*K|8$t>T9_#Ct-sHi4p``({I-aR74QEeA4 zszR@m+jlWvMd#kp?nI>~%ak$t`$z87%|o99Qt#Fl_6^7s3{OSkTpxXcHuI^yU9^#X!!d2gz+_Wr9OVijzy zGFTpw172+%!mh>`u$aM_-SCu?K@p7s!Q+}zmCR-PCTt_gqJo~-c*v99@4iK7=0e{3 zgxLM?QGriUcuUH%eYRJ?MnqVc&vakZ>|Tyc?HEbz4SI}K&!I7uY`TUUv@2dc+Qs7t&7vHZgb_q5Wid`DpV!6`IRbMbE6piCdmf!GbirIZ5g!U3Ydz^dvs?lceZf zne<3Xu3m#|ekHxKG0nSVPQ#Db0P9qE^_S4>yy`%)_+8)-#ZwP1=th zOd8inL$}`8zgJx--ggZ9V{NI7JU)n-4CQtTvEbiW*%5^9{f&nm*R~e6%|ggmZW<7A zueO*+!*GVx;V+8{UxBB`jF~lIxTVda-e>5R3^-Y!0x5nI$=-k^E^zor1bUl@;l=09Kf)*%=D~hL669^OeRp8u0hioE^;q?dd)+ zH`yKSUW)(SR^M`72ZtNq;_ya0D-7^t8$auVRz67W`H6M*&*RVdik8_Xo*DPOtAXd0 zustv0Of#_)wHOQ$Jf{E7*QkZJhn;;_z<=O^uB|+@K0rSw06=jS z4r6>%l0m#fmhWyFnK8wfS6kLxHu;GTRGB4qF9 zloqKTEQ+p}guurwwi5p8KmAmIKh+FJrReA;`wMlDc7RvFN!$D6m>Bo*Od*wT4wFAH zk*3o|2wG!wBi%X$5y)b2IZ~af`}V#8W8r83x{n!u*YQ@qnW^cMXU_y-Q{!9CGYbwp zHjx6CpO5^5b)_bNxm3aGb2t98fyHUhJclpEXsKvSwqbR*%(J14v zs7ng9BiXFv=C_N*a+~a7*;M`qcA>3wqXM@`V@u0nar;a`?;4gN{bpN?{6VU}Xggxww7z?EkZe1Cz|Jf1G0KSVV1ichf_|eP3OS^s+&c79N**BjBW! zm%u$MM>}LFir$}kC-{rOj{K%p_pKvQ|JA~Vmxxr#@cUUEU3t#7&vWjFuwP?jMi{1F zRYH`LGQc$y#~1UqC#ee5ig$nRoH~M(q*2P-#KJr2v>DWd*r=v->gr~al0j@6La;2v zHJO+~7SZ8qJ=Ufg?vNe7#X{rVEA%~3hUf(gfT?%X!ljpkO}5%mL!NNKicWCMUgS6r zxIOekd-jnqp7YB=jprzfuzB_VNVjrcFG&b`u>49~Krr?94G;JI_!<)7erqf<5-Xlo zkJ3eihqX_GC0mL=@thU+&P7J}o#@>7*EFJ*yeAZNs@qpz|DKk!nc7+3aOMl0PpYmX z5XJ&?{{DUBdteNTa>L`!O%HYj?dQ*S&tWpp=`iDgQ!#C&5EDZ>^R5$jNZZi#t2SES zaj)n~*TcQ=xp+q&<1wV6r<1Bjom%$lqwOx@XwC-%BZHss{X69uSo=Fg)6lxLa<{!U zt{)Q;lh;I&xJAg%bbEWP{oo~?4KJ-|!VhFpd@wuZy>%y)9%oq_T-JE7g=MYxiq7%Z zJKKnEy}vG{SU^^@ZtaP4-zF=gDh#fzC?DFZT{=zSTdV{Fo2frw6_#ib1Qp0@7Ew!y zMz4*%Y)^x4eW6FA%rcL0u7tLf?mPd`)9>XVP1-dcJqLOe(L{`C)U!L84|LGf{rh1; zJ2-f!I$|BZv21G?^vx14Q=oaEc4)@A4ks~H75ws>F)}q1jgFJrEIFCVTc5U6{Wxed z#`09DM5lKagXq#SZqQ`R=sHaUSBQ>HAF4juBM;2h++`cRbV@%=aO}->+uH!nJr^&Q zx|xY*eEyZ_o3K`YK9u8pRs@KF`IT$NTn_4ud|y~_Zu~Rsq`&KKLc6)J{Uz~ZAdpp{ zvQ)eBMLyL*%u1+$>eq7ilJ3VLvNUwQWX&RoFLGt$8Z>kd{sOZ02q zTnGZ+Ur?D>^t&4AJk=d)WQ4$VPE2(91{kXRgtPLk!^VsKc3L&q8bzZ~kY2Qm>Cu~8 zlnrV-HTK|Vcps6xU)x{1R^S=iJMg)=6#3V|P~7|G-PV)@Bsgl<>qR)uPBg5$g}>6O z4NN6Q-j!jc40nX=C~8LO$*wWpy__y~z*I%j2`*B#ECVntHStjqymjjqm_!M5GlZY7 z0e}R{;8@8pI#Y{ zKBe)B@tn-*Aevv)Gziq|d-m)Bj}}R56lXaAAyH{`Lhs+oPldrg0}9u#;WtX_j|#st zY8Nn%_mfh^laHTe{Cai&u6S|@+zbxtGy${;_d~c4ZZbhg{aS{fvl>pL@{I1=l{*qD zvBH-m2=3ewS141_iAYQu9mk{960q+{3K1LU7oO4n;N~o@Ei;b|-8T8OqsSL*b8<5- z$9pOL&ia#TP5&dCfazb6-WyTO2I~b{F|=pb3T%&FIV46#epijvDblcMs5-8AU;7{w z5iA87UGI(>XG=U89}D)$K!`7!YJ3*BPId1FGc~{5udS>m6py!I8IEu0A?VfJj@_@X zEsG_V8RoRRb3LaanxkVRX=0BG8ipRg-SiRx!{=E_6rpq^fuOl66xRPV@-1=j_b%ja zza&v-w=qgV`=MuZ@JUCkb=%mJUyQ64H>%tlFC{Jq)~jcqPo=+&etXW>JA>h?RCj;a z*~`-4eRSGB8G*7dWO`@m$g;6yWyAY3FT-bWWHj1~e?RSwYnd#6d@Ej8O3Vc?8AkK( zpNF@#NuJjlXL~9X6aDs}hzMc3i$55 zj^(UxttEC&J})!i^$2&Gn`93A#sT&%DBPqg+9(TJayka8-Dy?Gh?kFdL=T5`2!+1h3*fz*>IuJoXwlDf^&2If0>sSY z(*xdzo3zd50>Frjk&#|CzE)@Nu{|&tq@bLQ1T}BSqPmQTZr*JWLO1S0iYI3ZN|K-G&4jPeU>zI|C0*uvC;vXxDB8wbQ-a~4eW zvUi(@6<~<&K_a|&(bUkmWUR_**vJxyvbYEZn>j$r+=&;Q<5bW$tsR@DDQQVbu4lt2 zM*1|O?yXO)h2Y?5MpYdP)CwdZ`H!{(iw-f{`*B^MfPlano4DSdDEr6MvjLuu!Wls>V`M3xU)MU*gh?f*Rz z_+p|yKyjjV?8iX32*rUJUhV0pHHqnzBfs1mzJFvZQ#;=HcGg0xS|!lsbCSr$?9k?D9YYpPkwBVE{Q&JuMSxmz^&)?&pi5Y^ z;k8MrZTK46(Kp0W8i!uqVMbUMTh1B1d*#P}v9s^1cPdI}>F|@4+(nIkmw@N4SKGry zgx|PS)=e7iIR@|3(QIsX_?cXjGpS6d{D92Rjq$}Clc$Q9rIC$MA1@khpJ*hW-0Hb4 zVl6OBpZkfu1j!iZr1Ia@PH>qb=z#rr>rM)$bF0}9YC#&j&So?(g669ww{*P{dBdGEnI`+&re}C{A_oV}v^7^Yq1y34#esn;lh=~*UWfqBPQ~L4Z=kHWJkHa z8=gu>PU@YLU5c*{j*xYI+rXY+`<_x4Vmv4L$p0zqAO1kz6U7#>@#AB#hv3PU`rdnt z)pIy3W4ilix~fl)vsxE_3Qs5>A!M(MsyGa1DVXil%d;s`7;ESFI1O2`DKXz>s`R*# z_6!DMyxzuE;;{LnYi1}WAVj)?{)p)NIG;>CDmL?BhCZDTT7#~nbCuKc7Hz8TUq#bb zM?~!EI{TN~@SRlbBP=?8*oaFY_PxI|T7v8+y|746&2^qT%G`4RI_7|BH-fC}8>w9E zlX5uE2$T#UsC=b0^YO2ls0_~Dq7vd>BnT%rg6u{skgtY5J;{fla}`lHtPEYoHacw| zT{f+B8h0Y*I$7dR<&kmLnVlB>`U_Di^ z*E9{`&{}!X;O`>=7QQ#{Du59i073B4*EAu6)wF|_+L)aFSH8x=1(&NT8bV> z1@O}p*{gmkq0D&Ffs1oMI8O-qoKHQ$b?;`o%?XEc4q=Bi1cCMt+`_&4+if^0~&2cj_mcZ5V1)V^fs#84Q9FlP;PL zUa&XrpKhz>*!_7$>pnB$5w0~nBM0=~>1r%ei>~yQ19I1o$*jYe3F>2CttvQ-;;7)# zzIjs(66H)YC7m?+u%M}?-bm@Z@a@oE z{&jjB6ig_B>bs_HiWfXW#^sb3T8OJHQb9DJe&{eI)ZOJwzv`>wQ-0Wx$=mq zKDV?qRvtB#0p>UgPQ!(J&TRW>bS`WKl=)3Q3+~+fJE{!-+WfyT)Y-nPpn#EKQlj+t zzgTv^Cz_oU3Y~v%Lqz5z7Xl;LfME=g&<+S5VFrGN4Jt@6S8c*n1a8qft}OA3Fe2t` z%`T$V9O%QgJ(0wkVr(8lN#-QQ9dGsgxk2owOcUgjRk*KpK2=iuAo*c6yPVW0B!0LKJihv_?CuHEqZiLxBjJNEZwv% zOnnQdh5F0M{S;a&_H6gvOS|l24n&dq8ohTTI`L%bqfZIxMGp`?IYcU`0DdbI@-ATB z4qfZLR0bJb=N3ghT(3wumgGX(L$ zr=xnMK=gALe-$nJ0rh*}tWxhLJ1;c*7~YpKnf%3k^ZG8Tdz!g$@{Ybz$n`}rSd3I6 z&u!>qKc=*}Xoaiog0n>GBAB6!@#)uc)6{x&we|IV89*o#z) zrmCpd(~_HzC>0ipYa1LhQBp&KPHp?XI7%Y6N#5FlO!tY>C;iXaTu)h7h?7c^h&k6! z>~4?cz>dw|{?jGSKXu|8LuiL5;TIT?VLdT%Ipq_Ukh1-{F z_yIShG<;G>^3O}i0Wv=fn26~?WTd%J)UQbCy4VWm-c^64FM12E{cyAVW+xjlIEqoW zXQSSiHZ)jg@NpQ6-~pS`tT+Vx@TU2WlwOqwJW*2AjPk!(0~31;4?ewoViSn83KT-- zb7_4kE;xdYgN*osOr`;9dLev^4KqJPf8F)`fiXx$bkjtw`F}w$>%eO}7h9YPiPyV@ z0)9x-8wzwT!c68QmY|y=pVn4p_Wk2kBm7m65kL`|>vMzc~=D{68WTDVbZ37^`()@A!Hrnqz* z&VPpERdg=`B-Pszb0m>qQS7tC-gV9Eiyyuy`x09+Ddwr6PHlPpmK`4qQ_sRe%8z=3 zA>h!FN@}(-98F~n%bOtR^ma;=y9km@+qx}P|F-5HWEO7arA+XZqj6`S+?CDX|25yb zEW}p_v53v&IMG@ZZS-Wg30hgp4J~5bEO_hg1$C~4m6VvOxcEAJO!8b6pvJyTSqu%! z6d^-o4}DG|FxG3q)xO?FHXky|fs%8r5|=n_=O@O5vx|aNsQYuvXzS8?>Uhh!mP7PA zSk0@AZz}IX#WEcDV&@i(PjM%%0w9Yh-8U_f`^{-wo}9KEva;l;B8kjUz@x~*`oGk- zg~nTQA8io|s)NErr!9&R@d!Qa9*HT|IhZB#5XrqK_uXgw%?UGSahExPnKJBbP`XF*FhGId>)gi9qVg3 z9 z`-hp`E7J!nrL~3dJh$z2o*deY4{uak~WL4l>u%T+9DL(-P)Toq!B$jRX{jzX(if%LLWvDuox7fLTZ8@5mk`5uX|#-kn;1^Z zOUTm!p69pUeu5N-t0t}vZ(#p!cFodH~gwI1}EfIXbY}cJ$No1GIms7 zD~#kPIq+kk@qnxwSXW8DJ}$l&v3qA@rI-5t@8*6lL8CXUGBj-B{vw7FsMC-OazJ_F zF-NQYr>GaLvQ25WrJH?aZ`nx5%lJ&;I#l&hpLv*Ul5!F*2U@m!=JUJp=Y5g;wF`RH*6`K>`RjyI$`w#Gg-X5Xek8nmQZ zPh?mS5_edMO04=NAH0z(&H1oii33OQ{m!_oVzI)O7qJ76e=$o^1Q!OzRHz&8`0u7T zeUS<3?uNgg~z`|2W|A}3ph*&#j5leWm!5uEI1_dZvF+=jc4M&S`{t*^71~0AAf5DSV;?1vuBEXHz(GW;6MEd zE`w*urfhM0$qgIcJPra=;of5-_4QVkLlVlAF-wceu4ajosfYj8&da_`o|jJe#BHE` zW3@5yt%?sMO>|V3gH&pMu8!Ol`vbpZc zNz-nNIqOSXcOJ>qw5uV?MB>suqENERqWT8u^3uH)jiV7Tset*IfQ=k4eEW_$EsoIM z5%uREA4yar7BW>y3m3Tt$*#zq}a7DoTw8%Rb378S%e&Kvr7mO% zq%5Pr*UBS1EtQl~KQ3!sCy_AlV?oZ1h0Mz1K!sN!_I4))r|%BBfh{Inpa`8K5$&dUYv?JY#;^UckBM_=67aYtVP2x2Ex_U2(~>Wz<|O zeJ@({F%nYazs{~(xH5pnfyTa2fL*u|jHL3%g)L5qc;*fFiWRSYg>cShK)4nxZkQl( z$7MqGs>Z~78;pAW+F`+f>DOhY1Ubj8S=>VB3Cns;QH-uOgla@m)VO!m3cXsd7U z;$$%x&%@eAv0hme-@pfXD@(8`z6xK1C=yORd;_t>o&&sPR@oN8l{-way&Slwx_`es-@R*!0&cdF;|i8L;ZYeWq7I*2#1LlEoVa>RlCB+W1s^?jo zq3DRD_-3U$n35thk2mhOsLEPXx-Zo?{+x07VNKSj+|ZL!K+FFmK}@|Nh;!-b%JI<=wdK`fqX7xgnd%+YnNPyn^ll9<6t+6i?{@L+_(t zS&Zr*T#);qRqf*90*=ckS8u?uIv5`aMxHD|b1wgN$RIVRqtJ$W$g-2U5A1f0J^8p& z=g?ArhHd$Gdwh5u-cm1FVs5lyx$NG$n{s3(wteboIxJsb33~J!C2)%`-RaW<+NTb@t*Re>-7W1PzaD7W)r@dGi>?n{Byw29UW1f((a0;fK04*`7ikH*%CC8UU=t&- zhv9^QG_Dej|7zEOW%ehN=&8fiR33j0yy@pB0_+;yY~YSiePs5L^j(0Bq&+4K$Im-- z^c*u9xgqbwUbC7Lt*<JQYl{4^~)qWt~i3l^ZhQI zGsuPWUSVr4Y@8b2Xb(IRcka_K+_Ejp7tg}px2Yvbj(+2tym%FXg&O9Enioo6qc%GL z9`N`rbc?^?SS0Sxl1j5fds6yPmxR(h3(_5VZEoO@@X^>(*jzS)x2DE%_VcrU2^TT= z>*^s~4LEvK<<<^Zcf(vgrdppqCw%ZvjiqMWD9H98`wZV3=+u@R4({GmqibuL&0uiS zW}vuI9c1#!f8@5<4Uy)vsM8fotaD?6Rde|zRB1uN(>cPmoV6EmW~p)q0NA&WJm&YZ zT11qPM6nLL9HQ70YQgBDnPp`}lGCpp7NPxVB4~0I3vte}(Sc3SUpMXFOuvV8xy0Ds z#};+uA%0%5MlxhVq-*-TT)B+WC26fiM4eE6?OA~JBmnP!}R=?!Hj$l6W(4tChNN=&pcqfxMVt)Qx4 z2o~}tZ4E|j%)-Gqwut?qdk8tT>2TrHGixb@_u)8p&GvkidS6KlztPV-K^Y#22-8MO zhB1xh0QcK**;lvhv>(3DXx(V3```!nq_cI5Q%%6)ON*dN%g~0NeHG>9ss$KraqzRv zecKHcqC3#8Ti9Pyjh64u-z}!eEg;UE<|k=R#km8L%AMe2GIj8;EsOcX`8rL<)X9}O z1-uAVaFu+P6HxGd@2vJ#iTNA1d(Hw#uM%=W@Li6Lv*b%cl+DGB$ZVUu%tu&l>Z}m(qr!WDayJwOr%q2}`|xH$4k+OA z?QRr$coQwwc< zH|yIsHSxfLreTrw>KzI_%q)cdI{x_EzL*vAE;jXFSQ<)hsKm}~iquJSB+pn%>w!lct?VX*I!Hfqt6F$SnF}lz^=B$}dp%)~K z|E8?B`#S#_KRdgf+&yqU!c%Ek!cW{yqkRu+`XO=7>!Uc&_u+#qG&2N;cg&HNgejeB z#!DrnZ`i0gIbY0LeYVQt7VYBJ%gOg)Ej#A?shYWSw+JBE!;es=(-0;*`mf)=$2RJi z&4`-!U`?Yn$bK{G=d{IP?4ghl+a1pZav2wIUp)Q~-J{UUnpL+RZ9g=T0skFoH>r7l!S1C)!n}?aqBQTHqmV8qKaBhrAp~nRk&MNy#doR1cdM@Ui>WtgH4joJ3 z7NKG}hdb-z>ya0LhQGe<8L-hWv{hlos5C9Tx{m{Vy`$$DIX+GJ-+pff_{-2D=FsNG zVTf#yn6)!dkkcgzihl|QH2GevU@4+42|M><&L@52#QI%zO{{xZ^@#(^3Ij&=RPv%A z#6EiDG-L6}6`I9(ye1!g?DKy!UAPYBVbbVMKX{(6SI3t~2ca}Us4~OEm7AXGv9f6Y z%M#}V);i=M@4!>(>v6|X978O7F$-Hb>N?=U)Wq_74fXxMbV+o4-1uyi_P!`g*!H0m z(iG|%w!7AE;pFs1;$c1rB=6R{e8^&)P2CSMr9xSxcGW5A@8CP%N`_Fl5_2mn51r@I z4*trUNCzaeeZV;3JSY4W7|y`V@j=?hDG&eWBMia`<1hyRzz>Zmjk)SUQYuzVuTSCr zxO+;^0xSKkS6V_aQnJJK?3qF3#%wiZb0p{)LX(WhJ&5h3QQl<#Uv3AL7&Rc@+2BDL z;>Fi4fKP>gfYyKWW$swhkT%DRh!D4Jg2QJjRRigUyUthU0)q}%YrrajKUBAOK~ld+ zU@o|&@pL@T#Ad@H0Vkiz@D5dT<{Jt*c$-d}%yyK`jy%@#V)8d`(%DRb$;aoE9*=^e zBmqoiLMR5KB0k^9kUY2K;9lZ`cW3-=R`-oI^b#dj3Rxm|%M2 z^v`fa|4@RcXPx&;OFpQ5T2DI*hLR~?iYcm7i%e(bs&euvhFg(gck9Aq^a?a&*w2>4 z8hn8uX9@}w`oT){Z_xxVnKz~=YH7h6;~p@2YgSR%l!0>QAqFbVYjig+xiLaAA3|6x z4YIAL^w~|g9g1wkQ^#{MM;Q31JoX~OTn?%txMOR44DONtJXm2IhUHo6WUBJ(`p<_U zYi6_Ypr{Y0pPUrACT`R{b0W5m!pLaM=YNrFY0>8kjt^?AZJ4hd@%^+Gurpv->rK6Y zW1G~@wZ5%+BJfpV^saHk8vCMb$jT;^8UVs=MywfRkwE`Nz1^0BmehZcs1EOw_8LwL zKoiRc%TMo`~Vdo~e<@Q0^|Hj^kfttg8cbn=Hm2wQiDBd;zy*bGnRCJJ&;LmMwan&<#B0cc_74AT+N1Vd% znwS52ml6*>nDJ0aM>dL7gFwoW?;z^~uYTgNm}m322qM(kWpCfx8}!|AabY3Ce%FU> z9mpJGJW!wAE>9rU$1k0x3AYaA8y@WvVc40jDvqxRedJ`=I)6879o_R&HoNV z|L0O0Qv;GR{|eIa%4ef1X0CZtp=uNSm&KRU+ndLOhj&vwrZgi)yFR4DkkoRkMt+z8 zbMW{k&bJW0rI6U76PfM714Z&7Su$RTF-5EK`GfzE19jX}j_O zW$GAX?%ptC8|rXv3?XC>xX*P;D4aO?*VJoG2~g1!G$j4+;$>>f76qftaQpJefav0{ z?jM5v^HYI=s=$W}=^uK|B6IXHg!L0v6Sq6F*=Mdk!7x*4a+zuY>bbpRP&bmcSYdQl zUe{R=dw55kk)s+H!baP5MS<=(V(7JmXT(;JH~1oKP31qW(RdolUK)|8h0eJ;NO(os zD>MB_} zfZdquY{G4VQFFHRR8SV>K_PEco*@hQQ(zE0WDoR?7arSeFNkFN!|SHb2V`JiKoCfn zsfm7GBMxNuaC*V>^W<_P>^>1dXs90AV_YG+DOwDaNzi8#xxZ z?V7LgUuNAnWMTGFTX(Om{;Ato`kj>1>!kY!qDZCo3^%8$G*RQGG)*Eggx%cTl!Jk49ps1&Kczx z4s{Z3_7=(9C);B>wJw{Uc;V&Q)k+w3WOb1=ShjTBOkt|xRSuW}3(ix(oGBwq;a7WF z1e|%cR1)8oMz0ty>Rr3xBpgno`vIepo9GrneCFiD69uv2ei-P}^B`JcBJH{O=t0(pg;PjOh6+bW#`do3*5 zFW>c462`c?JqKPDnE1kE5=H$T@V5Qg-ud-nJe~8~CJc_$WU427^pLXhu*5`HfsTRK zMVfAvFVoCHML*gaMH9}jNh0qI@#c*sNY&}w0o{}LC0qow4n13M(0b6697ZIpmeq4d)*TFg~roi*XgMAH`D zjM5!J`IYi*$MGR3-l3qT#toS9$n7KeH$j7H3VujBNIaE{>v;dL5;J^!{2LyP0m|7D zBSm>T4;R~-v3OVEpiHE%(4=ceH=TAt2?9}Fb5a2PX^mfS4R>C?>HSjHf8B+;3>7sv+S#D)UGOva*>)9}Y{xIa=Tvv59g`61Gx8;ZxR5yQby>U3w7e#+hFOx1NA_?w#!f*OGS*)+e|!o26%_X_*2 z7(r5PUuRl^Fzk}hh9CNu{(yTl_C7cOedk-O;deqi$`d->8Oc{UNPPZBvF$FYugaH9Tqu`tb) zOg6r9^jGl8=XLyLGPF#nS*!S(6!4W%I$*cXP70MLJa&tLQl*Atl&tmU9wcrx&}lCxBa!EE1{xZaSYz6v#_vVN_r}x< zKbi+x*LUC4Au*ISg89fa;Js z1e!V{^D^N-BRheSJO9G@6TY9S#|^j;#o`9Ky-Ohv@|h9Lg`V_azr12$lU1hHn(W5MWd@a4 zT7Ak->qOe}rQ-+#qCOF^ynL0k-B0+aFA~~(So8ri{{8_Jsy^Ti$0HWi_20ID&w+-l zJQM3^NA^FkYo6)V*xQ?0esAoujrO@}DujK*rflNwbD8l&>gsv8@^AkHhxzyBHCzp` zVijO+M4c@6A1{S!$^%!yg>ex@7rV<~4H$jfP6&?H<=M*Yw;L1V^&8DEwtFA@puKT_ z7F3~@M?(HkHt;bs&)h@*o;!tcNLT`)-?TZRHL)ZqkW~{&RfnI?F($F`6_+{73~R`3 zbdGlpvWp&uyH#a4yXOnx1Md3u*NZbSKeu9oJ)MpU!e*#b5qJ0>Wj%kRs$YT=_^DsJ zJ6$U^m>KHOKOj#0Z$2#afT_L!x#jm7adgld11HEQ<(B8`8gWq7kOxO`nChu9J-}AN z!jroA)0vSqL~D9fG`l?6BfNNu@?PlJ$DCUUOLPgC_Lx+f1)W6}dWfF}TrM=(MtEe7 zF;O6)ESvMD7$<^Y>YuXKni7+7G%4-qTW{>2e|&hjICK}OR=KgcjcT5S5eBaUd)TvQ zoJW2yKX_)Rsx|9DovH<{wJbIA3DU_1U&lhO(x1bva8up?wtw{b9?u5w1QIm3^FC%D zpp^Tska6wDF?E<>`B6;v+PGynI%j3=sNZ<%yjFBEdN}n&YfzJh@)cuAa|deq#<86LiIXqZ`({Q8r~b4F=SD|CtNb@Xmn-7kV8oVYcBrSU<{J+M|Je;cS|Kocf$C%j-DWXe4 zE|DP=p$r*Hq%xcaa&KI7s3Q(hxs^nSOy43`N~OV-;T$58vASh;D497C4rls)Hm=+6 zdA@)A&OhgQblQ9Ez1I4ywLZi9CDK*>bVLQ)6*A&E8Ye<`)+%wnu=3VZykRt;lp|sH z{t&a84cA$!$L)nvC6ae!4pLv62Lq4k!wP$H`-|^ff8C7Dw%CkJ1r$Yo%qWzc`YG?F zpkIT)Z3`__^vXe6;}KXsAO!)VRMCJ2-XCmmcCX?M*j++(J-GN=Pd|sfSr(y6nW|+#o@At>5E4Ff^!i_Jziet0s#v+jOsI4{C2flTH<2;rf0TU(oJ((My zS8BPUq6BE=Pes0k53t{0bR{T4u3;T@a*AzkwtG^jKV^Icr-p3y+eFplvlf@I8g_L< z=-J>iz7_A*Lag)@X8$mu<1dhGMX?~e*eAzPy;1@ zaWAje-V}Ggu<*PRtT`W~TLTD|xELsxhXc?Ds2%-2PuL49AZ0p|4eAb2P%LNYChzLs z0X}6Qm)=knUa0_8UczO(z8(#QxzvoubVro_{ki(?l(7P@pb*-Vumrmx0KP% z(E53*%9H7{;1dX=9pk@nA;UUxD|?0x1-m$LIAFGMb7a*j3l^keu z*Y^FYRgsF2vucm6yEx1|Bj!d9v7|ll zKWfx+jw@f$E^b-@L5m7n1~i9Bg~ayK#VkFs)~~iaAFRTX)M;1SSy8rS19tdf+5=N7 z<+dibZ#=O^m8Ai`MVRbMz3bl@vHY7iBLlX$?=BCokV#&@WZJ{>1}@Ge_o#Mx%z=VJ!qHCsdD>bKGZp8!0>Yq_H%@hjqYn*l{;Mt%cv0*<)GX2io6MDp! zvO9c(bE*DU+NDJNsL4edpHmc#dx`beMlVKqEHsGhUb{6f>`;|M>b)3}D2)SEp+8rt z?09{lwuM1|EK_bqHHT@yr9k2ATBXyE8U8WO#~zbVdoERg_3wE;lg(8_ewcn409{GB8zy~5GMp}0T#^A5P_U~r2S!-Ebj;M+Om=SjCp(Wz@f~8MKf#$w^3a7JN-m1wFpAFGGa8% z_Uq>(=U(3?N_?Kk-I92fz>uBc_j}GSmbY8=x_)Z=Cfs-`sGY(8mc54< zVRBT7v#eLxG%5!B`s**An-iX~^jIRQHfhNL$qP^nh*8}^t&F4^!&enacD%rGWCzIK zdEhbd3w0YPeWs+28B)sP=e=nj`sV>QODpTk6!XTVBt;L=xF}aNcI`vTzdM|)pRGcn zy7@Jf0Upl=z@GP=)WW|{KPxG@RFRDdDbS6gyZ_ zWbs^?{u-e4ShIl%Edmn95s} z=DvK1XdB7W*-f0#F{_d9B7Y`RPAmjjCRL`SNMiB`2I+o)dBv>JAPX~`9X^u3^GRQG z+{*%M-(Be*4G@M5{YbbwJ!N`daAb$1z%j-X(d%+wPqKXvn7&mwjiD<>0@_vhU`N{T zl|ED7Czd!4{!R|09$&u9PkLapWJ^T%;eta#1_o-c>?pAZwI)V{ua8g6p~6_;sjKfcSt!g8ad@n;#a4t^?)vmEgI!MGZ1OpHL5 zg1_q}-m-x6WJ*E0sri8Aqqo95)gB$<~KJr9BATGbLX zWgD8%V?|0BL}R^aV=<<~L-R#B>)y6cgOC;O49fm!7%xB1kxX+A!;LlF)n!PR&n~*r_SG;|rKVZYNV3r2H?J z1U(q94l-r&QJ89Pkp*JT{0Kp`X?` zA<>oxd0v*)T1?9d^YZZE3c0ZQNg|`VNS@mAKFpUJTq{~K%r2k{gL)3|$PDu@aDqW= z8%nJ)D2TZbdnWYH1M}6K^)0^31A;NQRc`21umj=hTXbQyi9$>yB*5n@-L32BJ|Uq6-r zlc74_5=@;U-z01YX9Yd&s}UUg)<`i$0v|0=IdnU3GW($- zwmMMH9Z{TnYe~pa3UC26P9tJwv_6e|7R3{ZgJHNu?g4UnTn8a=E2Du0;^6HNz+P+* z6O=E)gXoXk)(cx9^w4psGP23TLl~$21R=_DKz6}a7ZiJ5R~`WB?D0byL&{2Ey+KP) z+?wv;LbJ!_+fN!Fw^&do5Vnkwcht}N{0VA1(deNsSCsgo&jgoCyk`{_7Jlx{f}9Qz zPf)pQ%ZA2c6B-zMfp!;b(N2e`ntg{t$Qm%7231`g5~Lr#w8^5u72UyE#0L}5>n zQG~yho<2Q`gN~pNT!|tHvmvVSX954#nNO#mS9)^g-@9i{MByD_PFFQipIxQm&#PPv zqB%f{2@lG(ghdKlds@pd9nQAskBPfNuw_nG^V4??# zj){<@LFzK^gcTxRb`A%L)6q_!gdxSD?u;?V9RbaRWod$MZs5Uh>td9^CKCc0(sFXI zfmXb&iL-o;`h0n;H2*EAu0fn7B2dv1IAl$}_J3boMmCy0CB6z>2vIe_{FqBxLDqc@ zYn+^%hR2y|j!v;c?7pNKwui_HNlV_$iUcf7kQi%N)Tx|*vKG++5A7;ZUq5Z02BM6+y1DtV+X7E0BuGv}P*`)k0ecN;Uiz5Q? zY~TbmT0UUjiUdgLmIQICIO&DYJ{(;c3Ri|lC)zSq{DSj=!dV%j zGwIpmPz&)Dy51-$Fz}Bih$$#-_cPA=tOYC=U4@zHw{^6SE`FZpX)Ta|3m>pwz2+1p zM7Ao`Fw-vld)wK@rlvQOIy%{|VzQ;rHHH{6gEizNYJ0iz}qo!FKYbCfKd;oe}C{kHUbr7JhV=6lXAp)prFIf5zTmxA->9T^0P+>ee zVQ6T0UM&cJR9cK7$SbG2Z=#q-D zbh9~?8A=>0jL7~Pun>TjQjcwgYzCw|}?<#wQC_;COU-dRX}#z^o9h3++Hcp+oGF6 zE-&AJ9jB_*XY|mPdXD*vNjTqQ9SUn(qY^5JRO0u`g!cgXAbhUFtJqxuFeYEEcs95u z`S3^H8E~6R(3+z4zoO4RidBp|y1Fp9|%aq4i8#D4tO=i2oAXZs5r!^R$#RO>LfNI`JMIv3~}2}+!p1p^$4 zvY7l!Q$&8M5?PKNr_9!49z@^klQr;V%W zq9~vE1gL220VLs&T}*U)b97YQ4US!pVgK9fBL-BWjuFBsi2Sv6bgc8OBy&?Vo|blO zlt8dH)Zj_si3m^3Z^Dpj8t`pk&(&+!-cFubcXR@jN)kTkcBIZgSSAKs10btRW7$pT zIux{acK&hi-ltbRHD83-&Vd1(f1gL2KL_6FXiX6r3K@XgyeFg(kC7xnjqq+4n1ZVS zHGz=HKz)Q{oWryTl6}Z=oT!mH4>|ZNt$8MaW+P$F;|8Tg;t6qz7_=Pp#X}DDyypiqO}^2oTD^#sviKBgAurC`y-Y_z}{7{-Yo$Ec|9v2lIh~ z&=lb$1?(}L24I|Es0)C*l=N(G1%1SI6C4Zfw~J35;S6eEXcz!&34gsb%(zrn)c!N) z?&!eaOEFxUGBYRO4XI*`yVA@oQ;=aE}1q_%s+RlrgsyusBhuU7~}u;Hj{CiiNh z0ZIia5;V@?%N8OtKsin5Sqw6{xi=Eo$6lR-9$9=a2X(t=10O)(27Guxkr3=wQT=yf zmA%0_fAggJKQjO+RYnDAHvFw|ZW?u`kvoUY)5b)Q3$(_0LVxe->!?prG=Y3cBsiw5 zskK!U;Nc2o$+*kWwVIzIxhbU(;LHy6Tdwed!RX<=DMv_52LB68hlXS|>GkV}nm2VE zC~&Miz~Qr@U0rnft8R7d74PKVKWdA67F*WT-mVYC>FB&XrAf`iSctk{Q)Y{XhDd1A zTK^CK+H(sDl*fEn2=PCPSP=vV*(9$b4spZms+q1Igw`4r;>*`h>cU8tmXWD`=+YN> z>4pa+en8CgPQl2mrJhSves^R7@#;SYhGY~+G6+k@%T)KA^7R#lsaV_CC>Sd3>FDC3 z<{rtKwd`S`)PrHxZ08@Ezh%2vYrif2=EbrmFd#5cW8d;PbXG8@x516}rVojPr86s> zu@cuG?zBl6wHEU{iXh!DXVouWyx6`aAy=I4LS6T5YDn(nKVvY5E{-lW=oX(mKQCJi zVI$OoDGX55!$!Cb(mE%O@`S14;Gb2v*+{EM%b(;}B9wJvW(m43F_mwawiy?E!&gsN zHy$X#kB`XbY0>nm-uGljfv016o*t@}5&{K^p^?S5SN@54zT#ryC8?m}gsbVqo$6BKmu;xrxhzd9g$kKr{Nb zCZ^)jBfLhQY!m5u9AHoM^e%z##b?WKKCCTHPQ3oZt;eC7-qIt6pc&;Q#FGC0HneAzOU80EL7v zf3Q#k)*V%`gen)KtD8CWiEWq^5!xgr=gVPP<3%^TF#Hm-@1iWSuw7O=qVn zrHRraCxqzgM(b~}?v6Smtx zamG@ym6w!!o{@E%Dz>y$!Gum$KFjS~wi7FVTDd3uZS`mW<4@2fn0bNE%HpuJTrOY! mhyVG%e#Vdd|1O*u!{H#MQUi@C8rK^U_*m_+GcPhd7X4q^K#Jc0 diff --git a/3rd/libuv-1.19.2/img/logos.svg b/3rd/libuv-1.19.2/img/logos.svg deleted file mode 100644 index d6185f8b..00000000 --- a/3rd/libuv-1.19.2/img/logos.svg +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/3rd/libuv-1.19.2/include/android-ifaddrs.h b/3rd/libuv-1.19.2/include/android-ifaddrs.h deleted file mode 100644 index 9cd19fec..00000000 --- a/3rd/libuv-1.19.2/include/android-ifaddrs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 . Note that if 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 - -__BEGIN_DECLS -extern int getifaddrs(struct ifaddrs **ifap); -extern void freeifaddrs(struct ifaddrs *ifa); -__END_DECLS - -#endif diff --git a/3rd/libuv-1.19.2/include/pthread-barrier.h b/3rd/libuv-1.19.2/include/pthread-barrier.h deleted file mode 100644 index 07db9b8a..00000000 --- a/3rd/libuv-1.19.2/include/pthread-barrier.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason - -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_PTHREAD_BARRIER_ -#define _UV_PTHREAD_BARRIER_ -#include -#include -#if !defined(__MVS__) -#include /* sem_t */ -#endif - -#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 -#define UV__PTHREAD_BARRIER_FALLBACK 1 - -/* - * To maintain ABI compatibility with - * libuv v1.x struct is padded according - * to target platform - */ -#if defined(__ANDROID__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - sizeof(pthread_cond_t) + \ - sizeof(unsigned int) - \ - sizeof(void *) -#elif defined(__APPLE__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - 2 * sizeof(sem_t) + \ - 2 * sizeof(unsigned int) - \ - sizeof(void *) -#else -# define UV_BARRIER_STRUCT_PADDING 0 -#endif - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned threshold; - unsigned in; - unsigned out; -} _uv_barrier; - -typedef struct { - _uv_barrier* b; - char _pad[UV_BARRIER_STRUCT_PADDING]; -} 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 /* _UV_PTHREAD_BARRIER_ */ diff --git a/3rd/libuv-1.19.2/include/stdint-msvc2008.h b/3rd/libuv-1.19.2/include/stdint-msvc2008.h deleted file mode 100644 index d02608a5..00000000 --- a/3rd/libuv-1.19.2/include/stdint-msvc2008.h +++ /dev/null @@ -1,247 +0,0 @@ -// 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 - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap 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 -#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 -#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/3rd/libuv-1.19.2/include/tree.h b/3rd/libuv-1.19.2/include/tree.h deleted file mode 100644 index f936416e..00000000 --- a/3rd/libuv-1.19.2/include/tree.h +++ /dev/null @@ -1,768 +0,0 @@ -/*- - * Copyright 2002 Niels Provos - * 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/3rd/libuv-1.19.2/include/uv-aix.h b/3rd/libuv-1.19.2/include/uv-aix.h deleted file mode 100644 index 7dc992fa..00000000 --- a/3rd/libuv-1.19.2/include/uv-aix.h +++ /dev/null @@ -1,32 +0,0 @@ -/* 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/3rd/libuv-1.19.2/include/uv-bsd.h b/3rd/libuv-1.19.2/include/uv-bsd.h deleted file mode 100644 index 2d72b3d7..00000000 --- a/3rd/libuv-1.19.2/include/uv-bsd.h +++ /dev/null @@ -1,34 +0,0 @@ -/* 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/3rd/libuv-1.19.2/include/uv-darwin.h b/3rd/libuv-1.19.2/include/uv-darwin.h deleted file mode 100644 index d2264158..00000000 --- a/3rd/libuv-1.19.2/include/uv-darwin.h +++ /dev/null @@ -1,61 +0,0 @@ -/* 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 -# include -# include -# include -# 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/3rd/libuv-1.19.2/include/uv-errno.h b/3rd/libuv-1.19.2/include/uv-errno.h deleted file mode 100644 index aa4d4509..00000000 --- a/3rd/libuv-1.19.2/include/uv-errno.h +++ /dev/null @@ -1,437 +0,0 @@ -/* 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 -#if EDOM > 0 -# define UV__ERR(x) (-(x)) -#else -# define UV__ERR(x) (x) -#endif - -#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 UV__ERR(E2BIG) -#else -# define UV__E2BIG (-4093) -#endif - -#if defined(EACCES) && !defined(_WIN32) -# define UV__EACCES UV__ERR(EACCES) -#else -# define UV__EACCES (-4092) -#endif - -#if defined(EADDRINUSE) && !defined(_WIN32) -# define UV__EADDRINUSE UV__ERR(EADDRINUSE) -#else -# define UV__EADDRINUSE (-4091) -#endif - -#if defined(EADDRNOTAVAIL) && !defined(_WIN32) -# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL) -#else -# define UV__EADDRNOTAVAIL (-4090) -#endif - -#if defined(EAFNOSUPPORT) && !defined(_WIN32) -# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT) -#else -# define UV__EAFNOSUPPORT (-4089) -#endif - -#if defined(EAGAIN) && !defined(_WIN32) -# define UV__EAGAIN UV__ERR(EAGAIN) -#else -# define UV__EAGAIN (-4088) -#endif - -#if defined(EALREADY) && !defined(_WIN32) -# define UV__EALREADY UV__ERR(EALREADY) -#else -# define UV__EALREADY (-4084) -#endif - -#if defined(EBADF) && !defined(_WIN32) -# define UV__EBADF UV__ERR(EBADF) -#else -# define UV__EBADF (-4083) -#endif - -#if defined(EBUSY) && !defined(_WIN32) -# define UV__EBUSY UV__ERR(EBUSY) -#else -# define UV__EBUSY (-4082) -#endif - -#if defined(ECANCELED) && !defined(_WIN32) -# define UV__ECANCELED UV__ERR(ECANCELED) -#else -# define UV__ECANCELED (-4081) -#endif - -#if defined(ECHARSET) && !defined(_WIN32) -# define UV__ECHARSET UV__ERR(ECHARSET) -#else -# define UV__ECHARSET (-4080) -#endif - -#if defined(ECONNABORTED) && !defined(_WIN32) -# define UV__ECONNABORTED UV__ERR(ECONNABORTED) -#else -# define UV__ECONNABORTED (-4079) -#endif - -#if defined(ECONNREFUSED) && !defined(_WIN32) -# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED) -#else -# define UV__ECONNREFUSED (-4078) -#endif - -#if defined(ECONNRESET) && !defined(_WIN32) -# define UV__ECONNRESET UV__ERR(ECONNRESET) -#else -# define UV__ECONNRESET (-4077) -#endif - -#if defined(EDESTADDRREQ) && !defined(_WIN32) -# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ) -#else -# define UV__EDESTADDRREQ (-4076) -#endif - -#if defined(EEXIST) && !defined(_WIN32) -# define UV__EEXIST UV__ERR(EEXIST) -#else -# define UV__EEXIST (-4075) -#endif - -#if defined(EFAULT) && !defined(_WIN32) -# define UV__EFAULT UV__ERR(EFAULT) -#else -# define UV__EFAULT (-4074) -#endif - -#if defined(EHOSTUNREACH) && !defined(_WIN32) -# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH) -#else -# define UV__EHOSTUNREACH (-4073) -#endif - -#if defined(EINTR) && !defined(_WIN32) -# define UV__EINTR UV__ERR(EINTR) -#else -# define UV__EINTR (-4072) -#endif - -#if defined(EINVAL) && !defined(_WIN32) -# define UV__EINVAL UV__ERR(EINVAL) -#else -# define UV__EINVAL (-4071) -#endif - -#if defined(EIO) && !defined(_WIN32) -# define UV__EIO UV__ERR(EIO) -#else -# define UV__EIO (-4070) -#endif - -#if defined(EISCONN) && !defined(_WIN32) -# define UV__EISCONN UV__ERR(EISCONN) -#else -# define UV__EISCONN (-4069) -#endif - -#if defined(EISDIR) && !defined(_WIN32) -# define UV__EISDIR UV__ERR(EISDIR) -#else -# define UV__EISDIR (-4068) -#endif - -#if defined(ELOOP) && !defined(_WIN32) -# define UV__ELOOP UV__ERR(ELOOP) -#else -# define UV__ELOOP (-4067) -#endif - -#if defined(EMFILE) && !defined(_WIN32) -# define UV__EMFILE UV__ERR(EMFILE) -#else -# define UV__EMFILE (-4066) -#endif - -#if defined(EMSGSIZE) && !defined(_WIN32) -# define UV__EMSGSIZE UV__ERR(EMSGSIZE) -#else -# define UV__EMSGSIZE (-4065) -#endif - -#if defined(ENAMETOOLONG) && !defined(_WIN32) -# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG) -#else -# define UV__ENAMETOOLONG (-4064) -#endif - -#if defined(ENETDOWN) && !defined(_WIN32) -# define UV__ENETDOWN UV__ERR(ENETDOWN) -#else -# define UV__ENETDOWN (-4063) -#endif - -#if defined(ENETUNREACH) && !defined(_WIN32) -# define UV__ENETUNREACH UV__ERR(ENETUNREACH) -#else -# define UV__ENETUNREACH (-4062) -#endif - -#if defined(ENFILE) && !defined(_WIN32) -# define UV__ENFILE UV__ERR(ENFILE) -#else -# define UV__ENFILE (-4061) -#endif - -#if defined(ENOBUFS) && !defined(_WIN32) -# define UV__ENOBUFS UV__ERR(ENOBUFS) -#else -# define UV__ENOBUFS (-4060) -#endif - -#if defined(ENODEV) && !defined(_WIN32) -# define UV__ENODEV UV__ERR(ENODEV) -#else -# define UV__ENODEV (-4059) -#endif - -#if defined(ENOENT) && !defined(_WIN32) -# define UV__ENOENT UV__ERR(ENOENT) -#else -# define UV__ENOENT (-4058) -#endif - -#if defined(ENOMEM) && !defined(_WIN32) -# define UV__ENOMEM UV__ERR(ENOMEM) -#else -# define UV__ENOMEM (-4057) -#endif - -#if defined(ENONET) && !defined(_WIN32) -# define UV__ENONET UV__ERR(ENONET) -#else -# define UV__ENONET (-4056) -#endif - -#if defined(ENOSPC) && !defined(_WIN32) -# define UV__ENOSPC UV__ERR(ENOSPC) -#else -# define UV__ENOSPC (-4055) -#endif - -#if defined(ENOSYS) && !defined(_WIN32) -# define UV__ENOSYS UV__ERR(ENOSYS) -#else -# define UV__ENOSYS (-4054) -#endif - -#if defined(ENOTCONN) && !defined(_WIN32) -# define UV__ENOTCONN UV__ERR(ENOTCONN) -#else -# define UV__ENOTCONN (-4053) -#endif - -#if defined(ENOTDIR) && !defined(_WIN32) -# define UV__ENOTDIR UV__ERR(ENOTDIR) -#else -# define UV__ENOTDIR (-4052) -#endif - -#if defined(ENOTEMPTY) && !defined(_WIN32) -# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY) -#else -# define UV__ENOTEMPTY (-4051) -#endif - -#if defined(ENOTSOCK) && !defined(_WIN32) -# define UV__ENOTSOCK UV__ERR(ENOTSOCK) -#else -# define UV__ENOTSOCK (-4050) -#endif - -#if defined(ENOTSUP) && !defined(_WIN32) -# define UV__ENOTSUP UV__ERR(ENOTSUP) -#else -# define UV__ENOTSUP (-4049) -#endif - -#if defined(EPERM) && !defined(_WIN32) -# define UV__EPERM UV__ERR(EPERM) -#else -# define UV__EPERM (-4048) -#endif - -#if defined(EPIPE) && !defined(_WIN32) -# define UV__EPIPE UV__ERR(EPIPE) -#else -# define UV__EPIPE (-4047) -#endif - -#if defined(EPROTO) && !defined(_WIN32) -# define UV__EPROTO UV__ERR(EPROTO) -#else -# define UV__EPROTO UV__ERR(4046) -#endif - -#if defined(EPROTONOSUPPORT) && !defined(_WIN32) -# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT) -#else -# define UV__EPROTONOSUPPORT (-4045) -#endif - -#if defined(EPROTOTYPE) && !defined(_WIN32) -# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE) -#else -# define UV__EPROTOTYPE (-4044) -#endif - -#if defined(EROFS) && !defined(_WIN32) -# define UV__EROFS UV__ERR(EROFS) -#else -# define UV__EROFS (-4043) -#endif - -#if defined(ESHUTDOWN) && !defined(_WIN32) -# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN) -#else -# define UV__ESHUTDOWN (-4042) -#endif - -#if defined(ESPIPE) && !defined(_WIN32) -# define UV__ESPIPE UV__ERR(ESPIPE) -#else -# define UV__ESPIPE (-4041) -#endif - -#if defined(ESRCH) && !defined(_WIN32) -# define UV__ESRCH UV__ERR(ESRCH) -#else -# define UV__ESRCH (-4040) -#endif - -#if defined(ETIMEDOUT) && !defined(_WIN32) -# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT) -#else -# define UV__ETIMEDOUT (-4039) -#endif - -#if defined(ETXTBSY) && !defined(_WIN32) -# define UV__ETXTBSY UV__ERR(ETXTBSY) -#else -# define UV__ETXTBSY (-4038) -#endif - -#if defined(EXDEV) && !defined(_WIN32) -# define UV__EXDEV UV__ERR(EXDEV) -#else -# define UV__EXDEV (-4037) -#endif - -#if defined(EFBIG) && !defined(_WIN32) -# define UV__EFBIG UV__ERR(EFBIG) -#else -# define UV__EFBIG (-4036) -#endif - -#if defined(ENOPROTOOPT) && !defined(_WIN32) -# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT) -#else -# define UV__ENOPROTOOPT (-4035) -#endif - -#if defined(ERANGE) && !defined(_WIN32) -# define UV__ERANGE UV__ERR(ERANGE) -#else -# define UV__ERANGE (-4034) -#endif - -#if defined(ENXIO) && !defined(_WIN32) -# define UV__ENXIO UV__ERR(ENXIO) -#else -# define UV__ENXIO (-4033) -#endif - -#if defined(EMLINK) && !defined(_WIN32) -# define UV__EMLINK UV__ERR(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 UV__ERR(EHOSTDOWN) -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) || \ - defined(__OpenBSD__) -# define UV__EHOSTDOWN (-64) -#else -# define UV__EHOSTDOWN (-4031) -#endif - -#if defined(EREMOTEIO) && !defined(_WIN32) -# define UV__EREMOTEIO UV__ERR(EREMOTEIO) -#else -# define UV__EREMOTEIO (-4030) -#endif - -#if defined(ENOTTY) && !defined(_WIN32) -# define UV__ENOTTY UV__ERR(ENOTTY) -#else -# define UV__ENOTTY (-4029) -#endif - - -#endif /* UV_ERRNO_H_ */ diff --git a/3rd/libuv-1.19.2/include/uv-linux.h b/3rd/libuv-1.19.2/include/uv-linux.h deleted file mode 100644 index 9b38405a..00000000 --- a/3rd/libuv-1.19.2/include/uv-linux.h +++ /dev/null @@ -1,34 +0,0 @@ -/* 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/3rd/libuv-1.19.2/include/uv-os390.h b/3rd/libuv-1.19.2/include/uv-os390.h deleted file mode 100644 index 39e7384d..00000000 --- a/3rd/libuv-1.19.2/include/uv-os390.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright 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. - */ - -#ifndef UV_MVS_H -#define UV_MVS_H - -#define UV_PLATFORM_SEM_T int - -#define UV_PLATFORM_LOOP_FIELDS \ - void* ep; \ - -#define UV_PLATFORM_FS_EVENT_FIELDS \ - char rfis_rftok[8]; \ - -#endif /* UV_MVS_H */ diff --git a/3rd/libuv-1.19.2/include/uv-posix.h b/3rd/libuv-1.19.2/include/uv-posix.h deleted file mode 100644 index 9a96634d..00000000 --- a/3rd/libuv-1.19.2/include/uv-posix.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 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. - */ - -#ifndef UV_POSIX_H -#define UV_POSIX_H - -#define UV_PLATFORM_LOOP_FIELDS \ - struct pollfd* poll_fds; \ - size_t poll_fds_used; \ - size_t poll_fds_size; \ - unsigned char poll_fds_iterating; \ - -#endif /* UV_POSIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-sunos.h b/3rd/libuv-1.19.2/include/uv-sunos.h deleted file mode 100644 index 04216642..00000000 --- a/3rd/libuv-1.19.2/include/uv-sunos.h +++ /dev/null @@ -1,44 +0,0 @@ -/* 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 -#include - -/* 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/3rd/libuv-1.19.2/include/uv-threadpool.h b/3rd/libuv-1.19.2/include/uv-threadpool.h deleted file mode 100644 index 9708ebdd..00000000 --- a/3rd/libuv-1.19.2/include/uv-threadpool.h +++ /dev/null @@ -1,37 +0,0 @@ -/* 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/3rd/libuv-1.19.2/include/uv-unix.h b/3rd/libuv-1.19.2/include/uv-unix.h deleted file mode 100644 index da32f86e..00000000 --- a/3rd/libuv-1.19.2/include/uv-unix.h +++ /dev/null @@ -1,464 +0,0 @@ -/* 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#if !defined(__MVS__) -#include -#endif -#include -#include - -#include "uv-threadpool.h" - -#if defined(__linux__) -# include "uv-linux.h" -#elif defined (__MVS__) -# include "uv-os390.h" -#elif defined(_PASE) -# include "uv-posix.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(__FreeBSD_kernel__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# include "uv-bsd.h" -#elif defined(__CYGWIN__) || defined(__MSYS__) -# include "uv-posix.h" -#endif - -#ifndef PTHREAD_BARRIER_SERIAL_THREAD -# include "pthread-barrier.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_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 -}; - -#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; -typedef pid_t uv_pid_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; -typedef pthread_barrier_t uv_barrier_t; - - -/* 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]; \ - void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ - uv__io_t async_io_watcher; \ - int async_wfd; \ - 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 \ - -/* fs open() flags supported on this platform: */ -#if defined(O_APPEND) -# define UV_FS_O_APPEND O_APPEND -#else -# define UV_FS_O_APPEND 0 -#endif -#if defined(O_CREAT) -# define UV_FS_O_CREAT O_CREAT -#else -# define UV_FS_O_CREAT 0 -#endif -#if defined(O_DIRECT) -# define UV_FS_O_DIRECT O_DIRECT -#else -# define UV_FS_O_DIRECT 0 -#endif -#if defined(O_DIRECTORY) -# define UV_FS_O_DIRECTORY O_DIRECTORY -#else -# define UV_FS_O_DIRECTORY 0 -#endif -#if defined(O_DSYNC) -# define UV_FS_O_DSYNC O_DSYNC -#else -# define UV_FS_O_DSYNC 0 -#endif -#if defined(O_EXCL) -# define UV_FS_O_EXCL O_EXCL -#else -# define UV_FS_O_EXCL 0 -#endif -#if defined(O_EXLOCK) -# define UV_FS_O_EXLOCK O_EXLOCK -#else -# define UV_FS_O_EXLOCK 0 -#endif -#if defined(O_NOATIME) -# define UV_FS_O_NOATIME O_NOATIME -#else -# define UV_FS_O_NOATIME 0 -#endif -#if defined(O_NOCTTY) -# define UV_FS_O_NOCTTY O_NOCTTY -#else -# define UV_FS_O_NOCTTY 0 -#endif -#if defined(O_NOFOLLOW) -# define UV_FS_O_NOFOLLOW O_NOFOLLOW -#else -# define UV_FS_O_NOFOLLOW 0 -#endif -#if defined(O_NONBLOCK) -# define UV_FS_O_NONBLOCK O_NONBLOCK -#else -# define UV_FS_O_NONBLOCK 0 -#endif -#if defined(O_RDONLY) -# define UV_FS_O_RDONLY O_RDONLY -#else -# define UV_FS_O_RDONLY 0 -#endif -#if defined(O_RDWR) -# define UV_FS_O_RDWR O_RDWR -#else -# define UV_FS_O_RDWR 0 -#endif -#if defined(O_SYMLINK) -# define UV_FS_O_SYMLINK O_SYMLINK -#else -# define UV_FS_O_SYMLINK 0 -#endif -#if defined(O_SYNC) -# define UV_FS_O_SYNC O_SYNC -#else -# define UV_FS_O_SYNC 0 -#endif -#if defined(O_TRUNC) -# define UV_FS_O_TRUNC O_TRUNC -#else -# define UV_FS_O_TRUNC 0 -#endif -#if defined(O_WRONLY) -# define UV_FS_O_WRONLY O_WRONLY -#else -# define UV_FS_O_WRONLY 0 -#endif - -/* fs open() flags supported on other platforms: */ -#define UV_FS_O_RANDOM 0 -#define UV_FS_O_SHORT_LIVED 0 -#define UV_FS_O_SEQUENTIAL 0 -#define UV_FS_O_TEMPORARY 0 - -#endif /* UV_UNIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-version.h b/3rd/libuv-1.19.2/include/uv-version.h deleted file mode 100644 index c2753d51..00000000 --- a/3rd/libuv-1.19.2/include/uv-version.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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 19 -#define UV_VERSION_PATCH 2 -#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/3rd/libuv-1.19.2/include/uv-win.h b/3rd/libuv-1.19.2/include/uv-win.h deleted file mode 100644 index 4c6c50a2..00000000 --- a/3rd/libuv-1.19.2/include/uv-win.h +++ /dev/null @@ -1,676 +0,0 @@ -/* 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 0x0600 -#endif - -#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) -typedef intptr_t ssize_t; -# define _SSIZE_T_ -# define _SSIZE_T_DEFINED -#endif - -#include - -#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 -#include -#include - -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#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 int uv_pid_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 */ \ - /* TODO: remove me in v2.x. */ \ - HANDLE unused_; \ - 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; - -#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 - -/* fs open() flags supported on this platform: */ -#define UV_FS_O_APPEND _O_APPEND -#define UV_FS_O_CREAT _O_CREAT -#define UV_FS_O_EXCL _O_EXCL -#define UV_FS_O_RANDOM _O_RANDOM -#define UV_FS_O_RDONLY _O_RDONLY -#define UV_FS_O_RDWR _O_RDWR -#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL -#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED -#define UV_FS_O_TEMPORARY _O_TEMPORARY -#define UV_FS_O_TRUNC _O_TRUNC -#define UV_FS_O_WRONLY _O_WRONLY - -/* fs open() flags supported on other platforms (or mapped on this platform): */ -#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ -#define UV_FS_O_DIRECTORY 0 -#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ -#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ -#define UV_FS_O_NOATIME 0 -#define UV_FS_O_NOCTTY 0 -#define UV_FS_O_NOFOLLOW 0 -#define UV_FS_O_NONBLOCK 0 -#define UV_FS_O_SYMLINK 0 -#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/3rd/libuv-1.19.2/include/uv.h b/3rd/libuv-1.19.2/include/uv.h deleted file mode 100644 index 9794d996..00000000 --- a/3rd/libuv-1.19.2/include/uv.h +++ /dev/null @@ -1,1567 +0,0 @@ -/* 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 -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#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") \ - XX(EREMOTEIO, "remote I/O error") \ - XX(ENOTTY, "inappropriate ioctl for device") \ - -#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 struct uv_passwd_s uv_passwd_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_loop_fork(uv_loop_t* loop); - -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 int uv_translate_sys_error(int sys_errno); - -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 uv_handle_type uv_handle_get_type(const uv_handle_t* handle); -UV_EXTERN const char* uv_handle_type_name(uv_handle_type type); -UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle); -UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle); -UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data); - -UV_EXTERN size_t uv_req_size(uv_req_type type); -UV_EXTERN void* uv_req_get_data(const uv_req_t* req); -UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data); -UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req); -UV_EXTERN const char* uv_req_type_name(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 size_t uv_stream_get_write_queue_size(const uv_stream_t* stream); - -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_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); -UV_EXTERN size_t uv_udp_get_send_queue_count(const 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(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); -UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); - - -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_DISCONNECT = 4, - UV_PRIORITIZED = 8 -}; - -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_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*); - - -/* - * 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; -}; - -struct uv_passwd_s { - char* username; - long uid; - long gid; - char* shell; - char* homedir; -}; - -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); -UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); - -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_os_tmpdir(char* buffer, size_t* size); -UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); -UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); -UV_EXTERN uv_pid_t uv_os_getpid(void); -UV_EXTERN uv_pid_t uv_os_getppid(void); - -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); - -UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); -UV_EXTERN int uv_os_setenv(const char* name, const char* value); -UV_EXTERN int uv_os_unsetenv(const char* name); - -UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); - - -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_COPYFILE -} 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 uv_fs_type uv_fs_get_type(const uv_fs_t*); -UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); -UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); -UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); -UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); - -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); -/* - * This flag can be used with uv_fs_copyfile() to return an error if the - * destination already exists. - */ -#define UV_FS_COPYFILE_EXCL 0x0001 - -UV_EXTERN int uv_fs_copyfile(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_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_start_oneshot(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); - -#if defined(IF_NAMESIZE) -# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) -#elif defined(IFNAMSIZ) -# define UV_IF_NAMESIZE (IFNAMSIZ + 1) -#else -# define UV_IF_NAMESIZE (16 + 1) -#endif - -UV_EXTERN int uv_if_indextoname(unsigned int ifindex, - char* buffer, - size_t* size); -UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, - char* buffer, - size_t* size); - -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 int uv_mutex_init_recursive(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 -}; - -UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); -UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); - -/* 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 -#undef UV__ERR - -#ifdef __cplusplus -} -#endif -#endif /* UV_H */ diff --git a/3rd/libuv-1.19.2/libuv.pc.in b/3rd/libuv-1.19.2/libuv.pc.in deleted file mode 100644 index 55c4b65d..00000000 --- a/3rd/libuv-1.19.2/libuv.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -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. -URL: http://libuv.org/ - -Libs: -L${libdir} -luv @LIBS@ -Cflags: -I${includedir} diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv-1.19.2/libuv.vcxproj deleted file mode 100644 index d15ee945..00000000 --- a/3rd/libuv-1.19.2/libuv.vcxproj +++ /dev/null @@ -1,217 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {DF6C5660-6B48-4E4A-BF98-E1739CA83E41} - Win32Proj - libuv - 10.0.16299.0 - - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - StaticLibrary - true - v141 - Unicode - - - StaticLibrary - false - v141 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(ProjectDir)\include;$(ProjectDir)\src;$(IncludePath) - - - true - - - false - $(ProjectDir)\include;$(ProjectDir)\src;$(IncludePath) - - - false - - - - NotUsing - Level3 - Disabled - true - WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) - true - ../include - - - Windows - true - - - - - Use - Level3 - Disabled - true - _DEBUG;_LIB;%(PreprocessorDefinitions) - true - - - Windows - true - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) - true - ../include - - - Windows - true - true - true - - - - - Use - Level3 - MaxSpeed - true - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - \ No newline at end of file diff --git a/3rd/libuv-1.19.2/m4/.gitignore b/3rd/libuv-1.19.2/m4/.gitignore deleted file mode 100644 index c44e4c29..00000000 --- a/3rd/libuv-1.19.2/m4/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore libtoolize-generated files. -*.m4 -!as_case.m4 -!libuv-check-flags.m4 diff --git a/3rd/libuv-1.19.2/m4/as_case.m4 b/3rd/libuv-1.19.2/m4/as_case.m4 deleted file mode 100644 index c7ae0f0f..00000000 --- a/3rd/libuv-1.19.2/m4/as_case.m4 +++ /dev/null @@ -1,21 +0,0 @@ -# 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/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 b/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 deleted file mode 100644 index 59c30635..00000000 --- a/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 +++ /dev/null @@ -1,319 +0,0 @@ -dnl Macros to check the presence of generic (non-typed) symbols. -dnl Copyright (c) 2006-2008 Diego Pettenà -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/3rd/libuv-1.19.2/samples/.gitignore b/3rd/libuv-1.19.2/samples/.gitignore deleted file mode 100644 index f868091b..00000000 --- a/3rd/libuv-1.19.2/samples/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -# 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/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore b/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore deleted file mode 100644 index c177f374..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# 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/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE b/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE deleted file mode 100644 index 63c1447f..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE +++ /dev/null @@ -1,53 +0,0 @@ -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/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp b/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp deleted file mode 100644 index 771a1e14..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp +++ /dev/null @@ -1,46 +0,0 @@ -# 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/3rd/libuv-1.19.2/samples/socks5-proxy/client.c b/3rd/libuv-1.19.2/samples/socks5-proxy/client.c deleted file mode 100644 index aa2a91c9..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/client.c +++ /dev/null @@ -1,736 +0,0 @@ -/* 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 -#include -#include - -/* 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); -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) { - conn *c; - - 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/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h b/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h deleted file mode 100644 index 99ee8160..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h +++ /dev/null @@ -1,139 +0,0 @@ -/* 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 -#include /* sockaddr_in, sockaddr_in6 */ -#include /* size_t, ssize_t */ -#include -#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c b/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c deleted file mode 100644 index 8481b226..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $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 -#include -#include -#include - -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/3rd/libuv-1.19.2/samples/socks5-proxy/main.c b/3rd/libuv-1.19.2/samples/socks5-proxy/main.c deleted file mode 100644 index 04020cbd..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/main.c +++ /dev/null @@ -1,99 +0,0 @@ -/* 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 -#include -#include - -#if HAVE_UNISTD_H -#include /* 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

[-h] [-p ]\n" - "\n" - "Options:\n" - "\n" - " -b Bind to this address or hostname.\n" - " Default: \"127.0.0.1\"\n" - " -h Show this help message.\n" - " -p Bind to this port number. Default: 1080\n" - "", - progname); - exit(1); -} diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c deleted file mode 100644 index 4f08e345..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c +++ /dev/null @@ -1,271 +0,0 @@ -/* 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 -#include -#include /* abort() */ -#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h deleted file mode 100644 index 715f3222..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/samples/socks5-proxy/server.c b/3rd/libuv-1.19.2/samples/socks5-proxy/server.c deleted file mode 100644 index 3f1ba42c..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/server.c +++ /dev/null @@ -1,241 +0,0 @@ -/* 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 /* INET6_ADDRSTRLEN */ -#include -#include - -#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/3rd/libuv-1.19.2/samples/socks5-proxy/util.c b/3rd/libuv-1.19.2/samples/socks5-proxy/util.c deleted file mode 100644 index af34f055..00000000 --- a/3rd/libuv-1.19.2/samples/socks5-proxy/util.c +++ /dev/null @@ -1,72 +0,0 @@ -/* 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 -#include -#include - -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/3rd/libuv-1.19.2/src/fs-poll.c b/3rd/libuv-1.19.2/src/fs-poll.c deleted file mode 100644 index ee73d5a2..00000000 --- a/3rd/libuv-1.19.2/src/fs-poll.c +++ /dev/null @@ -1,256 +0,0 @@ -/* 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 -#include -#include - -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 + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, ctx->path, required_len); - *size = required_len; - buffer[required_len] = '\0'; - - 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/3rd/libuv-1.19.2/src/heap-inl.h b/3rd/libuv-1.19.2/src/heap-inl.h deleted file mode 100644 index 1e2ed60e..00000000 --- a/3rd/libuv-1.19.2/src/heap-inl.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * 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 /* 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/3rd/libuv-1.19.2/src/inet.c b/3rd/libuv-1.19.2/src/inet.c deleted file mode 100644 index da63a688..00000000 --- a/3rd/libuv-1.19.2/src/inet.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * 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 -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#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/3rd/libuv-1.19.2/src/queue.h b/3rd/libuv-1.19.2/src/queue.h deleted file mode 100644 index ff3540a0..00000000 --- a/3rd/libuv-1.19.2/src/queue.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * 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 - -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/3rd/libuv-1.19.2/src/threadpool.c b/3rd/libuv-1.19.2/src/threadpool.c deleted file mode 100644 index 413d1c20..00000000 --- a/3rd/libuv-1.19.2/src/threadpool.c +++ /dev/null @@ -1,318 +0,0 @@ -/* 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" -#endif - -#include - -#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 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; - - uv_sem_post((uv_sem_t*) arg); - arg = NULL; - - 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 (nthreads == 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; -} -#endif - - -static void init_threads(void) { - unsigned int i; - const char* val; - uv_sem_t sem; - - 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); - - if (uv_sem_init(&sem, 0)) - abort(); - - for (i = 0; i < nthreads; i++) - if (uv_thread_create(threads + i, worker, &sem)) - abort(); - - for (i = 0; i < nthreads; i++) - uv_sem_wait(&sem); - - uv_sem_destroy(&sem); -} - - -#ifndef _WIN32 -static void reset_once(void) { - uv_once_t child_once = UV_ONCE_INIT; - memcpy(&once, &child_once, sizeof(child_once)); -} -#endif - - -static void init_once(void) { -#ifndef _WIN32 - /* Re-initialize the threadpool after fork. - * Note that this discards the global mutex and condition as well - * as the work queue. - */ - if (pthread_atfork(NULL, NULL, &reset_once)) - abort(); -#endif - init_threads(); -} - - -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/3rd/libuv-1.19.2/src/unix/aix-common.c b/3rd/libuv-1.19.2/src/unix/aix-common.c deleted file mode 100644 index e17e4494..00000000 --- a/3rd/libuv-1.19.2/src/unix/aix-common.c +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include - -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 UV_EINVAL; - - pi.pi_pid = getpid(); - res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) - return UV_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 UV__ERR(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 UV_EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return UV_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 UV_EINVAL; - } -} - -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, inet6, size = 1; - struct ifconf ifc; - struct ifreq *ifr, *p, flg; - struct sockaddr_dl* sa_addr; - - *count = 0; - - if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { - return UV__ERR(errno); - } - - if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - uv__close(sockfd); - return UV__ERR(errno); - } - - ifc.ifc_req = (struct ifreq*)uv__malloc(size); - ifc.ifc_len = size; - if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - uv__close(sockfd); - return UV__ERR(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) { - uv__close(sockfd); - return UV__ERR(errno); - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - (*count)++; - } - - /* Alloc the return interface structs */ - *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); - if (!(*addresses)) { - uv__close(sockfd); - return UV_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; - - inet6 = (p->ifr_addr.sa_family == AF_INET6); - - memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - uv__close(sockfd); - return UV_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 (inet6) - address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - else - address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); - - sa_addr = (struct sockaddr_dl*) &p->ifr_addr; - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - - if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { - uv__close(sockfd); - return UV_ENOSYS; - } - - if (inet6) - address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); - else - address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); - - 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); -} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/aix.c b/3rd/libuv-1.19.2/src/unix/aix.c deleted file mode 100644 index 92de8148..00000000 --- a/3rd/libuv-1.19.2/src/unix/aix.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#ifdef HAVE_SYS_AHAFS_EVPRODS_H -#include -#endif - -#include -#include -#include -#include -#include - -#define RDWR_BUF_SIZE 4096 -#define EQ(a,b) (strcmp(a,b) == 0) - -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static void* args_mem = NULL; -static char** process_argv = NULL; -static int process_argc = 0; -static char* process_title_ptr = NULL; - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - -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; - } -} - - -int uv__io_fork(uv_loop_t* loop) { - uv__platform_loop_delete(loop); - - return uv__platform_loop_init(loop); -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct poll_ctl pc; - - pc.events = POLLIN; - pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ - pc.fd = fd; - - if (pollset_ctl(loop->backend_fd, &pc, 1)) - return UV__ERR(errno); - - pc.cmd = PS_DELETE; - if (pollset_ctl(loop->backend_fd, &pc, 1)) - abort(); - - return 0; -} - - -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 have_signals; - 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; - } - - have_signals = 0; - 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; - } - - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) - have_signals = 1; - else - w->cb(loop, w, pe->revents); - - nevents++; - } - - if (have_signals != 0) - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - 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_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 UV__ERR(errno); - - /* Retrieve all mounted filesystems */ - rv = mntctl(MCTL_QUERY, siz, (char*)p); - if (rv < 0) - return UV__ERR(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 UV__ERR(errno); - rv = mntctl(MCTL_QUERY, siz, (char*)p); - if (rv < 0) - return UV__ERR(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 && errno != EEXIST) - 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 UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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; - char fname[PATH_MAX]; - char *p; - - handle = container_of(event_watch, uv_fs_event_t, event_watcher); - - /* 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"); - - /* In file / directory move cases, AIX Event infrastructure - * produces a second event with no data. - * Ignore it and return gracefully. - */ - if(bytes == 0) - return; - - /* Parse the data */ - if(bytes > 0) - rc = uv__parse_data(result_data, &events, handle); - - /* Unrecoverable error */ - if (rc == -1) - return; - - /* 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; - } else { - p = strrchr(handle->path, '/'); - if (p == NULL) - p = handle->path; - else - p++; - } - strncpy(fname, p, sizeof(fname) - 1); - /* Just in case */ - fname[sizeof(fname) - 1] = '\0'; - - handle->cb(handle, 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 UV_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, str_offset = 0; - char cwd[PATH_MAX]; - char absolute_path[PATH_MAX]; - char readlink_cwd[PATH_MAX]; - - - /* Figure out whether filename is absolute or not */ - if (filename[0] == '/') { - /* We have absolute pathname */ - snprintf(absolute_path, sizeof(absolute_path), "%s", filename); - } else { - /* We have a relative pathname, compose the absolute pathname */ - snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); - rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); - if (rc < 0) - return rc; - /* readlink does not null terminate our string */ - readlink_cwd[rc] = '\0'; - - if (filename[0] == '.' && filename[1] == '/') - str_offset = 2; - - snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, - filename + str_offset); - } - - 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(filename); - handle->cb = cb; - handle->dir_filename = NULL; - - uv__io_start(handle->loop, &handle->event_watcher, POLLIN); - - return 0; -#else - return UV_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 UV_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) { - char** new_argv; - size_t size; - char* s; - int i; - - if (argc <= 0) - return argv; - - /* Save the original pointer to argv. - * AIX uses argv to read the process name. - * (Not the memory pointed to by argv[0..n] as on Linux.) - */ - process_argv = argv; - process_argc = argc; - - /* Calculate how much memory we need for the argv strings. */ - size = 0; - for (i = 0; i < argc; i++) - size += strlen(argv[i]) + 1; - - /* 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) { - char* new_title; - - /* We cannot free this pointer when libuv shuts down, - * the process may still be using it. - */ - new_title = uv__strdup(title); - if (new_title == NULL) - return UV_ENOMEM; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - /* If this is the first time this is set, - * don't free and set argv[1] to NULL. - */ - if (process_title_ptr != NULL) - uv__free(process_title_ptr); - - process_title_ptr = new_title; - - process_argv[0] = process_title_ptr; - if (process_argc > 1) - process_argv[1] = NULL; - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - len = strlen(process_argv[0]); - if (buffer == NULL || size == 0) - return UV_EINVAL; - else if (size <= len) - return UV_ENOBUFS; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - memcpy(buffer, process_argv[0], len + 1); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -UV_DESTRUCTOR(static void free_args_mem(void)) { - uv__free(args_mem); /* Keep valgrind happy. */ - args_mem = NULL; -} - - -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 UV__ERR(errno); - - /* FIXME(bnoordhuis) Handle EINTR. */ - err = UV_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; - - boot_time = 0; - 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 UV_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 UV_ENOSYS; - } - - ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); - if (result == -1) { - return UV_ENOSYS; - } - - ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); - if (!ps_cpus) { - return UV_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 UV_ENOSYS; - } - - *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); - if (!*cpu_infos) { - uv__free(ps_cpus); - return UV_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__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/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c deleted file mode 100644 index bf30b141..00000000 --- a/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c +++ /dev/null @@ -1,710 +0,0 @@ -/* -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 -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct NetlinkList -{ - struct NetlinkList *m_next; - struct nlmsghdr *m_data; - unsigned int m_size; -} NetlinkList; - -static int netlink_socket(pid_t *p_pid) -{ - struct sockaddr_nl l_addr; - socklen_t l_len; - - 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; - } - - l_len = sizeof(l_addr); - if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) - { - close(l_socket); - return -1; - } - *p_pid = l_addr.nl_pid; - - 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, pid_t p_pid, 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) - { - 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 != p_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, pid_t p_pid) -{ - 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, p_pid, &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 = IFA_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_rtaDataSize + 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 = IFA_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); - unsigned 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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) -{ - - int l_numLinks = 0; - 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 != p_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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) -{ - 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 != p_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; - pid_t l_pid; - NetlinkList *l_linkResults; - NetlinkList *l_addrResults; - - if(!ifap) - { - return -1; - } - *ifap = NULL; - - l_socket = netlink_socket(&l_pid); - if(l_socket < 0) - { - return -1; - } - - l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); - if(!l_linkResults) - { - close(l_socket); - return -1; - } - - l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); - if(!l_addrResults) - { - close(l_socket); - freeResultList(l_linkResults); - return -1; - } - - l_result = 0; - l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); - if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, 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/3rd/libuv-1.19.2/src/unix/async.c b/3rd/libuv-1.19.2/src/unix/async.c deleted file mode 100644 index 0b450ae0..00000000 --- a/3rd/libuv-1.19.2/src/unix/async.c +++ /dev/null @@ -1,269 +0,0 @@ -/* 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 -#include /* snprintf() */ -#include -#include -#include -#include - -static void uv__async_send(uv_loop_t* loop); -static int uv__async_start(uv_loop_t* loop); -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); - 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); - - return 0; -} - - -void uv__async_close(uv_async_t* handle) { - QUEUE_REMOVE(&handle->queue); - uv__handle_stop(handle); -} - - -static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - char buf[1024]; - ssize_t r; - QUEUE queue; - QUEUE* q; - uv_async_t* h; - - assert(w == &loop->async_io_watcher); - - for (;;) { - r = read(w->fd, buf, sizeof(buf)); - - if (r == sizeof(buf)) - continue; - - if (r != -1) - break; - - if (errno == EAGAIN || errno == EWOULDBLOCK) - break; - - if (errno == EINTR) - continue; - - abort(); - } - - 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_send(uv_loop_t* loop) { - const void* buf; - ssize_t len; - int fd; - int r; - - buf = ""; - len = 1; - fd = loop->async_wfd; - -#if defined(__linux__) - if (fd == -1) { - static const uint64_t val = 1; - buf = &val; - len = sizeof(val); - fd = loop->async_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(); -} - - -static int uv__async_start(uv_loop_t* loop) { - int pipefd[2]; - int err; - - if (loop->async_io_watcher.fd != -1) - return 0; - - err = uv__async_eventfd(); - if (err >= 0) { - pipefd[0] = err; - pipefd[1] = -1; - } - else if (err == UV_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(&loop->async_io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &loop->async_io_watcher, POLLIN); - loop->async_wfd = pipefd[1]; - - return 0; -} - - -int uv__async_fork(uv_loop_t* loop) { - if (loop->async_io_watcher.fd == -1) /* never started */ - return 0; - - uv__async_stop(loop); - - return uv__async_start(loop); -} - - -void uv__async_stop(uv_loop_t* loop) { - if (loop->async_io_watcher.fd == -1) - return; - - if (loop->async_wfd != -1) { - if (loop->async_wfd != loop->async_io_watcher.fd) - uv__close(loop->async_wfd); - loop->async_wfd = -1; - } - - uv__io_stop(loop, &loop->async_io_watcher, POLLIN); - uv__close(loop->async_io_watcher.fd); - loop->async_io_watcher.fd = -1; -} - - -static int uv__async_eventfd(void) { -#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 UV__ERR(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 UV__ERR(errno); - - no_eventfd = 1; - -skip_eventfd: - -#endif - - return UV_ENOSYS; -} diff --git a/3rd/libuv-1.19.2/src/unix/atomic-ops.h b/3rd/libuv-1.19.2/src/unix/atomic-ops.h deleted file mode 100644 index 7cac1f98..00000000 --- a/3rd/libuv-1.19.2/src/unix/atomic-ops.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * 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 -#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; -#elif defined(__MVS__) - unsigned int op4; - if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, - (unsigned int*) ptr, *ptr, &op4)) - return oldval; - else - return op4; -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_uint(ptr, oldval, newval); -#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; -#elif defined (__MVS__) -#ifdef _LP64 - unsigned long long op4; - if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, - (unsigned long long*) ptr, *ptr, &op4)) -#else - unsigned long op4; - if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, - (unsigned int*) ptr, *ptr, &op4)) -#endif - return oldval; - else - return op4; -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_ulong(ptr, oldval, newval); -#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/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c deleted file mode 100644 index 0d021544..00000000 --- a/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -#include -#include -#if !defined(__CYGWIN__) && !defined(__MSYS__) -#include -#endif - -static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; -#if !defined(__CYGWIN__) && !defined(__MSYS__) - /* - * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` - * equals to `AF_LINK` or not. Otherwise, the result depends on the operation - * system with `AF_LINK` or `PF_INET`. - */ - if (exclude_type == UV__EXCLUDE_IFPHYS) - return (ent->ifa_addr->sa_family != AF_LINK); -#endif -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) - /* - * On BSD getifaddrs returns information related to the raw underlying - * devices. We're not interested in this information. - */ - if (ent->ifa_addr->sa_family == AF_LINK) - return 1; -#elif defined(__NetBSD__) - if (ent->ifa_addr->sa_family != PF_INET && - ent->ifa_addr->sa_family != PF_INET6) - return 1; -#elif defined(__OpenBSD__) - if (ent->ifa_addr->sa_family != PF_INET) - return 1; -#endif - return 0; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs* addrs; - struct ifaddrs* ent; - uv_interface_address_t* address; - int i; - - if (getifaddrs(&addrs) != 0) - return UV__ERR(errno); - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - - if (*addresses == NULL) { - freeifaddrs(addrs); - return UV_ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) - 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) - continue; - - address = *addresses; - - for (i = 0; i < *count; i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { -#if defined(__CYGWIN__) || defined(__MSYS__) - memset(address->phys_addr, 0, sizeof(address->phys_addr)); -#else - struct sockaddr_dl* sa_addr; - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); -#endif - } - 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/3rd/libuv-1.19.2/src/unix/core.c b/3rd/libuv-1.19.2/src/unix/core.c deleted file mode 100644 index 3741c1d0..00000000 --- a/3rd/libuv-1.19.2/src/unix/core.c +++ /dev/null @@ -1,1355 +0,0 @@ -/* 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 /* NULL */ -#include /* printf */ -#include -#include /* strerror */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* INT_MAX, PATH_MAX, IOV_MAX */ -#include /* writev */ -#include /* getrusage */ -#include - -#ifdef __sun -# include /* MAXHOSTNAMELEN on Solaris */ -# include -# include -# include -#endif - -#ifdef __APPLE__ -# include /* _NSGetExecutablePath */ -# include -# if defined(O_CLOEXEC) -# define UV__O_CLOEXEC O_CLOEXEC -# endif -#endif - -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) -# include -# include -# include -# define UV__O_CLOEXEC O_CLOEXEC -# if defined(__FreeBSD__) && __FreeBSD__ >= 10 -# define uv__accept4 accept4 -# endif -# if defined(__NetBSD__) -# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) -# endif -# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) -# 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 - -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 -# include /* for dlsym */ -#endif - -#if defined(__MVS__) -#include -#endif - -#if !defined(__MVS__) -#include /* MAXHOSTNAMELEN on Linux and the BSDs */ -#endif - -/* Fallback for the maximum hostname length */ -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 -#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(!uv__is_closing(handle)); - - 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 UV_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 UV_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 UV__ERR(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 UV__ERR(errno); -#endif - - sockfd = socket(domain, type, protocol); - if (sockfd == -1) - return UV__ERR(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; -} - -/* get a file pointer to a file in read-only and close-on-exec mode */ -FILE* uv__open_file(const char* path) { - int fd; - FILE* fp; - - fd = uv__open_cloexec(path, O_RDONLY); - if (fd < 0) - return NULL; - - fp = fdopen(fd, "r"); - if (fp == NULL) - uv__close(fd); - - return fp; -} - - -int uv__accept(int sockfd) { - int peerfd; - int err; - - assert(sockfd >= 0); - - while (1) { -#if defined(__linux__) || \ - (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ - defined(__NetBSD__) - 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 UV__ERR(errno); - - no_accept4 = 1; -skip: -#endif - - peerfd = accept(sockfd, NULL, NULL); - if (peerfd == -1) { - if (errno == EINTR) - continue; - return UV__ERR(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_nocheckstdio(int fd) { - int saved_errno; - int rc; - - assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ - - saved_errno = errno; - rc = close(fd); - if (rc == -1) { - rc = UV__ERR(errno); - if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) - rc = 0; /* The close is in progress, not an error. */ - errno = saved_errno; - } - - return rc; -} - - -int uv__close(int fd) { - assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ -#if defined(__MVS__) - epoll_file_close(fd); -#endif - return uv__close_nocheckstdio(fd); -} - - -int uv__nonblock_ioctl(int fd, int set) { - int r; - - do - r = ioctl(fd, FIONBIO, &set); - while (r == -1 && errno == EINTR); - - if (r) - return UV__ERR(errno); - - return 0; -} - - -#if !defined(__CYGWIN__) && !defined(__MSYS__) -int uv__cloexec_ioctl(int fd, int set) { - int r; - - do - r = ioctl(fd, set ? FIOCLEX : FIONCLEX); - while (r == -1 && errno == EINTR); - - if (r) - return UV__ERR(errno); - - return 0; -} -#endif - - -int uv__nonblock_fcntl(int fd, int set) { - int flags; - int r; - - do - r = fcntl(fd, F_GETFL); - while (r == -1 && errno == EINTR); - - if (r == -1) - return UV__ERR(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 UV__ERR(errno); - - return 0; -} - - -int uv__cloexec_fcntl(int fd, int set) { - int flags; - int r; - - do - r = fcntl(fd, F_GETFD); - while (r == -1 && errno == EINTR); - - if (r == -1) - return UV__ERR(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 UV__ERR(errno); - - return 0; -} - - -/* 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 UV__ERR(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 UV__ERR(errno); - rc = recvmsg(fd, msg, flags); - if (rc == -1) - return UV__ERR(errno); - no_msg_cmsg_cloexec = 1; - } else { - rc = recvmsg(fd, msg, flags); - } -#else - rc = recvmsg(fd, msg, flags); -#endif - if (rc == -1) - return UV__ERR(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 UV_EINVAL; - - if (getcwd(buffer, *size) == NULL) - return UV__ERR(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 UV__ERR(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 UV_EINVAL; - } - - if (uv__is_closing(handle) || fd_out == -1) - return UV_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, 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); - 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) - 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); - 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, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); - assert(0 != events); - return 0 != (w->pevents & events); -} - - -int uv_getrusage(uv_rusage_t* rusage) { - struct rusage usage; - - if (getrusage(RUSAGE_SELF, &usage)) - return UV__ERR(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; - -#if !defined(__MVS__) - 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; -#endif - - return 0; -} - - -int uv__open_cloexec(const char* path, int flags) { - int err; - int fd; - -#if defined(UV__O_CLOEXEC) - static int no_cloexec; - - if (!no_cloexec) { - fd = open(path, flags | UV__O_CLOEXEC); - if (fd != -1) - return fd; - - if (errno != EINVAL) - return UV__ERR(errno); - - /* O_CLOEXEC not supported. */ - no_cloexec = 1; - } -#endif - - fd = open(path, flags); - if (fd == -1) - return UV__ERR(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) || defined(__NetBSD__) - r = dup3(oldfd, newfd, O_CLOEXEC); - if (r == -1) - return UV__ERR(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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); - - err = uv__cloexec(newfd, 1); - if (err) { - uv__close(newfd); - return err; - } - - return r; - } -} - - -int uv_os_homedir(char* buffer, size_t* size) { - uv_passwd_t pwd; - char* buf; - size_t len; - int r; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - /* Check if the HOME environment variable is set first */ - buf = getenv("HOME"); - - if (buf != NULL) { - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, buf, len + 1); - *size = len; - - return 0; - } - - /* HOME is not set, so call uv__getpwuid_r() */ - r = uv__getpwuid_r(&pwd); - - if (r != 0) { - return r; - } - - len = strlen(pwd.homedir); - - if (len >= *size) { - *size = len + 1; - uv_os_free_passwd(&pwd); - return UV_ENOBUFS; - } - - memcpy(buffer, pwd.homedir, len + 1); - *size = len; - uv_os_free_passwd(&pwd); - - return 0; -} - - -int uv_os_tmpdir(char* buffer, size_t* size) { - const char* buf; - size_t len; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - -#define CHECK_ENV_VAR(name) \ - do { \ - buf = getenv(name); \ - if (buf != NULL) \ - goto return_buffer; \ - } \ - while (0) - - /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ - CHECK_ENV_VAR("TMPDIR"); - CHECK_ENV_VAR("TMP"); - CHECK_ENV_VAR("TEMP"); - CHECK_ENV_VAR("TEMPDIR"); - -#undef CHECK_ENV_VAR - - /* No temp environment variables defined */ - #if defined(__ANDROID__) - buf = "/data/local/tmp"; - #else - buf = "/tmp"; - #endif - -return_buffer: - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - /* The returned directory should not have a trailing slash. */ - if (len > 1 && buf[len - 1] == '/') { - len--; - } - - memcpy(buffer, buf, len + 1); - buffer[len] = '\0'; - *size = len; - - return 0; -} - - -int uv__getpwuid_r(uv_passwd_t* pwd) { - struct passwd pw; - struct passwd* result; - char* buf; - uid_t uid; - size_t bufsize; - size_t name_size; - size_t homedir_size; - size_t shell_size; - long initsize; - int r; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); - - getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); - if (getpwuid_r == NULL) - return UV_ENOSYS; -#endif - - if (pwd == NULL) - return UV_EINVAL; - - initsize = sysconf(_SC_GETPW_R_SIZE_MAX); - - if (initsize <= 0) - bufsize = 4096; - else - bufsize = (size_t) initsize; - - uid = geteuid(); - buf = NULL; - - for (;;) { - uv__free(buf); - buf = uv__malloc(bufsize); - - if (buf == NULL) - return UV_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 UV_ENOENT; - } - - /* Allocate memory for the username, shell, and home directory */ - name_size = strlen(pw.pw_name) + 1; - homedir_size = strlen(pw.pw_dir) + 1; - shell_size = strlen(pw.pw_shell) + 1; - pwd->username = uv__malloc(name_size + homedir_size + shell_size); - - if (pwd->username == NULL) { - uv__free(buf); - return UV_ENOMEM; - } - - /* Copy the username */ - memcpy(pwd->username, pw.pw_name, name_size); - - /* Copy the home directory */ - pwd->homedir = pwd->username + name_size; - memcpy(pwd->homedir, pw.pw_dir, homedir_size); - - /* Copy the shell */ - pwd->shell = pwd->homedir + homedir_size; - memcpy(pwd->shell, pw.pw_shell, shell_size); - - /* Copy the uid and gid */ - pwd->uid = pw.pw_uid; - pwd->gid = pw.pw_gid; - - uv__free(buf); - - return 0; -} - - -void uv_os_free_passwd(uv_passwd_t* pwd) { - if (pwd == NULL) - return; - - /* - The memory for name, shell, and homedir are allocated in a single - uv__malloc() call. The base of the pointer is stored in pwd->username, so - that is the field that needs to be freed. - */ - uv__free(pwd->username); - pwd->username = NULL; - pwd->shell = NULL; - pwd->homedir = NULL; -} - - -int uv_os_get_passwd(uv_passwd_t* pwd) { - return uv__getpwuid_r(pwd); -} - - -int uv_translate_sys_error(int sys_errno) { - /* If < 0 then it's already a libuv error. */ - return sys_errno <= 0 ? sys_errno : -sys_errno; -} - - -int uv_os_getenv(const char* name, char* buffer, size_t* size) { - char* var; - size_t len; - - if (name == NULL || buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - var = getenv(name); - - if (var == NULL) - return UV_ENOENT; - - len = strlen(var); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, var, len + 1); - *size = len; - - return 0; -} - - -int uv_os_setenv(const char* name, const char* value) { - if (name == NULL || value == NULL) - return UV_EINVAL; - - if (setenv(name, value, 1) != 0) - return UV__ERR(errno); - - return 0; -} - - -int uv_os_unsetenv(const char* name) { - if (name == NULL) - return UV_EINVAL; - - if (unsetenv(name) != 0) - return UV__ERR(errno); - - return 0; -} - - -int uv_os_gethostname(char* buffer, size_t* size) { - /* - On some platforms, if the input buffer is not large enough, gethostname() - succeeds, but truncates the result. libuv can detect this and return ENOBUFS - instead by creating a large enough buffer and comparing the hostname length - to the size input. - */ - char buf[MAXHOSTNAMELEN + 1]; - size_t len; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - if (gethostname(buf, sizeof(buf)) != 0) - return UV__ERR(errno); - - buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, buf, len + 1); - *size = len; - return 0; -} - - -uv_os_fd_t uv_get_osfhandle(int fd) { - return fd; -} - - -uv_pid_t uv_os_getpid(void) { - return getpid(); -} - - -uv_pid_t uv_os_getppid(void) { - return getppid(); -} diff --git a/3rd/libuv-1.19.2/src/unix/cygwin.c b/3rd/libuv-1.19.2/src/unix/cygwin.c deleted file mode 100644 index 9fe4093e..00000000 --- a/3rd/libuv-1.19.2/src/unix/cygwin.c +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -int uv_uptime(double* uptime) { - struct sysinfo info; - - if (sysinfo(&info) < 0) - return UV__ERR(errno); - - *uptime = info.uptime; - return 0; -} - -int uv_resident_set_memory(size_t* rss) { - /* FIXME: read /proc/meminfo? */ - *rss = 0; - return UV_ENOSYS; -} - -int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - /* FIXME: read /proc/stat? */ - *cpu_infos = NULL; - *count = 0; - return UV_ENOSYS; -} - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - (void)cpu_infos; - (void)count; -} diff --git a/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c b/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c deleted file mode 100644 index dabde223..00000000 --- a/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c +++ /dev/null @@ -1,209 +0,0 @@ -/* 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 -#include -#include -#include - -#include - -#if !TARGET_OS_IPHONE -# include -# include -#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 UV_ENOSYS; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - - err = dynamic_pthread_setname_np(namebuf); - if (err) - return UV__ERR(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 = UV_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 = UV_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 = UV_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/3rd/libuv-1.19.2/src/unix/darwin.c b/3rd/libuv-1.19.2/src/unix/darwin.c deleted file mode 100644 index 31ad8a9e..00000000 --- a/3rd/libuv-1.19.2/src/unix/darwin.c +++ /dev/null @@ -1,231 +0,0 @@ -/* 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 -#include -#include - -#include -#include -#include /* _NSGetExecutablePath */ -#include -#include -#include /* sysconf */ - - -int uv__platform_loop_init(uv_loop_t* loop) { - loop->cf_state = NULL; - - if (uv__kqueue_init(loop)) - return UV__ERR(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 UV_EINVAL; - - exepath_size = sizeof(exepath); - if (_NSGetExecutablePath(exepath, &exepath_size)) - return UV_EIO; - - if (realpath(exepath, abspath) != abspath) - return UV__ERR(errno); - - abspath_size = strlen(abspath); - if (abspath_size == 0) - return UV_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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); - } - - size = sizeof(cpuspeed); - if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) - return UV__ERR(errno); - - if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, - (processor_info_array_t*)&info, - &msg_type) != KERN_SUCCESS) { - return UV_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 UV_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); -} diff --git a/3rd/libuv-1.19.2/src/unix/dl.c b/3rd/libuv-1.19.2/src/unix/dl.c deleted file mode 100644 index fc1c052b..00000000 --- a/3rd/libuv-1.19.2/src/unix/dl.c +++ /dev/null @@ -1,80 +0,0 @@ -/* 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 -#include -#include -#include - -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/3rd/libuv-1.19.2/src/unix/freebsd.c b/3rd/libuv-1.19.2/src/unix/freebsd.c deleted file mode 100644 index 70ccb130..00000000 --- a/3rd/libuv-1.19.2/src/unix/freebsd.c +++ /dev/null @@ -1,375 +0,0 @@ -/* 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 -#include -#include - -#include -#include -#include -#include -#include -#include /* VM_LOADAVG */ -#include -#include -#include /* sysconf */ -#include - -#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 uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - -int uv__platform_loop_init(uv_loop_t* loop) { - return uv__kqueue_init(loop); -} - - -void uv__platform_loop_delete(uv_loop_t* loop) { -} - - -#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 UV_EINVAL; - - abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); - if (abspath_size < 0) - return UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(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]; - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_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); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\0'; - - return 0; -} - -int uv_resident_set_memory(size_t* rss) { - struct kinfo_proc kinfo; - size_t page_size; - size_t kinfo_size; - int mib[4]; - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - kinfo_size = sizeof(kinfo); - - if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) - return UV__ERR(errno); - - page_size = getpagesize(); - -#ifdef __DragonFly__ - *rss = kinfo.kp_vm_rssize * page_size; -#else - *rss = kinfo.ki_rssize * page_size; -#endif - - return 0; -} - - -int uv_uptime(double* uptime) { - int r; - struct timespec sp; - r = clock_gettime(CLOCK_MONOTONIC, &sp); - if (r) - return UV__ERR(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; - const char* model_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 - -#if defined(__arm__) || defined(__aarch64__) - /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ - model_key = "hw.machine"; - cpuspeed = 0; -#else - model_key = "hw.model"; - - size = sizeof(cpuspeed); - if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) - return -errno; -#endif - - size = sizeof(model); - if (sysctlbyname(model_key, &model, &size, NULL, 0)) - return UV__ERR(errno); - - size = sizeof(numcpus); - if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return UV__ERR(errno); - - *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); - if (!(*cpu_infos)) - return UV_ENOMEM; - - *count = numcpus; - - /* 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)) { - uv__free(*cpu_infos); - return UV__ERR(errno); - } - - size = maxcpus * CPUSTATES * sizeof(long); - - cp_times = uv__malloc(size); - if (cp_times == NULL) { - uv__free(*cpu_infos); - return UV_ENOMEM; - } - - if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { - uv__free(cp_times); - uv__free(*cpu_infos); - return UV__ERR(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); -} diff --git a/3rd/libuv-1.19.2/src/unix/fs.c b/3rd/libuv-1.19.2/src/unix/fs.c deleted file mode 100644 index 92e2d255..00000000 --- a/3rd/libuv-1.19.2/src/unix/fs.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* 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 -#include -#include -#include -#include /* PATH_MAX */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel_) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# define HAVE_PREADV 1 -#else -# define HAVE_PREADV 0 -#endif - -#if defined(__linux__) || defined(__sun) -# include -#endif - -#if defined(__APPLE__) -# include -#endif - -#define INIT(subtype) \ - do { \ - if (req == NULL) \ - return UV_EINVAL; \ - UV_REQ_INIT(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->bufs = 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) \ - return UV_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) \ - return UV_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__req_register(loop, req); \ - 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_fsync(uv_fs_t* req) { -#if defined(__APPLE__) - /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache - * to the drive platters. This is in contrast to Linux's fdatasync and fsync - * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent - * for flushing buffered data to permanent storage. If F_FULLFSYNC is not - * supported by the file system we should fall back to fsync(). This is the - * same approach taken by sqlite. - */ - int r; - - r = fcntl(req->file, F_FULLFSYNC); - if (r != 0 && errno == ENOTTY) - r = fsync(req->file); - return r; -#else - return fsync(req->file); -#endif -} - - -static ssize_t uv__fs_fdatasync(uv_fs_t* req) { -#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) - return fdatasync(req->file); -#elif defined(__APPLE__) - /* See the comment in uv__fs_fsync. */ - return uv__fs_fsync(req); -#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 = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(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 = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(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(__FreeBSD_kernel__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) \ - || defined(__sun) - struct timeval tv[2]; - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif -#elif defined(_AIX71) - struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - return futimens(req->file, ts); -#elif defined(__MVS__) - attrib_t atr; - memset(&atr, 0, sizeof(atr)); - atr.att_mtimechg = 1; - atr.att_atimechg = 1; - atr.att_mtime = req->mtime; - atr.att_atime = req->atime; - return __fchattr(req->file, &atr, sizeof(atr)); -#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) - 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(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) -#define UV_CONST_DIRENT uv__dirent_t -#else -#define UV_CONST_DIRENT const uv__dirent_t -#endif - - -static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) { - return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; -} - - -static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { - return strcmp((*a)->d_name, (*b)->d_name); -} - - -static ssize_t uv__fs_scandir(uv_fs_t* req) { - uv__dirent_t **dents; - int n; - - dents = NULL; - n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort); - - /* NOTE: We will use nbufs as an index field */ - req->nbufs = 0; - - if (n == 0) { - /* OS X still needs to deallocate some memory. - * Memory was allocated using the system allocator, so use free() here. - */ - free(dents); - dents = NULL; - } else if (n == -1) { - return n; - } - - req->ptr = dents; - - 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 -#error "PATH_MAX undefined in the current platform" -#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; - } - -#if defined(__MVS__) - len = os390_readlink(req->path, buf, len); -#else - len = readlink(req->path, buf, len); -#endif - - - 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(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) - { - 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); -#elif defined(__FreeBSD_kernel__) - len = 0; - r = bsd_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 ssize_t uv__fs_copyfile(uv_fs_t* req) { -#if defined(__APPLE__) && !TARGET_OS_IPHONE - /* On macOS, use the native copyfile(3). */ - copyfile_flags_t flags; - - flags = COPYFILE_ALL; - - if (req->flags & UV_FS_COPYFILE_EXCL) - flags |= COPYFILE_EXCL; - - return copyfile(req->path, req->new_path, NULL, flags); -#else - uv_fs_t fs_req; - uv_file srcfd; - uv_file dstfd; - struct stat statsbuf; - int dst_flags; - int result; - int err; - size_t bytes_to_send; - int64_t in_offset; - - dstfd = -1; - err = 0; - - /* Open the source file. */ - srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); - uv_fs_req_cleanup(&fs_req); - - if (srcfd < 0) - return srcfd; - - /* Get the source file's mode. */ - if (fstat(srcfd, &statsbuf)) { - err = UV__ERR(errno); - goto out; - } - - dst_flags = O_WRONLY | O_CREAT | O_TRUNC; - - if (req->flags & UV_FS_COPYFILE_EXCL) - dst_flags |= O_EXCL; - - /* Open the destination file. */ - dstfd = uv_fs_open(NULL, - &fs_req, - req->new_path, - dst_flags, - statsbuf.st_mode, - NULL); - uv_fs_req_cleanup(&fs_req); - - if (dstfd < 0) { - err = dstfd; - goto out; - } - - if (fchmod(dstfd, statsbuf.st_mode) == -1) { - err = UV__ERR(errno); - goto out; - } - - bytes_to_send = statsbuf.st_size; - in_offset = 0; - while (bytes_to_send != 0) { - err = uv_fs_sendfile(NULL, - &fs_req, - dstfd, - srcfd, - in_offset, - bytes_to_send, - NULL); - uv_fs_req_cleanup(&fs_req); - if (err < 0) - break; - bytes_to_send -= fs_req.result; - in_offset += fs_req.result; - } - -out: - if (err < 0) - result = err; - else - result = 0; - - /* Close the source file. */ - err = uv__close_nocheckstdio(srcfd); - - /* Don't overwrite any existing errors. */ - if (err != 0 && result == 0) - result = err; - - /* Close the destination file if it is open. */ - if (dstfd >= 0) { - err = uv__close_nocheckstdio(dstfd); - - /* Don't overwrite any existing errors. */ - if (err != 0 && result == 0) - result = err; - - /* Remove the destination file if something went wrong. */ - if (result != 0) { - uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); - /* Ignore the unlink return value, as an error already happened. */ - uv_fs_req_cleanup(&fs_req); - } - } - - return result; -#endif -} - -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_atimensec; - dst->st_mtim.tv_sec = src->st_mtime; - dst->st_mtim.tv_nsec = src->st_mtimensec; - dst->st_ctim.tv_sec = src->st_ctime; - dst->st_ctim.tv_nsec = src->st_ctimensec; - dst->st_birthtim.tv_sec = src->st_ctime; - dst->st_birthtim.tv_nsec = src->st_ctimensec; - dst->st_flags = 0; - dst->st_gen = 0; -#elif !defined(_AIX) && ( \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) || \ - defined(_GNU_SOURCE) || \ - 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(__FreeBSD__) || \ - 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); - if (ret == 0) - 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); - if (ret == 0) - 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); - if (ret == 0) - 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 (errno == EINTR && total == -1) - return total; - - if (bufs != req->bufsml) - uv__free(bufs); - - req->bufs = NULL; - req->nbufs = 0; - - 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(COPYFILE, uv__fs_copyfile(req)); - 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, uv__fs_fsync(req)); - 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 = UV__ERR(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 == UV_ECANCELED) { - assert(req->result == 0); - req->result = UV_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) - return UV_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) { - INIT(READ); - - if (bufs == NULL || nbufs == 0) - return UV_EINVAL; - - 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) - return UV_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) { - INIT(WRITE); - - if (bufs == NULL || nbufs == 0) - return UV_EINVAL; - - 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) - return UV_ENOMEM; - - memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); - - req->off = off; - POST; -} - - -void uv_fs_req_cleanup(uv_fs_t* req) { - if (req == NULL) - return; - - /* 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->bufs != req->bufsml) - uv__free(req->bufs); - req->bufs = NULL; - - if (req->ptr != &req->statbuf) - uv__free(req->ptr); - req->ptr = NULL; -} - - -int uv_fs_copyfile(uv_loop_t* loop, - uv_fs_t* req, - const char* path, - const char* new_path, - int flags, - uv_fs_cb cb) { - INIT(COPYFILE); - - if (flags & ~UV_FS_COPYFILE_EXCL) - return UV_EINVAL; - - PATH2; - req->flags = flags; - POST; -} diff --git a/3rd/libuv-1.19.2/src/unix/fsevents.c b/3rd/libuv-1.19.2/src/unix/fsevents.c deleted file mode 100644 index 47d8024b..00000000 --- a/3rd/libuv-1.19.2/src/unix/fsevents.c +++ /dev/null @@ -1,919 +0,0 @@ -/* 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 -#include -#include -#include - -#include -#include - -/* 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; - FSEventStreamEventFlags flags; - 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++) { - flags = eventFlags[i]; - - /* Ignore system events */ - if (flags & 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; -#else - if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) - 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); - event->events = UV_RENAME; - -#ifdef MAC_OS_X_VERSION_10_7 - if (0 != (flags & kFSEventsModified) && - 0 == (flags & kFSEventsRenamed)) { - event->events = UV_CHANGE; - } -#else - if (0 != (flags & kFSEventsModified) && - 0 != (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; - } - if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; - } -#endif /* MAC_OS_X_VERSION_10_7 */ - - 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 UV_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; - - /* 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 = UV_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 = UV_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 = UV_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 = UV_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 UV_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 = UV_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 = UV__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 UV_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 UV__ERR(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 = UV_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 UV_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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/getaddrinfo.c b/3rd/libuv-1.19.2/src/unix/getaddrinfo.c deleted file mode 100644 index 10e8afd7..00000000 --- a/3rd/libuv-1.19.2/src/unix/getaddrinfo.c +++ /dev/null @@ -1,232 +0,0 @@ -/* 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 -#include /* NULL */ -#include -#include -#include /* if_indextoname() */ - -/* EAI_* constants. */ -#include - - -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 UV__ERR(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 == UV_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 UV_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 UV_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); -} - - -int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { - char ifname_buf[UV_IF_NAMESIZE]; - size_t len; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - if (if_indextoname(ifindex, ifname_buf) == NULL) - return UV__ERR(errno); - - len = strnlen(ifname_buf, sizeof(ifname_buf)); - - if (*size <= len) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, ifname_buf, len); - buffer[len] = '\0'; - *size = len; - - return 0; -} - -int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { - return uv_if_indextoname(ifindex, buffer, size); -} diff --git a/3rd/libuv-1.19.2/src/unix/getnameinfo.c b/3rd/libuv-1.19.2/src/unix/getnameinfo.c deleted file mode 100644 index 9a436722..00000000 --- a/3rd/libuv-1.19.2/src/unix/getnameinfo.c +++ /dev/null @@ -1,120 +0,0 @@ -/* 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 -#include -#include -#include - -#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 == 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_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/3rd/libuv-1.19.2/src/unix/ibmi.c b/3rd/libuv-1.19.2/src/unix/ibmi.c deleted file mode 100644 index c50a4e76..00000000 --- a/3rd/libuv-1.19.2/src/unix/ibmi.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -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]) { - avg[0] = avg[1] = avg[2] = 0; - return; -} - - -int uv_resident_set_memory(size_t* rss) { - return UV_ENOSYS; -} - - -int uv_uptime(double* uptime) { - return UV_ENOSYS; -} - - -int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - unsigned int numcpus, idx = 0; - uv_cpu_info_t* cpu_info; - - *cpu_infos = NULL; - *count = 0; - - numcpus = sysconf(_SC_NPROCESSORS_ONLN); - - *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); - if (!*cpu_infos) { - return UV_ENOMEM; - } - - cpu_info = *cpu_infos; - for (idx = 0; idx < numcpus; idx++) { - cpu_info->speed = 0; - cpu_info->model = uv__strdup("unknown"); - cpu_info->cpu_times.user = 0; - cpu_info->cpu_times.sys = 0; - cpu_info->cpu_times.idle = 0; - cpu_info->cpu_times.irq = 0; - cpu_info->cpu_times.nice = 0; - cpu_info++; - } - *count = numcpus; - - return 0; -} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/internal.h b/3rd/libuv-1.19.2/src/unix/internal.h deleted file mode 100644 index 2bb3773c..00000000 --- a/3rd/libuv-1.19.2/src/unix/internal.h +++ /dev/null @@ -1,340 +0,0 @@ -/* 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 -#include /* abort */ -#include /* strrchr */ -#include /* O_CLOEXEC, may be */ -#include -#include - -#if defined(__STRICT_ANSI__) -# define inline __inline -#endif - -#if defined(__linux__) -# include "linux-syscalls.h" -#endif /* __linux__ */ - -#if defined(__MVS__) -# include "os390-syscalls.h" -#endif /* __MVS__ */ - -#if defined(__sun) -# include -# include -#endif /* __sun */ - -#if defined(_AIX) -# define reqevents events -# define rtnevents revents -# include -#else -# include -#endif /* _AIX */ - -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include -#endif - -#if defined(__ANDROID__) -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 - -#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 - -/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ -#ifdef POLLRDHUP -# define UV__POLLRDHUP POLLRDHUP -#else -# define UV__POLLRDHUP 0x2000 -#endif - -#ifdef POLLPRI -# define UV__POLLPRI POLLPRI -#else -# define UV__POLLPRI 0 -#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. */ - UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ -}; - -/* loop flags */ -enum { - UV_LOOP_BLOCK_SIGPROF = 1 -}; - -/* flags of excluding ifaddr */ -enum { - UV__EXCLUDE_IFPHYS, - UV__EXCLUDE_IFADDR -}; - -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]; -}; - - -#if defined(_AIX) || \ - defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__linux__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -#define uv__cloexec uv__cloexec_ioctl -#define uv__nonblock uv__nonblock_ioctl -#else -#define uv__cloexec uv__cloexec_fcntl -#define uv__nonblock uv__nonblock_fcntl -#endif - -/* core */ -int uv__cloexec_ioctl(int fd, int set); -int uv__cloexec_fcntl(int fd, int set); -int uv__nonblock_ioctl(int fd, int set); -int uv__nonblock_fcntl(int fd, int set); -int uv__close(int fd); -int uv__close_nocheckstdio(int fd); -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); -int uv__io_check_fd(uv_loop_t* loop, int fd); -void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ -int uv__io_fork(uv_loop_t* loop); - -/* async */ -void uv__async_stop(uv_loop_t* loop); -int uv__async_fork(uv_loop_t* loop); - - -/* 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); -int uv__signal_loop_fork(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); -FILE* uv__open_file(const char* path); -int uv__getpwuid_r(uv_passwd_t* pwd); - - -#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__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; -} - -#if defined(__linux__) -int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); -#endif - -#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/kqueue.c b/3rd/libuv-1.19.2/src/unix/kqueue.c deleted file mode 100644 index a30fd730..00000000 --- a/3rd/libuv-1.19.2/src/unix/kqueue.c +++ /dev/null @@ -1,533 +0,0 @@ -/* 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * Required on - * - Until at least FreeBSD 11.0 - * - Older versions of Mac OS X - * - * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp - */ -#ifndef EV_OOBAND -#define EV_OOBAND EV_FLAG1 -#endif - -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 UV__ERR(errno); - - uv__cloexec(loop->backend_fd, 1); - - return 0; -} - - -#if defined(__APPLE__) -static int uv__has_forked_with_cfrunloop; -#endif - -int uv__io_fork(uv_loop_t* loop) { - int err; - loop->backend_fd = -1; - err = uv__kqueue_init(loop); - if (err) - return err; - -#if defined(__APPLE__) - if (loop->cf_state != NULL) { - /* We cannot start another CFRunloop and/or thread in the child - process; CF aborts if you try or if you try to touch the thread - at all to kill it. So the best we can do is ignore it from now - on. This means we can't watch directories in the same way - anymore (like other BSDs). It also means we cannot properly - clean up the allocated resources; calling - uv__fsevents_loop_delete from uv_loop_close will crash the - process. So we sidestep the issue by pretending like we never - started it in the first place. - */ - uv__has_forked_with_cfrunloop = 1; - uv__free(loop->cf_state); - loop->cf_state = NULL; - } -#endif - return err; -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct kevent ev; - int rc; - - rc = 0; - EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = UV__ERR(errno); - - EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - if (rc == 0) - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - abort(); - - return rc; -} - - -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 have_signals; - 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 & POLLIN) == 0 && (w->pevents & 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 & POLLOUT) == 0 && (w->pevents & 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; - } - } - - if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { - EV_SET(events + nevents, w->fd, EV_OOBAND, 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; - } - - have_signals = 0; - 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 == POLLIN); - assert(w->pevents == POLLIN); - w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ - nevents++; - continue; - } - - revents = 0; - - if (ev->filter == EVFILT_READ) { - if (w->pevents & POLLIN) { - revents |= 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 == EV_OOBAND) { - if (w->pevents & UV__POLLPRI) { - revents |= UV__POLLPRI; - 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 & POLLOUT) { - revents |= 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 |= POLLERR; - - if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) - revents |= UV__POLLRDHUP; - - if (revents == 0) - continue; - - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) - have_signals = 1; - else - w->cb(loop, w, revents); - - nevents++; - } - - if (have_signals != 0) - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - 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 UV_EINVAL; - - /* TODO open asynchronously - but how do we report back errors? */ - fd = open(path, O_RDONLY); - if (fd == -1) - return UV__ERR(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__) - if (uv__has_forked_with_cfrunloop) - goto fallback; - - /* 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, 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__has_forked_with_cfrunloop || 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/3rd/libuv-1.19.2/src/unix/linux-core.c b/3rd/libuv-1.19.2/src/unix/linux-core.c deleted file mode 100644 index b63c25f3..00000000 --- a/3rd/libuv-1.19.2/src/unix/linux-core.c +++ /dev/null @@ -1,951 +0,0 @@ -/* 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. - */ - -/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their - * EPOLL* counterparts. We use the POLL* variants in this file because that - * is what libuv uses elsewhere and it avoids a dependency on . - */ - -#include "uv.h" -#include "internal.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#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 -# endif -# include -# include -# include -#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 but we can't - * include that file because it conflicts with . 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(FILE* statfile_fp, - 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 UV__ERR(errno); - - return 0; -} - - -int uv__io_fork(uv_loop_t* loop) { - int err; - void* old_watchers; - - old_watchers = loop->inotify_watchers; - - uv__close(loop->backend_fd); - loop->backend_fd = -1; - uv__platform_loop_delete(loop); - - err = uv__platform_loop_init(loop); - if (err) - return err; - - return uv__inotify_fork(loop, old_watchers); -} - - -void uv__platform_loop_delete(uv_loop_t* loop) { - if (loop->inotify_fd == -1) return; - uv__io_stop(loop, &loop->inotify_read_watcher, 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); - } -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event e; - int rc; - - e.events = POLLIN; - e.data = -1; - - rc = 0; - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) - if (errno != EEXIST) - rc = UV__ERR(errno); - - if (rc == 0) - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) - abort(); - - return rc; -} - - -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 have_signals; - 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); - - if (timeout == 0) - return; - - /* We may have been inside the system call for longer than |timeout| - * milliseconds so we need to update the timestamp to avoid drift. - */ - goto update_timeout; - } - - 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; - } - - have_signals = 0; - 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 | POLLERR | 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 == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); - - if (pe->events != 0) { - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) - have_signals = 1; - else - w->cb(loop, w, pe->events); - - nevents++; - } - } - - if (have_signals != 0) - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - 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; -} - - -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 UV__ERR(errno); - - do - n = read(fd, buf, sizeof(buf) - 1); - while (n == -1 && errno == EINTR); - - uv__close(fd); - if (n == -1) - return UV__ERR(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 UV_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 UV__ERR(errno); - - *uptime = now.tv_sec; - return 0; -} - - -static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { - unsigned int num; - char buf[1024]; - - if (!fgets(buf, sizeof(buf), statfile_fp)) - return UV_EIO; - - num = 0; - while (fgets(buf, sizeof(buf), statfile_fp)) { - if (strncmp(buf, "cpu", 3)) - break; - num++; - } - - if (num == 0) - return UV_EIO; - - *numcpus = num; - return 0; -} - - -int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - unsigned int numcpus; - uv_cpu_info_t* ci; - int err; - FILE* statfile_fp; - - *cpu_infos = NULL; - *count = 0; - - statfile_fp = uv__open_file("/proc/stat"); - if (statfile_fp == NULL) - return UV__ERR(errno); - - err = uv__cpu_num(statfile_fp, &numcpus); - if (err < 0) - goto out; - - err = UV_ENOMEM; - ci = uv__calloc(numcpus, sizeof(*ci)); - if (ci == NULL) - goto out; - - err = read_models(numcpus, ci); - if (err == 0) - err = read_times(statfile_fp, numcpus, ci); - - if (err) { - uv_free_cpu_info(ci, numcpus); - goto out; - } - - /* 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; - err = 0; - -out: - - if (fclose(statfile_fp)) - if (errno != EINTR && errno != EINPROGRESS) - abort(); - - return err; -} - - -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 = uv__open_file("/proc/cpuinfo"); - if (fp == NULL) - return UV__ERR(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 UV_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 UV_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 UV_ENOMEM; - ci[model_idx++].model = model; - } - - return 0; -} - - -static int read_times(FILE* statfile_fp, - 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]; - - clock_ticks = sysconf(_SC_CLK_TCK); - assert(clock_ticks != (unsigned long) -1); - assert(clock_ticks != 0); - - rewind(statfile_fp); - - if (!fgets(buf, sizeof(buf), statfile_fp)) - abort(); - - num = 0; - - while (fgets(buf, sizeof(buf), statfile_fp)) { - if (num >= numcpus) - break; - - if (strncmp(buf, "cpu", 3)) - break; - - /* skip "cpu " 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; - } - 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 = uv__open_file(buf); - 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); -} - -static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - /* - * 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) - return exclude_type; - return !exclude_type; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { -#ifndef HAVE_IFADDRS_H - return UV_ENOSYS; -#else - struct ifaddrs *addrs, *ent; - uv_interface_address_t* address; - int i; - struct sockaddr_ll *sll; - - if (getifaddrs(&addrs)) - return UV__ERR(errno); - - *count = 0; - *addresses = NULL; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) - continue; - - (*count)++; - } - - if (*count == 0) - return 0; - - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { - freeifaddrs(addrs); - return UV_ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) - 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) - 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/3rd/libuv-1.19.2/src/unix/linux-inotify.c b/3rd/libuv-1.19.2/src/unix/linux-inotify.c deleted file mode 100644 index bcad630f..00000000 --- a/3rd/libuv-1.19.2/src/unix/linux-inotify.c +++ /dev/null @@ -1,352 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#include -#include - -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 void maybe_free_watcher_list(struct watcher_list* w, - uv_loop_t* loop); - -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 UV__ERR(errno); - - fd = uv__inotify_init(); - if (fd == -1) - return UV__ERR(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, POLLIN); - - return 0; -} - - -int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { - /* Open the inotify_fd, and re-arm all the inotify watchers. */ - int err; - struct watcher_list* tmp_watcher_list_iter; - struct watcher_list* watcher_list; - struct watcher_list tmp_watcher_list; - QUEUE queue; - QUEUE* q; - uv_fs_event_t* handle; - char* tmp_path; - - if (old_watchers != NULL) { - /* We must restore the old watcher list to be able to close items - * out of it. - */ - loop->inotify_watchers = old_watchers; - - QUEUE_INIT(&tmp_watcher_list.watchers); - /* Note that the queue we use is shared with the start and stop() - * functions, making QUEUE_FOREACH unsafe to use. So we use the - * QUEUE_MOVE trick to safely iterate. Also don't free the watcher - * list until we're done iterating. c.f. uv__inotify_read. - */ - RB_FOREACH_SAFE(watcher_list, watcher_root, - CAST(&old_watchers), tmp_watcher_list_iter) { - watcher_list->iterating = 1; - QUEUE_MOVE(&watcher_list->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - /* It's critical to keep a copy of path here, because it - * will be set to NULL by stop() and then deallocated by - * maybe_free_watcher_list - */ - tmp_path = uv__strdup(handle->path); - assert(tmp_path != NULL); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&watcher_list->watchers, q); - uv_fs_event_stop(handle); - - QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); - handle->path = tmp_path; - } - watcher_list->iterating = 0; - maybe_free_watcher_list(watcher_list, loop); - } - - QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - QUEUE_REMOVE(q); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - tmp_path = handle->path; - handle->path = NULL; - err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); - uv__free(tmp_path); - if (err) - return err; - } - } - - 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 UV_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 UV__ERR(errno); - - w = find_watcher(handle->loop, wd); - if (w) - goto no_insert; - - w = uv__malloc(sizeof(*w) + strlen(path) + 1); - if (w == NULL) - return UV_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/3rd/libuv-1.19.2/src/unix/linux-syscalls.c b/3rd/libuv-1.19.2/src/unix/linux-syscalls.c deleted file mode 100644 index 89998ded..00000000 --- a/3rd/libuv-1.19.2/src/unix/linux-syscalls.c +++ /dev/null @@ -1,471 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#if defined(__has_feature) -# if __has_feature(memory_sanitizer) -# define MSAN_ACTIVE 1 -# include -# 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/3rd/libuv-1.19.2/src/unix/linux-syscalls.h b/3rd/libuv-1.19.2/src/unix/linux-syscalls.h deleted file mode 100644 index 4c095e9b..00000000 --- a/3rd/libuv-1.19.2/src/unix/linux-syscalls.h +++ /dev/null @@ -1,151 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#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 - -/* 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/3rd/libuv-1.19.2/src/unix/loop-watcher.c b/3rd/libuv-1.19.2/src/unix/loop-watcher.c deleted file mode 100644 index b8c1c2a7..00000000 --- a/3rd/libuv-1.19.2/src/unix/loop-watcher.c +++ /dev/null @@ -1,68 +0,0 @@ -/* 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 UV_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/3rd/libuv-1.19.2/src/unix/loop.c b/3rd/libuv-1.19.2/src/unix/loop.c deleted file mode 100644 index 5b5b0e09..00000000 --- a/3rd/libuv-1.19.2/src/unix/loop.c +++ /dev/null @@ -1,193 +0,0 @@ -/* 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 -#include -#include - -int uv_loop_init(uv_loop_t* loop) { - void* saved_data; - int err; - - - saved_data = loop->data; - memset(loop, 0, sizeof(*loop)); - loop->data = saved_data; - - 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); - loop->async_io_watcher.fd = -1; - loop->async_wfd = -1; - 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; - - uv__signal_global_once_init(); - 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; -} - - -int uv_loop_fork(uv_loop_t* loop) { - int err; - unsigned int i; - uv__io_t* w; - - err = uv__io_fork(loop); - if (err) - return err; - - err = uv__async_fork(loop); - if (err) - return err; - - err = uv__signal_loop_fork(loop); - if (err) - return err; - - /* Rearm all the watchers that aren't re-queued by the above. */ - for (i = 0; i < loop->nwatchers; i++) { - w = loop->watchers[i]; - if (w == NULL) - continue; - - if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) { - w->events = 0; /* Force re-registration in uv__io_poll. */ - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); - } - } - - return 0; -} - - -void uv__loop_close(uv_loop_t* loop) { - uv__signal_loop_cleanup(loop); - uv__platform_loop_delete(loop); - uv__async_stop(loop); - - 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/3rd/libuv-1.19.2/src/unix/netbsd.c b/3rd/libuv-1.19.2/src/unix/netbsd.c deleted file mode 100644 index 2605c114..00000000 --- a/3rd/libuv-1.19.2/src/unix/netbsd.c +++ /dev/null @@ -1,309 +0,0 @@ -/* 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 -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - -int uv__platform_loop_init(uv_loop_t* loop) { - return uv__kqueue_init(loop); -} - - -void uv__platform_loop_delete(uv_loop_t* loop) { -} - - -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) { - /* Intermediate buffer, retrieving partial path name does not work - * As of NetBSD-8(beta), vnode->path translator does not handle files - * with longer names than 31 characters. - */ - char int_buf[PATH_MAX]; - size_t int_size; - int mib[4]; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC_ARGS; - mib[2] = -1; - mib[3] = KERN_PROC_PATHNAME; - int_size = ARRAY_SIZE(int_buf); - - if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) - return UV__ERR(errno); - - /* Copy string from the intermediate buffer to outer one with appropriate - * length. - */ - strlcpy(buffer, int_buf, *size); - - /* Set new size. */ - *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 UV__ERR(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 UV__ERR(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) { - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_title; - setproctitle("%s", title); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\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 UV_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 UV__ERR(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 UV__ERR(errno); - } - - size = sizeof(numcpus); - if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return UV__ERR(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 UV_ENOMEM; - - if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) - return UV__ERR(errno); - - *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); - if (!(*cpu_infos)) { - uv__free(cp_times); - uv__free(*cpu_infos); - return UV_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); -} diff --git a/3rd/libuv-1.19.2/src/unix/no-fsevents.c b/3rd/libuv-1.19.2/src/unix/no-fsevents.c deleted file mode 100644 index 158643af..00000000 --- a/3rd/libuv-1.19.2/src/unix/no-fsevents.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include - -int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return UV_ENOSYS; -} - -int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, unsigned int flags) { - return UV_ENOSYS; -} - -int uv_fs_event_stop(uv_fs_event_t* handle) { - return UV_ENOSYS; -} - -void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); -} diff --git a/3rd/libuv-1.19.2/src/unix/no-proctitle.c b/3rd/libuv-1.19.2/src/unix/no-proctitle.c deleted file mode 100644 index 165740ca..00000000 --- a/3rd/libuv-1.19.2/src/unix/no-proctitle.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -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 (buffer == NULL || size == 0) - return UV_EINVAL; - - buffer[0] = '\0'; - return 0; -} diff --git a/3rd/libuv-1.19.2/src/unix/openbsd.c b/3rd/libuv-1.19.2/src/unix/openbsd.c deleted file mode 100644 index ce937cd3..00000000 --- a/3rd/libuv-1.19.2/src/unix/openbsd.c +++ /dev/null @@ -1,313 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - -int uv__platform_loop_init(uv_loop_t* loop) { - return uv__kqueue_init(loop); -} - - -void uv__platform_loop_delete(uv_loop_t* loop) { -} - - -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 UV_EINVAL; - - mypid = getpid(); - for (;;) { - err = UV_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 = UV__ERR(errno); - goto out; - } - argsbuf_size *= 2U; - } - - if (argsbuf[0] == NULL) { - err = UV_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 UV__ERR(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 UV__ERR(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) { - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_title; - setproctitle("%s", title); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); - - which[1] = HW_NCPU; - size = sizeof(numcpus); - if (sysctl(which, 2, &numcpus, &size, NULL, 0)) - return UV__ERR(errno); - - *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); - if (!(*cpu_infos)) - return UV_ENOMEM; - - *count = numcpus; - - which[1] = HW_CPUSPEED; - size = sizeof(cpuspeed); - if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { - uv__free(*cpu_infos); - return UV__ERR(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)) { - uv__free(*cpu_infos); - return UV__ERR(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); -} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.c b/3rd/libuv-1.19.2/src/unix/os390-syscalls.c deleted file mode 100644 index 21558ea8..00000000 --- a/3rd/libuv-1.19.2/src/unix/os390-syscalls.c +++ /dev/null @@ -1,499 +0,0 @@ -/* Copyright 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. - */ - - -#include "os390-syscalls.h" -#include -#include -#include -#include -#include -#include - -#define CW_CONDVAR 32 - -#pragma linkage(BPX4CTW, OS) -#pragma linkage(BPX1CTW, OS) - -static int number_of_epolls; -static QUEUE global_epoll_queue; -static uv_mutex_t global_epoll_lock; -static uv_once_t once = UV_ONCE_INIT; - -int scandir(const char* maindir, struct dirent*** namelist, - int (*filter)(const struct dirent*), - int (*compar)(const struct dirent**, - const struct dirent **)) { - struct dirent** nl; - struct dirent* dirent; - unsigned count; - size_t allocated; - DIR* mdir; - - nl = NULL; - count = 0; - allocated = 0; - mdir = opendir(maindir); - if (!mdir) - return -1; - - while (1) { - dirent = readdir(mdir); - if (!dirent) - break; - if (!filter || filter(dirent)) { - struct dirent* copy; - copy = uv__malloc(sizeof(*copy)); - if (!copy) { - while (count) { - dirent = nl[--count]; - uv__free(dirent); - } - uv__free(nl); - closedir(mdir); - errno = ENOMEM; - return -1; - } - memcpy(copy, dirent, sizeof(*copy)); - - nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); - nl[count++] = copy; - } - } - - qsort(nl, count, sizeof(struct dirent *), - (int (*)(const void *, const void *)) compar); - - closedir(mdir); - - *namelist = nl; - return count; -} - - -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__os390_epoll* lst, unsigned int len) { - unsigned int newsize; - unsigned int i; - struct pollfd* newlst; - struct pollfd event; - - if (len <= lst->size) - return; - - if (lst->size == 0) - event.fd = -1; - else { - /* Extract the message queue at the end. */ - event = lst->items[lst->size - 1]; - lst->items[lst->size - 1].fd = -1; - } - - newsize = next_power_of_two(len); - newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); - - if (newlst == NULL) - abort(); - for (i = lst->size; i < newsize; ++i) - newlst[i].fd = -1; - - /* Restore the message queue at the end */ - newlst[newsize - 1] = event; - - lst->items = newlst; - lst->size = newsize; -} - - -static void init_message_queue(uv__os390_epoll* lst) { - struct { - long int header; - char body; - } msg; - - /* initialize message queue */ - lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); - if (lst->msg_queue == -1) - abort(); - - /* - On z/OS, the message queue will be affiliated with the process only - when a send is performed on it. Once this is done, the system - can be queried for all message queues belonging to our process id. - */ - msg.header = 1; - if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) - abort(); - - /* Clean up the dummy message sent above */ - if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) - abort(); -} - - -static void before_fork(void) { - uv_mutex_lock(&global_epoll_lock); -} - - -static void after_fork(void) { - uv_mutex_unlock(&global_epoll_lock); -} - - -static void child_fork(void) { - QUEUE* q; - uv_once_t child_once = UV_ONCE_INIT; - - /* reset once */ - memcpy(&once, &child_once, sizeof(child_once)); - - /* reset epoll list */ - while (!QUEUE_EMPTY(&global_epoll_queue)) { - uv__os390_epoll* lst; - q = QUEUE_HEAD(&global_epoll_queue); - QUEUE_REMOVE(q); - lst = QUEUE_DATA(q, uv__os390_epoll, member); - uv__free(lst->items); - lst->items = NULL; - lst->size = 0; - } - - uv_mutex_unlock(&global_epoll_lock); - uv_mutex_destroy(&global_epoll_lock); -} - - -static void epoll_init(void) { - QUEUE_INIT(&global_epoll_queue); - if (uv_mutex_init(&global_epoll_lock)) - abort(); - - if (pthread_atfork(&before_fork, &after_fork, &child_fork)) - abort(); -} - - -uv__os390_epoll* epoll_create1(int flags) { - uv__os390_epoll* lst; - - lst = uv__malloc(sizeof(*lst)); - if (lst != NULL) { - /* initialize list */ - lst->size = 0; - lst->items = NULL; - init_message_queue(lst); - maybe_resize(lst, 1); - lst->items[lst->size - 1].fd = lst->msg_queue; - lst->items[lst->size - 1].events = POLLIN; - uv_once(&once, epoll_init); - uv_mutex_lock(&global_epoll_lock); - QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); - uv_mutex_unlock(&global_epoll_lock); - } - - return lst; -} - - -int epoll_ctl(uv__os390_epoll* lst, - int op, - int fd, - struct epoll_event *event) { - uv_mutex_lock(&global_epoll_lock); - - if (op == EPOLL_CTL_DEL) { - if (fd >= lst->size || lst->items[fd].fd == -1) { - uv_mutex_unlock(&global_epoll_lock); - errno = ENOENT; - return -1; - } - lst->items[fd].fd = -1; - } else if (op == EPOLL_CTL_ADD) { - - /* Resizing to 'fd + 1' would expand the list to contain at least - * 'fd'. But we need to guarantee that the last index on the list - * is reserved for the message queue. So specify 'fd + 2' instead. - */ - maybe_resize(lst, fd + 2); - if (lst->items[fd].fd != -1) { - uv_mutex_unlock(&global_epoll_lock); - errno = EEXIST; - return -1; - } - lst->items[fd].fd = fd; - lst->items[fd].events = event->events; - } else if (op == EPOLL_CTL_MOD) { - if (fd >= lst->size || lst->items[fd].fd == -1) { - uv_mutex_unlock(&global_epoll_lock); - errno = ENOENT; - return -1; - } - lst->items[fd].events = event->events; - } else - abort(); - - uv_mutex_unlock(&global_epoll_lock); - return 0; -} - - -int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, - int maxevents, int timeout) { - nmsgsfds_t size; - struct pollfd* pfds; - int pollret; - int reventcount; - - size = _SET_FDS_MSGS(size, 1, lst->size - 1); - pfds = lst->items; - pollret = poll(pfds, size, timeout); - if (pollret <= 0) - return pollret; - - pollret = _NFDS(pollret) + _NMSGS(pollret); - - reventcount = 0; - for (int i = 0; - i < lst->size && i < maxevents && reventcount < pollret; ++i) { - struct epoll_event ev; - - if (pfds[i].fd == -1 || pfds[i].revents == 0) - continue; - - ev.fd = pfds[i].fd; - ev.events = pfds[i].revents; - events[reventcount++] = ev; - } - - return reventcount; -} - - -int epoll_file_close(int fd) { - QUEUE* q; - - uv_once(&once, epoll_init); - uv_mutex_lock(&global_epoll_lock); - QUEUE_FOREACH(q, &global_epoll_queue) { - uv__os390_epoll* lst; - - lst = QUEUE_DATA(q, uv__os390_epoll, member); - if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) - lst->items[fd].fd = -1; - } - - uv_mutex_unlock(&global_epoll_lock); - return 0; -} - -void epoll_queue_close(uv__os390_epoll* lst) { - /* Remove epoll instance from global queue */ - uv_mutex_lock(&global_epoll_lock); - QUEUE_REMOVE(&lst->member); - uv_mutex_unlock(&global_epoll_lock); - - /* Free resources */ - msgctl(lst->msg_queue, IPC_RMID, NULL); - lst->msg_queue = -1; - uv__free(lst->items); - lst->items = NULL; -} - - -int nanosleep(const struct timespec* req, struct timespec* rem) { - unsigned nano; - unsigned seconds; - unsigned events; - unsigned secrem; - unsigned nanorem; - int rv; - int rc; - int rsn; - - nano = (int)req->tv_nsec; - seconds = req->tv_sec; - events = CW_CONDVAR; - -#if defined(_LP64) - BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); -#else - BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); -#endif - - assert(rv == -1 && errno == EAGAIN); - - if(rem != NULL) { - rem->tv_nsec = nanorem; - rem->tv_sec = secrem; - } - - return 0; -} - - -char* mkdtemp(char* path) { - static const char* tempchars = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - static const size_t num_chars = 62; - static const size_t num_x = 6; - char *ep, *cp; - unsigned int tries, i; - size_t len; - uint64_t v; - int fd; - int retval; - int saved_errno; - - len = strlen(path); - ep = path + len; - if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { - errno = EINVAL; - return NULL; - } - - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - return NULL; - - tries = TMP_MAX; - retval = -1; - do { - if (read(fd, &v, sizeof(v)) != sizeof(v)) - break; - - cp = ep - num_x; - for (i = 0; i < num_x; i++) { - *cp++ = tempchars[v % num_chars]; - v /= num_chars; - } - - if (mkdir(path, S_IRWXU) == 0) { - retval = 0; - break; - } - else if (errno != EEXIST) - break; - } while (--tries); - - saved_errno = errno; - uv__close(fd); - if (tries == 0) { - errno = EEXIST; - return NULL; - } - - if (retval == -1) { - errno = saved_errno; - return NULL; - } - - return path; -} - - -ssize_t os390_readlink(const char* path, char* buf, size_t len) { - ssize_t rlen; - ssize_t vlen; - ssize_t plen; - char* delimiter; - char old_delim; - char* tmpbuf; - char realpathstr[PATH_MAX + 1]; - - tmpbuf = uv__malloc(len + 1); - if (tmpbuf == NULL) { - errno = ENOMEM; - return -1; - } - - rlen = readlink(path, tmpbuf, len); - if (rlen < 0) { - uv__free(tmpbuf); - return rlen; - } - - if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { - /* Straightforward readlink. */ - memcpy(buf, tmpbuf, rlen); - uv__free(tmpbuf); - return rlen; - } - - /* - * There is a parmlib variable at the beginning - * which needs interpretation. - */ - tmpbuf[rlen] = '\0'; - delimiter = strchr(tmpbuf + 2, '/'); - if (delimiter == NULL) - /* No slash at the end */ - delimiter = strchr(tmpbuf + 2, '\0'); - - /* Read real path of the variable. */ - old_delim = *delimiter; - *delimiter = '\0'; - if (realpath(tmpbuf, realpathstr) == NULL) { - uv__free(tmpbuf); - return -1; - } - - /* realpathstr is not guaranteed to end with null byte.*/ - realpathstr[PATH_MAX] = '\0'; - - /* Reset the delimiter and fill up the buffer. */ - *delimiter = old_delim; - plen = strlen(delimiter); - vlen = strlen(realpathstr); - rlen = plen + vlen; - if (rlen > len) { - uv__free(tmpbuf); - errno = ENAMETOOLONG; - return -1; - } - memcpy(buf, realpathstr, vlen); - memcpy(buf + vlen, delimiter, plen); - - /* Done using temporary buffer. */ - uv__free(tmpbuf); - - return rlen; -} - - -size_t strnlen(const char* str, size_t maxlen) { - void* p = memchr(str, 0, maxlen); - if (p == NULL) - return maxlen; - else - return p - str; -} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.h b/3rd/libuv-1.19.2/src/unix/os390-syscalls.h deleted file mode 100644 index 6e34a88c..00000000 --- a/3rd/libuv-1.19.2/src/unix/os390-syscalls.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright 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. - */ - - -#ifndef UV_OS390_SYSCALL_H_ -#define UV_OS390_SYSCALL_H_ - -#include "uv.h" -#include "internal.h" -#include -#include -#include - -#define EPOLL_CTL_ADD 1 -#define EPOLL_CTL_DEL 2 -#define EPOLL_CTL_MOD 3 -#define MAX_EPOLL_INSTANCES 256 -#define MAX_ITEMS_PER_EPOLL 1024 - -#define UV__O_CLOEXEC 0x80000 -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD -#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL -#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD - -struct epoll_event { - int events; - int fd; -}; - -typedef struct { - QUEUE member; - struct pollfd* items; - unsigned long size; - int msg_queue; -} uv__os390_epoll; - -/* epoll api */ -uv__os390_epoll* epoll_create1(int flags); -int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event); -int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout); -int epoll_file_close(int fd); - -/* utility functions */ -int nanosleep(const struct timespec* req, struct timespec* rem); -int scandir(const char* maindir, struct dirent*** namelist, - int (*filter)(const struct dirent *), - int (*compar)(const struct dirent **, - const struct dirent **)); -char *mkdtemp(char* path); -ssize_t os390_readlink(const char* path, char* buf, size_t len); -size_t strnlen(const char* str, size_t maxlen); - -#endif /* UV_OS390_SYSCALL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/os390.c b/3rd/libuv-1.19.2/src/unix/os390.c deleted file mode 100644 index f766b393..00000000 --- a/3rd/libuv-1.19.2/src/unix/os390.c +++ /dev/null @@ -1,998 +0,0 @@ -/* Copyright 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. - */ - -#include "internal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__clang__) -#include "csrsic.h" -#else -#include "//'SYS1.SAMPLIB(CSRSIC)'" -#endif - -#define CVT_PTR 0x10 -#define PSA_PTR 0x00 -#define CSD_OFFSET 0x294 - -/* - Long-term average CPU service used by this logical partition, - in millions of service units per hour. If this value is above - the partition's defined capacity, the partition will be capped. - It is calculated using the physical CPU adjustment factor - (RCTPCPUA) so it may not match other measures of service which - are based on the logical CPU adjustment factor. It is available - if the hardware supports LPAR cluster. -*/ -#define RCTLACS_OFFSET 0xC4 - -/* 32-bit count of alive CPUs. This includes both CPs and IFAs */ -#define CSD_NUMBER_ONLINE_CPUS 0xD4 - -/* Address of system resources manager (SRM) control table */ -#define CVTOPCTP_OFFSET 0x25C - -/* Address of the RCT table */ -#define RMCTRCT_OFFSET 0xE4 - -/* Address of the rsm control and enumeration area. */ -#define CVTRCEP_OFFSET 0x490 - -/* - Number of frames currently available to system. - Excluded are frames backing perm storage, frames offline, and bad frames. -*/ -#define RCEPOOL_OFFSET 0x004 - -/* Total number of frames currently on all available frame queues. */ -#define RCEAFC_OFFSET 0x088 - -/* CPC model length from the CSRSI Service. */ -#define CPCMODEL_LENGTH 16 - -/* Pointer to the home (current) ASCB. */ -#define PSAAOLD 0x224 - -/* Pointer to rsm address space block extension. */ -#define ASCBRSME 0x16C - -/* - NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. - It does not include 2G frames. -*/ -#define RAXFMCT 0x2C - -/* Thread Entry constants */ -#define PGTH_CURRENT 1 -#define PGTH_LEN 26 -#define PGTHAPATH 0x20 -#pragma linkage(BPX4GTH, OS) -#pragma linkage(BPX1GTH, OS) - -/* TOD Clock resolution in nanoseconds */ -#define TOD_RES 4.096 - -typedef unsigned data_area_ptr_assign_type; - -typedef union { - struct { -#if defined(_LP64) - data_area_ptr_assign_type lower; -#endif - data_area_ptr_assign_type assign; - }; - char* deref; -} data_area_ptr; - - -void uv_loadavg(double avg[3]) { - /* TODO: implement the following */ - avg[0] = 0; - avg[1] = 0; - avg[2] = 0; -} - - -int uv__platform_loop_init(uv_loop_t* loop) { - uv__os390_epoll* ep; - - ep = epoll_create1(0); - loop->ep = ep; - if (ep == NULL) - return UV__ERR(errno); - - return 0; -} - - -void uv__platform_loop_delete(uv_loop_t* loop) { - if (loop->ep != NULL) { - epoll_queue_close(loop->ep); - loop->ep = NULL; - } -} - - -uint64_t uv__hrtime(uv_clocktype_t type) { - unsigned long long timestamp; - __stckf(×tamp); - /* Convert to nanoseconds */ - return timestamp / TOD_RES; -} - - -/* - Get the exe path using the thread entry information - in the address space. -*/ -static int getexe(const int pid, char* buf, size_t len) { - struct { - int pid; - int thid[2]; - char accesspid; - char accessthid; - char asid[2]; - char loginname[8]; - char flag; - char len; - } Input_data; - - union { - struct { - char gthb[4]; - int pid; - int thid[2]; - char accesspid; - char accessthid[3]; - int lenused; - int offsetProcess; - int offsetConTTY; - int offsetPath; - int offsetCommand; - int offsetFileData; - int offsetThread; - } Output_data; - char buf[2048]; - } Output_buf; - - struct Output_path_type { - char gthe[4]; - short int len; - char path[1024]; - }; - - int Input_length; - int Output_length; - void* Input_address; - void* Output_address; - struct Output_path_type* Output_path; - int rv; - int rc; - int rsn; - - Input_length = PGTH_LEN; - Output_length = sizeof(Output_buf); - Output_address = &Output_buf; - Input_address = &Input_data; - memset(&Input_data, 0, sizeof Input_data); - Input_data.flag |= PGTHAPATH; - Input_data.pid = pid; - Input_data.accesspid = PGTH_CURRENT; - -#ifdef _LP64 - BPX4GTH(&Input_length, - &Input_address, - &Output_length, - &Output_address, - &rv, - &rc, - &rsn); -#else - BPX1GTH(&Input_length, - &Input_address, - &Output_length, - &Output_address, - &rv, - &rc, - &rsn); -#endif - - if (rv == -1) { - errno = rc; - return -1; - } - - /* Check highest byte to ensure data availability */ - assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); - - /* Get the offset from the lowest 3 bytes */ - Output_path = (char*)(&Output_buf) + - (Output_buf.Output_data.offsetPath & 0x00FFFFFF); - - if (Output_path->len >= len) { - errno = ENOBUFS; - return -1; - } - - strncpy(buf, Output_path->path, len); - - return 0; -} - - -/* - * 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 zOS - 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; - int pid; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - pid = getpid(); - res = getexe(pid, args, sizeof(args)); - if (res < 0) - return UV_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 UV__ERR(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 UV_EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return UV_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 UV_EINVAL; - } -} - - -uint64_t uv_get_free_memory(void) { - uint64_t freeram; - - data_area_ptr cvt = {0}; - data_area_ptr rcep = {0}; - cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); - rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); - freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; - return freeram; -} - - -uint64_t uv_get_total_memory(void) { - uint64_t totalram; - - data_area_ptr cvt = {0}; - data_area_ptr rcep = {0}; - cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); - rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); - totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4; - return totalram; -} - - -int uv_resident_set_memory(size_t* rss) { - char* psa; - char* ascb; - char* rax; - size_t nframes; - - psa = PSA_PTR; - ascb = *(char* __ptr32 *)(psa + PSAAOLD); - rax = *(char* __ptr32 *)(ascb + ASCBRSME); - nframes = *(unsigned int*)(rax + RAXFMCT); - - *rss = nframes * sysconf(_SC_PAGESIZE); - return 0; -} - - -int uv_uptime(double* uptime) { - struct utmpx u ; - struct utmpx *v; - time64_t t; - - u.ut_type = BOOT_TIME; - v = getutxid(&u); - if (v == NULL) - return -1; - *uptime = difftime64(time64(&t), v->ut_tv.tv_sec); - return 0; -} - - -int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - uv_cpu_info_t* cpu_info; - int idx; - siv1v2 info; - data_area_ptr cvt = {0}; - data_area_ptr csd = {0}; - data_area_ptr rmctrct = {0}; - data_area_ptr cvtopctp = {0}; - int cpu_usage_avg; - - cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); - - csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET)); - cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET)); - rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET)); - - *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS)); - cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET)); - - *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); - if (!*cpu_infos) - return UV_ENOMEM; - - cpu_info = *cpu_infos; - idx = 0; - while (idx < *count) { - cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability); - cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1); - memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1); - memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH); - cpu_info->cpu_times.user = cpu_usage_avg; - /* TODO: implement the following */ - cpu_info->cpu_times.sys = 0; - cpu_info->cpu_times.idle = 0; - cpu_info->cpu_times.irq = 0; - cpu_info->cpu_times.nice = 0; - ++cpu_info; - ++idx; - } - - return 0; -} - - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - for (int i = 0; i < count; ++i) - uv__free(cpu_infos[i].model); - uv__free(cpu_infos); -} - - -static int uv__interface_addresses_v6(uv_interface_address_t** addresses, - int* count) { - uv_interface_address_t* address; - int sockfd; - int maxsize; - __net_ifconf6header_t ifc; - __net_ifconf6entry_t* ifr; - __net_ifconf6entry_t* p; - __net_ifconf6entry_t flg; - - *count = 0; - /* Assume maximum buffer size allowable */ - maxsize = 16384; - - if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) - return UV__ERR(errno); - - ifc.__nif6h_version = 1; - ifc.__nif6h_buflen = maxsize; - ifc.__nif6h_buffer = uv__calloc(1, maxsize);; - - if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { - uv__close(sockfd); - return UV__ERR(errno); - } - - - *count = 0; - ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); - while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { - p = ifr; - ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); - - if (!(p->__nif6e_addr.sin6_family == AF_INET6 || - p->__nif6e_addr.sin6_family == AF_INET)) - continue; - - if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) - continue; - - ++(*count); - } - - /* Alloc the return interface structs */ - *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); - if (!(*addresses)) { - uv__close(sockfd); - return UV_ENOMEM; - } - address = *addresses; - - ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); - while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { - p = ifr; - ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); - - if (!(p->__nif6e_addr.sin6_family == AF_INET6 || - p->__nif6e_addr.sin6_family == AF_INET)) - continue; - - if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) - continue; - - /* All conditions above must match count loop */ - - address->name = uv__strdup(p->__nif6e_name); - - if (p->__nif6e_addr.sin6_family == AF_INET6) - address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); - else - address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr); - - /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ - - address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; - - address++; - } - - uv__close(sockfd); - return 0; -} - - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - uv_interface_address_t* address; - int sockfd; - int maxsize; - struct ifconf ifc; - struct ifreq flg; - struct ifreq* ifr; - struct ifreq* p; - int count_v6; - - /* get the ipv6 addresses first */ - uv_interface_address_t* addresses_v6; - uv__interface_addresses_v6(&addresses_v6, &count_v6); - - /* now get the ipv4 addresses */ - *count = 0; - - /* Assume maximum buffer size allowable */ - maxsize = 16384; - - sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (0 > sockfd) - return UV__ERR(errno); - - ifc.ifc_req = uv__calloc(1, maxsize); - ifc.ifc_len = maxsize; - if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - uv__close(sockfd); - return UV__ERR(errno); - } - -#define MAX(a,b) (((a)>(b))?(a):(b)) -#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) { - uv__close(sockfd); - return UV__ERR(errno); - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - (*count)++; - } - - /* Alloc the return interface structs */ - *addresses = uv__malloc((*count + count_v6) * - sizeof(uv_interface_address_t)); - - if (!(*addresses)) { - uv__close(sockfd); - return UV_ENOMEM; - } - address = *addresses; - - /* copy over the ipv6 addresses */ - memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); - address += count_v6; - *count += count_v6; - uv__free(addresses_v6); - - 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 UV_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); - } - - address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; - address++; - } - -#undef ADDR_SIZE -#undef MAX - - 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 epoll_event* events; - struct epoll_event dummy; - uintptr_t i; - uintptr_t nfds; - - assert(loop->watchers != NULL); - - events = (struct 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].fd == fd) - events[i].fd = -1; - - /* Remove the file descriptor from the epoll. */ - if (loop->ep != NULL) - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct pollfd p[1]; - int rv; - - p[0].fd = fd; - p[0].events = POLLIN; - - do - rv = poll(p, 1, 0); - while (rv == -1 && errno == EINTR); - - if (rv == -1) - abort(); - - if (p[0].revents & POLLNVAL) - return -1; - - return 0; -} - - -void uv__fs_event_close(uv_fs_event_t* handle) { - uv_fs_event_stop(handle); -} - - -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* filename, unsigned int flags) { - uv__os390_epoll* ep; - _RFIS reg_struct; - char* path; - int rc; - - if (uv__is_active(handle)) - return UV_EINVAL; - - ep = handle->loop->ep; - assert(ep->msg_queue != -1); - - reg_struct.__rfis_cmd = _RFIS_REG; - reg_struct.__rfis_qid = ep->msg_queue; - reg_struct.__rfis_type = 1; - memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); - - path = uv__strdup(filename); - if (path == NULL) - return UV_ENOMEM; - - rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); - if (rc != 0) - return UV__ERR(errno); - - uv__handle_start(handle); - handle->path = path; - handle->cb = cb; - memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, - sizeof(handle->rfis_rftok)); - - return 0; -} - - -int uv_fs_event_stop(uv_fs_event_t* handle) { - uv__os390_epoll* ep; - _RFIS reg_struct; - int rc; - - if (!uv__is_active(handle)) - return 0; - - ep = handle->loop->ep; - assert(ep->msg_queue != -1); - - reg_struct.__rfis_cmd = _RFIS_UNREG; - reg_struct.__rfis_qid = ep->msg_queue; - reg_struct.__rfis_type = 1; - memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, - sizeof(handle->rfis_rftok)); - - /* - * This call will take "/" as the path argument in case we - * don't care to supply the correct path. The system will simply - * ignore it. - */ - rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); - if (rc != 0 && errno != EALREADY && errno != ENOENT) - abort(); - - uv__handle_stop(handle); - - return 0; -} - - -static int os390_message_queue_handler(uv__os390_epoll* ep) { - uv_fs_event_t* handle; - int msglen; - int events; - _RFIM msg; - - if (ep->msg_queue == -1) - return 0; - - msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT); - - if (msglen == -1 && errno == ENOMSG) - return 0; - - if (msglen == -1) - abort(); - - events = 0; - if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) - events = UV_CHANGE; - else if (msg.__rfim_event == _RFIM_RENAME) - events = UV_RENAME; - else - /* Some event that we are not interested in. */ - return 0; - - handle = *(uv_fs_event_t**)(msg.__rfim_utok); - handle->cb(handle, uv__basename_r(handle->path), events, 0); - return 1; -} - - -void uv__io_poll(uv_loop_t* loop, int timeout) { - static const int max_safe_timeout = 1789569; - struct epoll_event events[1024]; - struct epoll_event* pe; - struct epoll_event e; - uv__os390_epoll* ep; - int real_timeout; - QUEUE* q; - uv__io_t* w; - uint64_t base; - 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)) { - uv_stream_t* stream; - - 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); - - stream= container_of(w, uv_stream_t, io_watcher); - - assert(w->fd < (int) loop->nwatchers); - - e.events = w->pevents; - e.fd = 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 (epoll_ctl(loop->ep, 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 (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) - abort(); - } - - w->events = w->pevents; - } - - assert(timeout >= -1); - base = loop->time; - count = 48; /* Benchmarks suggest this gives the best throughput. */ - real_timeout = timeout; - int nevents = 0; - - nfds = 0; - for (;;) { - if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) - timeout = max_safe_timeout; - - nfds = epoll_wait(loop->ep, 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. - */ - base = loop->time; - SAVE_ERRNO(uv__update_time(loop)); - if (nfds == 0) { - assert(timeout != -1); - - if (timeout > 0) { - timeout = real_timeout - timeout; - continue; - } - - 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; - } - - - 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->fd; - - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) - continue; - - ep = loop->ep; - if (fd == ep->msg_queue) { - os390_message_queue_handler(ep); - 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. - */ - epoll_ctl(loop->ep, 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 | POLLERR | POLLHUP; - - if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT); - - 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; - } -} - -void uv__set_process_title(const char* title) { - /* do nothing */ -} - -int uv__io_fork(uv_loop_t* loop) { - /* - Nullify the msg queue but don't close it because - it is still being used by the parent. - */ - loop->ep = NULL; - - uv__platform_loop_delete(loop); - return uv__platform_loop_init(loop); -} diff --git a/3rd/libuv-1.19.2/src/unix/pipe.c b/3rd/libuv-1.19.2/src/unix/pipe.c deleted file mode 100644 index e640bf29..00000000 --- a/3rd/libuv-1.19.2/src/unix/pipe.c +++ /dev/null @@ -1,357 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - - -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; - - /* Already bound? */ - if (uv__stream_fd(handle) >= 0) - return UV_EINVAL; - - /* Make a copy of the file name, it outlives this function's scope. */ - pipe_fname = uv__strdup(name); - if (pipe_fname == NULL) - return UV_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 = UV__ERR(errno); - /* Convert ENOENT to EACCES for compatibility with Windows. */ - if (err == UV_ENOENT) - err = UV_EACCES; - - uv__close(sockfd); - goto err_socket; - } - - /* Success. */ - handle->flags |= UV_HANDLE_BOUND; - handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ - handle->io_watcher.fd = sockfd; - return 0; - -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 UV_EINVAL; - -#if defined(__MVS__) - /* On zOS, backlog=0 has undefined behaviour */ - if (backlog == 0) - backlog = 1; - else if (backlog < 0) - backlog = SOMAXCONN; -#endif - - if (listen(uv__stream_fd(handle), backlog)) - return UV__ERR(errno); - - handle->connection_cb = cb; - handle->io_watcher.cb = uv__server_io; - uv__io_start(handle->loop, &handle->io_watcher, 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 = UV__ERR(errno); -#if defined(__CYGWIN__) || defined(__MSYS__) - /* EBADF is supposed to mean that the socket fd is bad, but - Cygwin reports EBADF instead of ENOTSOCK when the file is - not a socket. We do not expect to see a bad fd here - (e.g. due to new_sock), so translate the error. */ - if (err == UV_EBADF) - err = UV_ENOTSOCK; -#endif - 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, POLLIN | 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); - -} - - -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 UV__ERR(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 + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, sa.sun_path, addrlen); - *size = addrlen; - - /* only null-terminate if it's not an abstract socket */ - if (buffer[0] != '\0') - buffer[addrlen] = '\0'; - - 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); -} - - -int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - unsigned desired_mode; - struct stat pipe_stat; - char* name_buffer; - size_t name_len; - int r; - - if (handle == NULL || uv__stream_fd(handle) == -1) - return UV_EBADF; - - if (mode != UV_READABLE && - mode != UV_WRITABLE && - mode != (UV_WRITABLE | UV_READABLE)) - return UV_EINVAL; - - if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) - return UV__ERR(errno); - - desired_mode = 0; - if (mode & UV_READABLE) - desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; - if (mode & UV_WRITABLE) - desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) - return 0; - - pipe_stat.st_mode |= desired_mode; - - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = 0; - r = uv_pipe_getsockname(handle, NULL, &name_len); - if (r != UV_ENOBUFS) - return r; - - name_buffer = uv__malloc(name_len); - if (name_buffer == NULL) - return UV_ENOMEM; - - r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) { - uv__free(name_buffer); - return r; - } - - r = chmod(name_buffer, pipe_stat.st_mode); - uv__free(name_buffer); - - return r != -1 ? 0 : UV__ERR(errno); -} diff --git a/3rd/libuv-1.19.2/src/unix/poll.c b/3rd/libuv-1.19.2/src/unix/poll.c deleted file mode 100644 index f3b0bf4e..00000000 --- a/3rd/libuv-1.19.2/src/unix/poll.c +++ /dev/null @@ -1,147 +0,0 @@ -/* 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 -#include -#include - - -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); - - /* - * As documented in the kernel source fs/kernfs/file.c #780 - * poll will return POLLERR|POLLPRI in case of sysfs - * polling. This does not happen in case of out-of-band - * TCP messages. - * - * The above is the case on (at least) FreeBSD and Linux. - * - * So to properly determine a POLLPRI or a POLLERR we need - * to check for both. - */ - if ((events & POLLERR) && !(events & UV__POLLPRI)) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - uv__handle_stop(handle); - handle->poll_cb(handle, UV_EBADF, 0); - return; - } - - pevents = 0; - if (events & POLLIN) - pevents |= UV_READABLE; - if (events & UV__POLLPRI) - pevents |= UV_PRIORITIZED; - if (events & POLLOUT) - pevents |= UV_WRITABLE; - if (events & UV__POLLRDHUP) - pevents |= UV_DISCONNECT; - - handle->poll_cb(handle, 0, pevents); -} - - -int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { - int err; - - err = uv__io_check_fd(loop, fd); - if (err) - return err; - - /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). - * Workaround for e.g. kqueue fds not supporting ioctls. - */ - err = uv__nonblock(fd, 1); - if (err == UV_ENOTTY) - if (uv__nonblock == uv__nonblock_ioctl) - err = uv__nonblock_fcntl(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, - POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - uv__handle_stop(handle); - uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); -} - - -int uv_poll_stop(uv_poll_t* handle) { - assert(!uv__is_closing(handle)); - 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 | UV_DISCONNECT | - UV_PRIORITIZED)) == 0); - assert(!uv__is_closing(handle)); - - uv__poll_stop(handle); - - if (pevents == 0) - return 0; - - events = 0; - if (pevents & UV_READABLE) - events |= POLLIN; - if (pevents & UV_PRIORITIZED) - events |= UV__POLLPRI; - if (pevents & UV_WRITABLE) - events |= POLLOUT; - if (pevents & UV_DISCONNECT) - events |= UV__POLLRDHUP; - - 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/3rd/libuv-1.19.2/src/unix/posix-hrtime.c b/3rd/libuv-1.19.2/src/unix/posix-hrtime.c deleted file mode 100644 index 323dfc20..00000000 --- a/3rd/libuv-1.19.2/src/unix/posix-hrtime.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - -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); -} diff --git a/3rd/libuv-1.19.2/src/unix/posix-poll.c b/3rd/libuv-1.19.2/src/unix/posix-poll.c deleted file mode 100644 index f356e76c..00000000 --- a/3rd/libuv-1.19.2/src/unix/posix-poll.c +++ /dev/null @@ -1,324 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -/* POSIX defines poll() as a portable way to wait on file descriptors. - * Here we maintain a dynamically sized array of file descriptors and - * events to pass as the first argument to poll(). - */ - -#include -#include -#include -#include -#include - -int uv__platform_loop_init(uv_loop_t* loop) { - loop->poll_fds = NULL; - loop->poll_fds_used = 0; - loop->poll_fds_size = 0; - loop->poll_fds_iterating = 0; - return 0; -} - -void uv__platform_loop_delete(uv_loop_t* loop) { - uv__free(loop->poll_fds); - loop->poll_fds = NULL; -} - -int uv__io_fork(uv_loop_t* loop) { - uv__platform_loop_delete(loop); - return uv__platform_loop_init(loop); -} - -/* Allocate or dynamically resize our poll fds array. */ -static void uv__pollfds_maybe_resize(uv_loop_t* loop) { - size_t i; - size_t n; - struct pollfd* p; - - if (loop->poll_fds_used < loop->poll_fds_size) - return; - - n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; - p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); - if (p == NULL) - abort(); - - loop->poll_fds = p; - for (i = loop->poll_fds_size; i < n; i++) { - loop->poll_fds[i].fd = -1; - loop->poll_fds[i].events = 0; - loop->poll_fds[i].revents = 0; - } - loop->poll_fds_size = n; -} - -/* Primitive swap operation on poll fds array elements. */ -static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) { - struct pollfd pfd; - pfd = loop->poll_fds[l]; - loop->poll_fds[l] = loop->poll_fds[r]; - loop->poll_fds[r] = pfd; -} - -/* Add a watcher's fd to our poll fds array with its pending events. */ -static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { - size_t i; - struct pollfd* pe; - - /* If the fd is already in the set just update its events. */ - assert(!loop->poll_fds_iterating); - for (i = 0; i < loop->poll_fds_used; ++i) { - if (loop->poll_fds[i].fd == w->fd) { - loop->poll_fds[i].events = w->pevents; - return; - } - } - - /* Otherwise, allocate a new slot in the set for the fd. */ - uv__pollfds_maybe_resize(loop); - pe = &loop->poll_fds[loop->poll_fds_used++]; - pe->fd = w->fd; - pe->events = w->pevents; -} - -/* Remove a watcher's fd from our poll fds array. */ -static void uv__pollfds_del(uv_loop_t* loop, int fd) { - size_t i; - assert(!loop->poll_fds_iterating); - for (i = 0; i < loop->poll_fds_used; ++i) { - if (loop->poll_fds[i].fd == fd) { - /* swap to last position and remove */ - --loop->poll_fds_used; - uv__pollfds_swap(loop, i, loop->poll_fds_used); - loop->poll_fds[loop->poll_fds_used].fd = -1; - loop->poll_fds[loop->poll_fds_used].events = 0; - loop->poll_fds[loop->poll_fds_used].revents = 0; - return; - } - } -} - - -void uv__io_poll(uv_loop_t* loop, int timeout) { - sigset_t* pset; - sigset_t set; - uint64_t time_base; - uint64_t time_diff; - QUEUE* q; - uv__io_t* w; - size_t i; - unsigned int nevents; - int nfds; - int have_signals; - struct pollfd* pe; - int fd; - - if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); - return; - } - - /* Take queued watchers and add their fds to our poll fds array. */ - 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); - - uv__pollfds_add(loop, w); - - w->events = w->pevents; - } - - /* Prepare a set of signals to block around poll(), if any. */ - pset = NULL; - if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { - pset = &set; - sigemptyset(pset); - sigaddset(pset, SIGPROF); - } - - assert(timeout >= -1); - time_base = loop->time; - - /* Loop calls to poll() and processing of results. If we get some - * results from poll() but they turn out not to be interesting to - * our caller then we need to loop around and poll() again. - */ - for (;;) { - if (pset != NULL) - if (pthread_sigmask(SIG_BLOCK, pset, NULL)) - abort(); - nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); - if (pset != NULL) - if (pthread_sigmask(SIG_UNBLOCK, pset, 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); - 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; - } - - /* Tell uv__platform_invalidate_fd not to manipulate our array - * while we are iterating over it. - */ - loop->poll_fds_iterating = 1; - - /* Initialize a count of events that we care about. */ - nevents = 0; - have_signals = 0; - - /* Loop over the entire poll fds array looking for returned events. */ - for (i = 0; i < loop->poll_fds_used; i++) { - pe = loop->poll_fds + i; - fd = pe->fd; - - /* 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, ignore. */ - uv__platform_invalidate_fd(loop, fd); - continue; - } - - /* Filter out events that user has not requested us to watch - * (e.g. POLLNVAL). - */ - pe->revents &= w->pevents | POLLERR | POLLHUP; - - if (pe->revents != 0) { - /* Run signal watchers last. */ - if (w == &loop->signal_io_watcher) { - have_signals = 1; - } else { - w->cb(loop, w, pe->revents); - } - - nevents++; - } - } - - if (have_signals != 0) - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - - loop->poll_fds_iterating = 0; - - /* Purge invalidated fds from our poll fds array. */ - uv__pollfds_del(loop, -1); - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - if (nevents != 0) - return; - - if (timeout == 0) - return; - - if (timeout == -1) - continue; - -update_timeout: - assert(timeout > 0); - - time_diff = loop->time - time_base; - if (time_diff >= (uint64_t) timeout) - return; - - timeout -= time_diff; - } -} - -/* Remove the given fd from our poll fds array because no one - * is interested in its events anymore. - */ -void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - size_t i; - - if (loop->poll_fds_iterating) { - /* uv__io_poll is currently iterating. Just invalidate fd. */ - for (i = 0; i < loop->poll_fds_used; i++) - if (loop->poll_fds[i].fd == fd) { - loop->poll_fds[i].fd = -1; - loop->poll_fds[i].events = 0; - loop->poll_fds[i].revents = 0; - } - } else { - /* uv__io_poll is not iterating. Delete fd from the set. */ - uv__pollfds_del(loop, fd); - } -} - -/* Check whether the given fd is supported by poll(). */ -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct pollfd p[1]; - int rv; - - p[0].fd = fd; - p[0].events = POLLIN; - - do - rv = poll(p, 1, 0); - while (rv == -1 && (errno == EINTR || errno == EAGAIN)); - - if (rv == -1) - return UV__ERR(errno); - - if (p[0].revents & POLLNVAL) - return UV_EINVAL; - - return 0; -} diff --git a/3rd/libuv-1.19.2/src/unix/process.c b/3rd/libuv-1.19.2/src/unix/process.c deleted file mode 100644 index 74113e3a..00000000 --- a/3rd/libuv-1.19.2/src/unix/process.c +++ /dev/null @@ -1,599 +0,0 @@ -/* 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 -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include -# define environ (*_NSGetEnviron()) -#else -extern char **environ; -#endif - -#if defined(__linux__) || defined(__GLIBC__) -# include -#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 UV__ERR(errno); - - no_cloexec = 1; - -skip: -#endif - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - return UV__ERR(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 UV__ERR(errno); - - no_pipe2 = 1; - -skip: -#endif - - if (pipe(fds)) - return UV__ERR(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 UV_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 UV_EINVAL; - - fds[1] = fd; - return 0; - - default: - assert(0 && "Unexpected flags"); - return UV_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) - 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) { - sigset_t set; - int close_fd; - int use_fd; - int err; - int fd; - int n; - - 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, UV__ERR(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, UV__ERR(errno)); - _exit(127); - } - } - } - - if (fd == use_fd) - uv__cloexec_fcntl(use_fd, 0); - else - fd = dup2(use_fd, fd); - - if (fd == -1) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } - - if (fd <= 2) - uv__nonblock_fcntl(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, UV__ERR(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, UV__ERR(errno)); - _exit(127); - } - - if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } - - if (options->env != NULL) { - environ = options->env; - } - - /* Reset signal disposition. Use a hard-coded limit because NSIG - * is not fixed on Linux: it's either 32, 34 or 64, depending on - * whether RT signals are enabled. We are not allowed to touch - * RT signal handlers, glibc uses them internally. - */ - for (n = 1; n < 32; n += 1) { - if (n == SIGKILL || n == SIGSTOP) - continue; /* Can't be changed. */ - - if (SIG_ERR != signal(n, SIG_DFL)) - continue; - - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } - - /* Reset signal mask. */ - sigemptyset(&set); - err = pthread_sigmask(SIG_SETMASK, &set, NULL); - - if (err != 0) { - uv__write_int(error_fd, UV__ERR(err)); - _exit(127); - } - - execvp(options->file, options->args); - uv__write_int(error_fd, UV__ERR(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 UV_ENOSYS; -#else - int signal_pipe[2] = { -1, -1 }; - int pipes_storage[8][2]; - 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 = UV_ENOMEM; - pipes = pipes_storage; - if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) - 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 = UV__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_nocheckstdio(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; - - if (pipes != pipes_storage) - 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) - uv__close_nocheckstdio(pipes[i][0]); - if (pipes[i][1] != -1) - uv__close_nocheckstdio(pipes[i][1]); - } - - if (pipes != pipes_storage) - 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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/procfs-exepath.c b/3rd/libuv-1.19.2/src/unix/procfs-exepath.c deleted file mode 100644 index 00dc021f..00000000 --- a/3rd/libuv-1.19.2/src/unix/procfs-exepath.c +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -int uv_exepath(char* buffer, size_t* size) { - ssize_t n; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - n = *size - 1; - if (n > 0) - n = readlink("/proc/self/exe", buffer, n); - - if (n == -1) - return UV__ERR(errno); - - buffer[n] = '\0'; - *size = n; - - return 0; -} diff --git a/3rd/libuv-1.19.2/src/unix/proctitle.c b/3rd/libuv-1.19.2/src/unix/proctitle.c deleted file mode 100644 index 1a8c7a70..00000000 --- a/3rd/libuv-1.19.2/src/unix/proctitle.c +++ /dev/null @@ -1,132 +0,0 @@ -/* 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 -#include - -extern void uv__set_process_title(const char* title); - -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static void* args_mem; - -static struct { - char* str; - size_t len; -} process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - -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; - -#if defined(__MVS__) - /* argv is not adjacent. So just use argv[0] */ - process_title.str = argv[0]; - process_title.len = strlen(argv[0]); -#else - 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. */ -#endif - - /* 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) { - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title.len != 0) { - /* No need to terminate, byte after is always '\0'. */ - strncpy(process_title.str, title, process_title.len); - uv__set_process_title(title); - } - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (size <= process_title.len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - if (process_title.len != 0) - memcpy(buffer, process_title.str, process_title.len + 1); - - buffer[process_title.len] = '\0'; - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -UV_DESTRUCTOR(static void free_args_mem(void)) { - uv__free(args_mem); /* Keep valgrind happy. */ - args_mem = NULL; -} diff --git a/3rd/libuv-1.19.2/src/unix/pthread-fixes.c b/3rd/libuv-1.19.2/src/unix/pthread-fixes.c deleted file mode 100644 index fb179958..00000000 --- a/3rd/libuv-1.19.2/src/unix/pthread-fixes.c +++ /dev/null @@ -1,56 +0,0 @@ -/* 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. */ -#include -#include -#include - -int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { - static int workaround; - int err; - - if (workaround) { - return sigprocmask(how, set, oset); - } else { - err = pthread_sigmask(how, set, oset); - if (err) { - if (err == EINVAL && sigprocmask(how, set, oset) == 0) { - workaround = 1; - return 0; - } else { - return -1; - } - } - } - - return 0; -} diff --git a/3rd/libuv-1.19.2/src/unix/signal.c b/3rd/libuv-1.19.2/src/unix/signal.c deleted file mode 100644 index b9d0a560..00000000 --- a/3rd/libuv-1.19.2/src/unix/signal.c +++ /dev/null @@ -1,564 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#ifndef SA_RESTART -# define SA_RESTART 0 -#endif - -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 int uv__signal_start(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum, - int oneshot); -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 void uv__signal_unregister_handler(int signum); - - -static uv_once_t uv__signal_global_init_guard = UV_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_reinit(void); - -static void uv__signal_global_init(void) { - if (!uv__signal_lock_pipefd[0]) - /* pthread_atfork can register before and after handlers, one - * for each child. This only registers one for the child. That - * state is both persistent and cumulative, so if we keep doing - * it the handler functions will be called multiple times. Thus - * we only want to do it once. - */ - if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) - abort(); - - if (uv__make_pipe(uv__signal_lock_pipefd, 0)) - abort(); - - if (uv__signal_unlock()) - abort(); -} - - -static void uv__signal_global_reinit(void) { - /* We can only use signal-safe functions here. - * That includes read/write and close, fortunately. - * We do all of this directly here instead of resetting - * uv__signal_global_init_guard because - * uv__signal_global_once_init is only called from uv_loop_init - * and this needs to function in existing loops. - */ - uv__close(uv__signal_lock_pipefd[0]); - uv__signal_lock_pipefd[0] = -1; - uv__close(uv__signal_lock_pipefd[1]); - uv__signal_lock_pipefd[1] = -1; - uv__signal_global_init(); -} - - -void uv__signal_global_once_init(void) { - uv_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.flags = 0; - 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, int oneshot) { - /* 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; - sa.sa_flags = SA_RESTART; - if (oneshot) - sa.sa_flags |= SA_RESETHAND; - - /* XXX save old action so we can restore it later on? */ - if (sigaction(signum, &sa, NULL)) - return UV__ERR(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, POLLIN); - - return 0; -} - - -int uv__signal_loop_fork(uv_loop_t* loop) { - uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); - uv__close(loop->signal_pipefd[0]); - uv__close(loop->signal_pipefd[1]); - loop->signal_pipefd[0] = -1; - loop->signal_pipefd[1] = -1; - return uv__signal_loop_once_init(loop); -} - - -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) { - return uv__signal_start(handle, signal_cb, signum, 0); -} - - -int uv_signal_start_oneshot(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum) { - return uv__signal_start(handle, signal_cb, signum, 1); -} - - -static int uv__signal_start(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum, - int oneshot) { - sigset_t saved_sigmask; - int err; - uv_signal_t* first_handle; - - assert(!uv__is_closing(handle)); - - /* 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 - * 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. - * Also in case there's only one-shot handlers and a regular handler comes in. - */ - first_handle = uv__signal_first_handle(signum); - if (first_handle == NULL || - (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { - err = uv__signal_register_handler(signum, oneshot); - if (err) { - /* Registering the signal handler failed. Must be an invalid signal. */ - uv__signal_unlock_and_unblock(&saved_sigmask); - return err; - } - } - - handle->signum = signum; - if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; - - 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 (handle->flags & UV__SIGNAL_ONE_SHOT) - uv__signal_stop(handle); - - /* 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) { - int f1; - int f2; - /* 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; - - /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first - * handler returned is a one-shot handler, the rest will be too. - */ - f1 = w1->flags & UV__SIGNAL_ONE_SHOT; - f2 = w2->flags & UV__SIGNAL_ONE_SHOT; - if (f1 < f2) return -1; - if (f1 > f2) 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(!uv__is_closing(handle)); - uv__signal_stop(handle); - return 0; -} - - -static void uv__signal_stop(uv_signal_t* handle) { - uv_signal_t* removed_handle; - sigset_t saved_sigmask; - uv_signal_t* first_handle; - int rem_oneshot; - int first_oneshot; - int ret; - - /* 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. - */ - first_handle = uv__signal_first_handle(handle->signum); - if (first_handle == NULL) { - uv__signal_unregister_handler(handle->signum); - } else { - rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; - first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; - if (first_oneshot && !rem_oneshot) { - ret = uv__signal_register_handler(handle->signum, 1); - assert(ret == 0); - } - } - - uv__signal_unlock_and_unblock(&saved_sigmask); - - handle->signum = 0; - uv__handle_stop(handle); -} diff --git a/3rd/libuv-1.19.2/src/unix/spinlock.h b/3rd/libuv-1.19.2/src/unix/spinlock.h deleted file mode 100644 index a20c83cc..00000000 --- a/3rd/libuv-1.19.2/src/unix/spinlock.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * 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/3rd/libuv-1.19.2/src/unix/stream.c b/3rd/libuv-1.19.2/src/unix/stream.c deleted file mode 100644 index 3e786abe..00000000 --- a/3rd/libuv-1.19.2/src/unix/stream.c +++ /dev/null @@ -1,1696 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include /* IOV_MAX */ - -#if defined(__APPLE__) -# include -# include -# include - -/* 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; -}; -# define WRITE_RETRY_ON_ERROR(send_handle) \ - (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ - (errno == EMSGSIZE && send_handle)) -#else -# define WRITE_RETRY_ON_ERROR(send_handle) \ - (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) -#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, POLLIN)) - FD_SET(fd, s->sread); - if (uv__io_active(&stream->io_watcher, 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 |= POLLIN; - if (FD_ISSET(fd, s->swrite)) - events |= 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 & (POLLIN | POLLOUT))); - - /* Invoke callback on event-loop */ - if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) - uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); - - if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) - uv__stream_io(stream->loop, &stream->io_watcher, 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 UV__ERR(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; - - do - ret = kevent(kq, filter, 1, events, 1, &timeout); - while (ret == -1 && errno == EINTR); - - uv__close(kq); - - if (ret == -1) - return UV__ERR(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 UV__ERR(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 = UV_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 UV_EBUSY; - - assert(fd >= 0); - stream->flags |= flags; - - if (stream->type == UV_TCP) { - if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) - return UV__ERR(errno); - - /* TODO Use delay the user passed in. */ - if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) - return UV__ERR(errno); - } - -#if defined(__APPLE__) - enable = 1; - if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && - errno != ENOTSOCK && - errno != EINVAL) { - return UV__ERR(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, POLLIN | 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, UV_ECANCELED); - stream->connect_req = NULL; - } - - uv__stream_flush_write_queue(stream, UV_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, UV_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 UV_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 == UV_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 & POLLIN); - assert(stream->accepted_fd == -1); - assert(!(stream->flags & UV_CLOSING)); - - uv__io_start(stream->loop, &stream->io_watcher, 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 == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) - return; /* Not an error. */ - - if (err == UV_ECONNABORTED) - continue; /* Ignore. Nothing we can do about that. */ - - if (err == UV_EMFILE || err == UV_ENFILE) { - err = uv__emfile_trick(loop, uv__stream_fd(stream)); - if (err == UV_EAGAIN || err == UV__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, 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; - - assert(server->loop == client->loop); - - if (server->accepted_fd == -1) - return UV_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 UV_EINVAL; - } - - client->flags |= UV_HANDLE_BOUND; - -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, 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 = UV_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, 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 = UV__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; - int err; - -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) { - int fd_to_send; - struct msghdr msg; - struct cmsghdr *cmsg; - union { - char data[64]; - struct cmsghdr alias; - } scratch; - - if (uv__is_closing(req->send_handle)) { - err = UV_EBADF; - goto error; - } - - fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); - - memset(&scratch, 0, sizeof(scratch)); - - 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 = &scratch.alias; - 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 (!WRITE_RETRY_ON_ERROR(req->send_handle)) { - err = UV__ERR(errno); - goto error; - } 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, POLLOUT); - - /* Notify select() thread about state change */ - uv__stream_osx_interrupt_select(stream); - - return; - -error: - req->error = err; - uv__write_req_finish(req); - uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - if (!uv__io_active(&stream->io_watcher, POLLIN)) - uv__handle_stop(stream); - 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 sslen; - socklen_t len; - int type; - - memset(&ss, 0, sizeof(ss)); - sslen = sizeof(ss); - - if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) - return UV_UNKNOWN_HANDLE; - - len = sizeof type; - - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) - return UV_UNKNOWN_HANDLE; - - if (type == SOCK_STREAM) { -#if defined(_AIX) || defined(__DragonFly__) - /* on AIX/DragonFly 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 (sslen == 0) - return UV_NAMED_PIPE; -#endif - 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, POLLIN); - if (!uv__io_active(&stream->io_watcher, 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 UV_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 UV_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; -} - - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wgnu-folding-constant" -#endif - -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); - - buf = uv_buf_init(NULL, 0); - stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); - if (buf.base == NULL || 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, POLLIN); - uv__stream_osx_interrupt_select(stream); - } - stream->read_cb(stream, 0, &buf); -#if defined(__CYGWIN__) || defined(__MSYS__) - } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { - uv__stream_eof(stream, &buf); - return; -#endif - } else { - /* Error. User should call uv_close(). */ - stream->read_cb(stream, UV__ERR(errno), &buf); - if (stream->flags & UV_STREAM_READING) { - stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); - if (!uv__io_active(&stream->io_watcher, 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; - } - } - -#if defined(__MVS__) - if (is_ipc && msg.msg_controllen > 0) { - uv_buf_t blankbuf; - int nread; - struct iovec *old; - - blankbuf.base = 0; - blankbuf.len = 0; - old = msg.msg_iov; - msg.msg_iov = (struct iovec*) &blankbuf; - nread = 0; - do { - nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); - err = uv__stream_recv_cmsg(stream, &msg); - if (err != 0) { - stream->read_cb(stream, err, &buf); - msg.msg_iov = old; - return; - } - } while (nread == 0 && msg.msg_controllen > 0); - msg.msg_iov = old; - } -#endif - 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; - } - } - } -} - - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#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_TTY || - stream->type == UV_NAMED_PIPE); - - if (!(stream->flags & UV_STREAM_WRITABLE) || - stream->flags & UV_STREAM_SHUT || - stream->flags & UV_STREAM_SHUTTING || - uv__is_closing(stream)) { - return UV_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, 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 & (POLLIN | POLLERR | 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 & 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 & (POLLOUT | POLLERR | 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 = UV__ERR(error); - } - - if (error == UV__ERR(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, POLLOUT); - } - - if (req->cb) - req->cb(req, error); - - if (uv__stream_fd(stream) == -1) - return; - - if (error < 0) { - uv__stream_flush_write_queue(stream, UV_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 UV_EBADF; - - if (send_handle) { - if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) - return UV_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 UV_EBADF; - -#if defined(__CYGWIN__) || defined(__MSYS__) - /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. - See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ - return UV_ENOSYS; -#endif - } - - /* 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 UV_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, 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 UV_EAGAIN; - - has_pollout = uv__io_active(&stream->io_watcher, 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, POLLOUT); - uv__stream_osx_interrupt_select(stream); - } - - if (written == 0 && req_size != 0) - return UV_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 UV_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, 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, POLLIN); - if (!uv__io_active(&stream->io_watcher, 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, POLLIN | 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/3rd/libuv-1.19.2/src/unix/sunos.c b/3rd/libuv-1.19.2/src/unix/sunos.c deleted file mode 100644 index b6b3dfea..00000000 --- a/3rd/libuv-1.19.2/src/unix/sunos.c +++ /dev/null @@ -1,821 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#ifndef SUNOS_NO_IFADDRS -# include -#endif -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#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 - -#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 UV__ERR(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; - } -} - - -int uv__io_fork(uv_loop_t* loop) { -#if defined(PORT_SOURCE_FILE) - if (loop->fs_fd != -1) { - /* stop the watcher before we blow away its fileno */ - uv__io_stop(loop, &loop->fs_event_watcher, POLLIN); - } -#endif - uv__platform_loop_delete(loop); - return uv__platform_loop_init(loop); -} - - -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; -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) - return UV__ERR(errno); - - if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) - abort(); - - return 0; -} - - -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 have_signals; - 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; - } - - have_signals = 0; - 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; - - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) - have_signals = 1; - else - 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); - } - - if (have_signals != 0) - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - 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 UV_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 UV__ERR(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 UV_EBADF; - - if (port_associate(handle->loop->fs_fd, - PORT_SOURCE_FILE, - (uintptr_t) &handle->fo, - FILE_ATTRIB | FILE_MODIFIED, - handle) == -1) { - return UV__ERR(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 UV_EINVAL; - - first_run = 0; - if (handle->loop->fs_fd == -1) { - portfd = port_create(); - if (portfd == -1) - return UV__ERR(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) { - uv_fs_event_stop(handle); - 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, 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 UV_ENOSYS; -} - - -int uv_fs_event_start(uv_fs_event_t* handle, - uv_fs_event_cb cb, - const char* filename, - unsigned int flags) { - return UV_ENOSYS; -} - - -int uv_fs_event_stop(uv_fs_event_t* handle) { - return UV_ENOSYS; -} - - -void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); -} - -#endif /* defined(PORT_SOURCE_FILE) */ - - -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 UV__ERR(errno); - - /* FIXME(bnoordhuis) Handle EINTR. */ - err = UV_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 UV_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 UV_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 UV_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); -} - -#ifdef SUNOS_NO_IFADDRS -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - return UV_ENOSYS; -} -#else /* SUNOS_NO_IFADDRS */ -/* - * Inspired By: - * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris - * http://www.pauliesworld.org/project/getmac.c - */ -static int uv__set_phys_addr(uv_interface_address_t* address, - struct ifaddrs* ent) { - - struct sockaddr_dl* sa_addr; - int sockfd; - int i; - struct arpreq arpreq; - - /* This appears to only work as root */ - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - for (i = 0; i < sizeof(address->phys_addr); i++) { - if (address->phys_addr[i] != 0) - return 0; - } - memset(&arpreq, 0, sizeof(arpreq)); - if (address->address.address4.sin_family == AF_INET) { - struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); - sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; - } else if (address->address.address4.sin_family == AF_INET6) { - struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); - memcpy(sin->sin6_addr.s6_addr, - address->address.address6.sin6_addr.s6_addr, - sizeof(address->address.address6.sin6_addr.s6_addr)); - } else { - return 0; - } - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - return UV__ERR(errno); - - if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { - uv__close(sockfd); - return UV__ERR(errno); - } - memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); - uv__close(sockfd); - return 0; -} - - -static int uv__ifaddr_exclude(struct ifaddrs *ent) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - if (ent->ifa_addr->sa_family != AF_INET && - ent->ifa_addr->sa_family != AF_INET6) - return 1; - return 0; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - uv_interface_address_t* address; - struct ifaddrs* addrs; - struct ifaddrs* ent; - - if (getifaddrs(&addrs)) - return UV__ERR(errno); - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { - freeifaddrs(addrs); - return UV_ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - 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)); - - uv__set_phys_addr(address, ent); - 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/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c b/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c deleted file mode 100644 index ebad0e89..00000000 --- a/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -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; -} diff --git a/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c b/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c deleted file mode 100644 index 23b4fc6e..00000000 --- a/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "internal.h" - -#include -#include - -uint64_t uv_get_free_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.freeram * info.mem_unit; - return 0; -} - -uint64_t uv_get_total_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.totalram * info.mem_unit; - return 0; -} diff --git a/3rd/libuv-1.19.2/src/unix/tcp.c b/3rd/libuv-1.19.2/src/unix/tcp.c deleted file mode 100644 index 96f89312..00000000 --- a/3rd/libuv-1.19.2/src/unix/tcp.c +++ /dev/null @@ -1,444 +0,0 @@ -/* 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 -#include -#include -#include - - -static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { - struct sockaddr_storage saddr; - socklen_t slen; - int sockfd; - int err; - - 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; - } - - if (flags & UV_HANDLE_BOUND) { - /* Bind this new socket to an arbitrary port */ - slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); - if (err) { - uv__close(sockfd); - return err; - } - - err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); - if (err) { - uv__close(sockfd); - return err; - } - } - - return 0; -} - - -static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { - struct sockaddr_storage saddr; - socklen_t slen; - - if (domain == AF_UNSPEC) { - handle->flags |= flags; - return 0; - } - - if (uv__stream_fd(handle) != -1) { - - if (flags & UV_HANDLE_BOUND) { - - if (handle->flags & UV_HANDLE_BOUND) { - /* It is already bound to a port. */ - handle->flags |= flags; - return 0; - } - - /* Query to see if tcp socket is bound. */ - slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) - return UV__ERR(errno); - - if ((saddr.ss_family == AF_INET6 && - ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || - (saddr.ss_family == AF_INET && - ((struct sockaddr_in*) &saddr)->sin_port != 0)) { - /* Handle is already bound to a port. */ - handle->flags |= flags; - return 0; - } - - /* Bind to arbitrary port */ - if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) - return UV__ERR(errno); - } - - handle->flags |= flags; - return 0; - } - - return new_socket(handle, domain, flags); -} - - -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 UV_EINVAL; - - if (flags & ~0xFF) - return UV_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 UV_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 UV__ERR(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) { -#if defined(__MVS__) - if (errno == EOPNOTSUPP) - return UV_EINVAL; -#endif - return UV__ERR(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 UV_EINVAL; - return UV__ERR(errno); - } - tcp->delayed_error = UV__ERR(errno); - - tcp->flags |= UV_HANDLE_BOUND; - 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 UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ - - err = maybe_new_socket(handle, - addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); - if (err) - return err; - - handle->delayed_error = 0; - - do { - errno = 0; - r = connect(uv__stream_fd(handle), addr, addrlen); - } while (r == -1 && errno == EINTR); - - /* We not only check the return value, but also check the errno != 0. - * Because in rare cases connect() will return -1 but the errno - * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) - * and actually the tcp three-way handshake is completed. - */ - if (r == -1 && errno != 0) { - 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 = UV__ERR(errno); - else - return UV__ERR(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, 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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getsockname(uv__stream_fd(handle), name, &socklen)) - return UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getpeername(uv__stream_fd(handle), name, &socklen)) - return UV__ERR(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; - unsigned long flags; - 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; - - flags = UV_STREAM_READABLE; -#if defined(__MVS__) - /* on zOS the listen call does not bind automatically - if the socket is unbound. Hence the manual binding to - an arbitrary port is required to be done manually - */ - flags |= UV_HANDLE_BOUND; -#endif - err = maybe_new_socket(tcp, AF_INET, flags); - if (err) - return err; - - if (listen(tcp->io_watcher.fd, backlog)) - return UV__ERR(errno); - - tcp->connection_cb = cb; - tcp->flags |= UV_HANDLE_BOUND; - - /* Start listening for connections. */ - tcp->io_watcher.cb = uv__server_io; - uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); - - return 0; -} - - -int uv__tcp_nodelay(int fd, int on) { - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) - return UV__ERR(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 UV__ERR(errno); - -#ifdef TCP_KEEPIDLE - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return UV__ERR(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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/thread.c b/3rd/libuv-1.19.2/src/unix/thread.c deleted file mode 100644 index 3def2945..00000000 --- a/3rd/libuv-1.19.2/src/unix/thread.c +++ /dev/null @@ -1,729 +0,0 @@ -/* 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 -#include -#include - -#include -#include /* getrlimit() */ -#include /* getpagesize() */ - -#include - -#ifdef __MVS__ -#include -#include -#endif - -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - - -#if defined(UV__PTHREAD_BARRIER_FALLBACK) -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; - - b = uv__malloc(sizeof(*b)); - if (b == NULL) - return ENOMEM; - - b->in = 0; - b->out = 0; - b->threshold = count; - - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) - goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) - goto error; - - barrier->b = b; - return 0; - -error: - pthread_mutex_destroy(&b->mutex); -error2: - uv__free(b); - return rc; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ - if (++b->in == b->threshold) { - b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; -} - -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - if (b->in > 0 || b->out > 0) - rc = EBUSY; - - pthread_mutex_unlock(&b->mutex); - - if (rc) - return rc; - - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); - uv__free(barrier->b); - barrier->b = NULL; - return 0; -} -#endif - - -/* On MacOS, threads other than the main thread are created with a reduced - * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. - * - * On Linux, threads created by musl have a much smaller stack than threads - * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. - */ -static size_t thread_stack_size(void) { -#if defined(__APPLE__) || defined(__linux__) - struct rlimit lim; - - if (getrlimit(RLIMIT_STACK, &lim)) - abort(); - - if (lim.rlim_cur != RLIM_INFINITY) { - /* pthread_attr_setstacksize() expects page-aligned values. */ - lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); - if (lim.rlim_cur >= PTHREAD_STACK_MIN) - return lim.rlim_cur; - } -#endif - -#if !defined(__linux__) - return 0; -#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) - return 4 << 20; /* glibc default. */ -#else - return 2 << 20; /* glibc default. */ -#endif -} - - -int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - int err; - size_t stack_size; - pthread_attr_t* attr; - pthread_attr_t attr_storage; - - attr = NULL; - stack_size = thread_stack_size(); - - if (stack_size > 0) { - attr = &attr_storage; - - if (pthread_attr_init(attr)) - abort(); - - if (pthread_attr_setstacksize(attr, stack_size)) - abort(); - } - - err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); - - if (attr != NULL) - pthread_attr_destroy(attr); - - return UV__ERR(err); -} - - -uv_thread_t uv_thread_self(void) { - return pthread_self(); -} - -int uv_thread_join(uv_thread_t *tid) { - return UV__ERR(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 UV__ERR(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 UV__ERR(err); -#endif -} - - -int uv_mutex_init_recursive(uv_mutex_t* mutex) { - pthread_mutexattr_t attr; - int err; - - if (pthread_mutexattr_init(&attr)) - abort(); - - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) - abort(); - - err = pthread_mutex_init(mutex, &attr); - - if (pthread_mutexattr_destroy(&attr)) - abort(); - - return UV__ERR(err); -} - - -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 UV_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 UV__ERR(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 UV_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 UV_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 UV_EINVAL; - if (err == KERN_RESOURCE_SHORTAGE) - return UV_ENOMEM; - - abort(); - return UV_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 UV_EAGAIN; - - abort(); - return UV_EINVAL; /* Satisfy the compiler. */ -} - -#elif defined(__MVS__) - -int uv_sem_init(uv_sem_t* sem, unsigned int value) { - uv_sem_t semid; - int err; - union { - int val; - struct semid_ds* buf; - unsigned short* array; - } arg; - - - semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); - if (semid == -1) - return UV__ERR(errno); - - arg.val = value; - if (-1 == semctl(semid, 0, SETVAL, arg)) { - err = errno; - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); - return UV__ERR(err); - } - - *sem = semid; - return 0; -} - -void uv_sem_destroy(uv_sem_t* sem) { - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); -} - -void uv_sem_post(uv_sem_t* sem) { - struct sembuf buf; - - buf.sem_num = 0; - buf.sem_op = 1; - buf.sem_flg = 0; - - if (-1 == semop(*sem, &buf, 1)) - abort(); -} - -void uv_sem_wait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = 0; - - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); - - if (op_status) - abort(); -} - -int uv_sem_trywait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = IPC_NOWAIT; - - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); - - if (op_status) { - if (errno == EAGAIN) - return UV_EAGAIN; - abort(); - } - - return 0; -} - -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - -int uv_sem_init(uv_sem_t* sem, unsigned int value) { - if (sem_init(sem, 0, value)) - return UV__ERR(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 UV_EAGAIN; - abort(); - } - - return 0; -} - -#endif /* defined(__APPLE__) && defined(__MACH__) */ - - -#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) - -int uv_cond_init(uv_cond_t* cond) { - return UV__ERR(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 UV__ERR(err); - -#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) - 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 UV__ERR(err); -} - -#endif /* defined(__APPLE__) && defined(__MACH__) */ - -void uv_cond_destroy(uv_cond_t* cond) { -#if defined(__APPLE__) && defined(__MACH__) - /* It has been reported that destroying condition variables that have been - * signalled but not waited on can sometimes result in application crashes. - * See https://codereview.chromium.org/1323293005. - */ - pthread_mutex_t mutex; - struct timespec ts; - int err; - - if (pthread_mutex_init(&mutex, NULL)) - abort(); - - if (pthread_mutex_lock(&mutex)) - abort(); - - ts.tv_sec = 0; - ts.tv_nsec = 1; - - err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); - if (err != 0 && err != ETIMEDOUT) - abort(); - - if (pthread_mutex_unlock(&mutex)) - abort(); - - if (pthread_mutex_destroy(&mutex)) - abort(); -#endif /* defined(__APPLE__) && defined(__MACH__) */ - - 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(__MVS__) - struct timeval tv; -#endif - -#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 -#if defined(__MVS__) - if (gettimeofday(&tv, NULL)) - abort(); - timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; -#else - timeout += uv__hrtime(UV_CLOCK_PRECISE); -#endif - ts.tv_sec = timeout / NANOSEC; - ts.tv_nsec = timeout % NANOSEC; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - - /* - * 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_API__ */ -#endif - - - if (r == 0) - return 0; - - if (r == ETIMEDOUT) - return UV_ETIMEDOUT; - - abort(); - return UV_EINVAL; /* Satisfy the compiler. */ -} - - -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return UV__ERR(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; -} - - -int uv_key_create(uv_key_t* key) { - return UV__ERR(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/3rd/libuv-1.19.2/src/unix/timer.c b/3rd/libuv-1.19.2/src/unix/timer.c deleted file mode 100644 index 54dabfe7..00000000 --- a/3rd/libuv-1.19.2/src/unix/timer.c +++ /dev/null @@ -1,172 +0,0 @@ -/* 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 -#include - - -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, uv_timer_t, heap_node); - b = container_of(hb, 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 UV_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 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) { - 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, 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/3rd/libuv-1.19.2/src/unix/tty.c b/3rd/libuv-1.19.2/src/unix/tty.c deleted file mode 100644 index f22b3b80..00000000 --- a/3rd/libuv-1.19.2/src/unix/tty.c +++ /dev/null @@ -1,372 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -#if defined(__MVS__) && !defined(IMAXBEL) -#define IMAXBEL 0 -#endif - -static int orig_termios_fd = -1; -static struct termios orig_termios; -static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; - -static int uv__tty_is_slave(const int fd) { - int result; -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - int dummy; - - result = ioctl(fd, TIOCGPTN, &dummy) != 0; -#elif defined(__APPLE__) - char dummy[256]; - - result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; -#elif defined(__NetBSD__) - /* - * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave - * device name for both descriptors, the master one and slave one. - * - * Implement function to compare major device number with pts devices. - * - * The major numbers are machine-dependent, on NetBSD/amd64 they are - * respectively: - * - master tty: ptc - major 6 - * - slave tty: pts - major 5 - */ - - struct stat sb; - /* Lookup device's major for the pts driver and cache it. */ - static devmajor_t pts = NODEVMAJOR; - - if (pts == NODEVMAJOR) { - pts = getdevmajor("pts", S_IFCHR); - if (pts == NODEVMAJOR) - abort(); - } - - /* Lookup stat structure behind the file descriptor. */ - if (fstat(fd, &sb) != 0) - abort(); - - /* Assert character device. */ - if (!S_ISCHR(sb.st_mode)) - abort(); - - /* Assert valid major. */ - if (major(sb.st_rdev) == NODEVMAJOR) - abort(); - - result = (pts == major(sb.st_rdev)); -#else - /* Fallback to ptsname - */ - result = ptsname(fd) == NULL; -#endif - return result; -} - -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; - int saved_flags; - char path[256]; - - /* 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 UV_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) { - /* Reopening a pty in master mode won't work either because the reopened - * pty will be in slave mode (*BSD) or reopening will allocate a new - * master/slave pair (Linux). Therefore check if the fd points to a - * slave device. - */ - if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) - r = uv__open_cloexec(path, O_RDWR); - else - r = -1; - - 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 != UV_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; - } - -#if defined(__APPLE__) - /* Save the fd flags in case we need to restore them due to an error. */ - do - saved_flags = fcntl(fd, F_GETFL); - while (saved_flags == -1 && errno == EINTR); - - if (saved_flags == -1) { - if (newfd != -1) - uv__close(newfd); - return UV__ERR(errno); - } -#endif - - /* Pacify the compiler. */ - (void) &saved_flags; - -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 (!(flags & UV_STREAM_BLOCKING)) - uv__nonblock(fd, 1); - -#if defined(__APPLE__) - r = uv__stream_try_select((uv_stream_t*) tty, &fd); - if (r) { - int rc = r; - if (newfd != -1) - uv__close(newfd); - QUEUE_REMOVE(&tty->handle_queue); - do - r = fcntl(fd, F_SETFL, saved_flags); - while (r == -1 && errno == EINTR); - return rc; - } -#endif - - if (readable) - flags |= UV_STREAM_READABLE; - else - flags |= UV_STREAM_WRITABLE; - - 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); - -#if defined __sun || defined __MVS__ - /* - * 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 UV__ERR(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 UV__ERR(errno); - - tty->mode = mode; - return 0; -} - - -int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { - struct winsize ws; - int err; - - do - err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); - while (err == -1 && errno == EINTR); - - if (err == -1) - return UV__ERR(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) || defined(__DragonFly__) - /* on AIX/DragonFly 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) || defined(__DragonFly__) */ - - 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 UV_EBUSY; /* In uv_tty_set_mode(). */ - - err = 0; - if (orig_termios_fd != -1) - if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) - err = UV__ERR(errno); - - uv_spinlock_unlock(&termios_spinlock); - errno = saved_errno; - - return err; -} diff --git a/3rd/libuv-1.19.2/src/unix/udp.c b/3rd/libuv-1.19.2/src/unix/udp.c deleted file mode 100644 index 74d613b6..00000000 --- a/3rd/libuv-1.19.2/src/unix/udp.c +++ /dev/null @@ -1,902 +0,0 @@ -/* 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 -#include -#include -#include -#include -#if defined(__MVS__) -#include -#endif - -#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, POLLIN | 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 = UV_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, POLLOUT); - if (!uv__io_active(&handle->io_watcher, 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 & POLLIN) - uv__udp_recvmsg(handle); - - if (revents & 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 { - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); - if (buf.base == NULL || 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, UV__ERR(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) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - break; - } - - req->status = (size == -1 ? UV__ERR(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 UV__ERR(errno); -#else - yes = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) - return UV__ERR(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 UV_EINVAL; - - /* Cannot set IPv6-only mode on non-IPv6 socket. */ - if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) - return UV_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) - return err; - } - - if (flags & UV_UDP_IPV6ONLY) { -#ifdef IPV6_V6ONLY - yes = 1; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { - err = UV__ERR(errno); - return err; - } -#else - err = UV_ENOTSUP; - return err; -#endif - } - - if (bind(fd, addr, addrlen)) { - err = UV__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 = UV_EINVAL; - return err; - } - - if (addr->sa_family == AF_INET6) - handle->flags |= UV_HANDLE_IPV6; - - handle->flags |= UV_HANDLE_BOUND; - return 0; -} - - -static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, - int domain, - unsigned int flags) { - union { - struct sockaddr_in6 in6; - struct sockaddr_in in; - struct sockaddr addr; - } taddr; - socklen_t addrlen; - - if (handle->io_watcher.fd != -1) - return 0; - - switch (domain) { - case AF_INET: - { - struct sockaddr_in* addr = &taddr.in; - 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 = &taddr.in6; - 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, &taddr.addr, 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 UV_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); - - /* `uv__udp_sendmsg` may not be able to do non-blocking write straight - * away. In such cases the `io_watcher` has to be queued for asynchronous - * write. - */ - if (!QUEUE_EMPTY(&handle->write_queue)) - uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); - } else { - uv__io_start(handle->loop, &handle->io_watcher, 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 UV_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 || errno == ENOBUFS) - return UV_EAGAIN; - else - return UV__ERR(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 UV_EINVAL; - } - - if (setsockopt(handle->io_watcher.fd, - IPPROTO_IP, - optname, - &mreq, - sizeof(mreq))) { -#if defined(__MVS__) - if (errno == ENXIO) - return UV_ENODEV; -#endif - return UV__ERR(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 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->io_watcher.fd, - IPPROTO_IPV6, - optname, - &mreq, - sizeof(mreq))) { -#if defined(__MVS__) - if (errno == ENXIO) - return UV_ENODEV; -#endif - return UV__ERR(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 UV_EINVAL; - - if (flags & ~0xFF) - return UV_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 UV_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 UV_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 UV__ERR(errno); - - return 0; -} - -static int uv__setsockopt_maybe_char(uv_udp_t* handle, - int option4, - int option6, - int val) { -#if defined(__sun) || defined(_AIX) || defined(__MVS__) - char arg = val; -#elif defined(__OpenBSD__) - unsigned char arg = val; -#else - int arg = val; -#endif - - if (val < 0 || val > 255) - return UV_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 UV__ERR(errno); - } - - return 0; -} - - -int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { - if (ttl < 1 || ttl > 255) - return UV_EINVAL; - -#if defined(__MVS__) - if (!(handle->flags & UV_HANDLE_IPV6)) - return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */ -#endif - -/* - * 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__) || \ - defined(__MVS__) - - return uv__setsockopt(handle, - IP_TTL, - IPV6_UNICAST_HOPS, - &ttl, - sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || - defined(__MVS__) */ - - 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) || defined(__MVS__) - if (handle->flags & UV_HANDLE_IPV6) - return uv__setsockopt(handle, - IP_MULTICAST_TTL, - IPV6_MULTICAST_HOPS, - &ttl, - sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ - - 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) || defined(__MVS__) - if (handle->flags & UV_HANDLE_IPV6) - return uv__setsockopt(handle, - IP_MULTICAST_LOOP, - IPV6_MULTICAST_LOOP, - &on, - sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ - - 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 UV_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 UV__ERR(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 UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getsockname(handle->io_watcher.fd, name, &socklen)) - return UV__ERR(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 UV_EINVAL; - - if (uv__io_active(&handle->io_watcher, POLLIN)) - return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_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, POLLIN); - uv__handle_start(handle); - - return 0; -} - - -int uv__udp_recv_stop(uv_udp_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); - - if (!uv__io_active(&handle->io_watcher, POLLOUT)) - uv__handle_stop(handle); - - handle->alloc_cb = NULL; - handle->recv_cb = NULL; - - return 0; -} diff --git a/3rd/libuv-1.19.2/src/uv-common.c b/3rd/libuv-1.19.2/src/uv-common.c deleted file mode 100644 index bc7d1379..00000000 --- a/3rd/libuv-1.19.2/src/uv-common.c +++ /dev/null @@ -1,664 +0,0 @@ -/* 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 -#include -#include -#include /* NULL */ -#include -#include /* malloc */ -#include /* memset */ - -#if defined(_WIN32) -# include /* malloc */ -#else -# include /* 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) { - int saved_errno; - - /* Libuv expects that free() does not clobber errno. The system allocator - * honors that assumption but custom allocators may not be so careful. - */ - saved_errno = errno; - uv__allocator.local_free(ptr); - errno = saved_errno; -} - -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 = ""; - } - - 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 + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, handle->path, required_len); - *size = required_len; - buffer[required_len] = '\0'; - - 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 -} - -/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows - * systems. So, the memory should be released using free(). On Windows, - * uv__malloc() is used, so use uv__free() to free memory. -*/ -#ifdef _WIN32 -# define uv__fs_scandir_free uv__free -#else -# define uv__fs_scandir_free free -#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__fs_scandir_free(dents[*nbufs]); - - uv__fs_scandir_free(req->ptr); - req->ptr = NULL; -} - - -int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { - uv__dirent_t** dents; - uv__dirent_t* dent; - unsigned int* nbufs; - - /* Check to see if req passed */ - if (req->result < 0) - return req->result; - - /* Ptr will be null if req was canceled or no files found */ - if (!req->ptr) - return UV_EOF; - - nbufs = uv__get_nbufs(req); - assert(nbufs); - - dents = req->ptr; - - /* Free previous entity */ - if (*nbufs > 0) - uv__fs_scandir_free(dents[*nbufs - 1]); - - /* End was already reached */ - if (*nbufs == (unsigned int) req->result) { - uv__fs_scandir_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; -#ifndef NDEBUG - void* saved_data; -#endif - - 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 - saved_data = loop->data; - memset(loop, -1, sizeof(*loop)); - loop->data = saved_data; -#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/3rd/libuv-1.19.2/src/uv-common.h b/3rd/libuv-1.19.2/src/uv-common.h deleted file mode 100644 index d4fa22aa..00000000 --- a/3rd/libuv-1.19.2/src/uv-common.h +++ /dev/null @@ -1,260 +0,0 @@ -/* 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 -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#endif - -#include "uv.h" -#include "tree.h" -#include "queue.h" - -#if EDOM > 0 -# define UV__ERR(x) (-(x)) -#else -# define UV__ERR(x) (x) -#endif - -#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__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ - UV__HANDLE_INTERNAL = 0x8000, - UV__HANDLE_ACTIVE = 0x4000, - UV__HANDLE_REF = 0x2000, - UV__HANDLE_CLOSING = 0 /* no-op on unix */ -}; -#else -# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 -# define UV__SIGNAL_ONE_SHOT 0x100 -# 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) - -/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of - * a circular dependency between src/uv-common.h and src/win/internal.h. - */ -#if defined(_WIN32) -# define UV_REQ_INIT(req, typ) \ - do { \ - (req)->type = (typ); \ - (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \ - } \ - while (0) -#else -# define UV_REQ_INIT(req, typ) \ - do { \ - (req)->type = (typ); \ - } \ - while (0) -#endif - -#define uv__req_init(loop, req, typ) \ - do { \ - UV_REQ_INIT(req, typ); \ - uv__req_register(loop, req); \ - } \ - 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/3rd/libuv-1.19.2/src/uv-data-getter-setters.c b/3rd/libuv-1.19.2/src/uv-data-getter-setters.c deleted file mode 100644 index 533e4a2f..00000000 --- a/3rd/libuv-1.19.2/src/uv-data-getter-setters.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "uv.h" - -const char* uv_handle_type_name(uv_handle_type type) { - switch (type) { -#define XX(uc,lc) case UV_##uc: return #lc; - UV_HANDLE_TYPE_MAP(XX) -#undef XX - case UV_FILE: return "file"; - case UV_HANDLE_TYPE_MAX: - case UV_UNKNOWN_HANDLE: return NULL; - } - return NULL; -} - -uv_handle_type uv_handle_get_type(const uv_handle_t* handle) { - return handle->type; -} - -void* uv_handle_get_data(const uv_handle_t* handle) { - return handle->data; -} - -uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) { - return handle->loop; -} - -void uv_handle_set_data(uv_handle_t* handle, void* data) { - handle->data = data; -} - -const char* uv_req_type_name(uv_req_type type) { - switch (type) { -#define XX(uc,lc) case UV_##uc: return #lc; - UV_REQ_TYPE_MAP(XX) -#undef XX - case UV_REQ_TYPE_MAX: - case UV_UNKNOWN_REQ: return NULL; - } - return NULL; -} - -uv_req_type uv_req_get_type(const uv_req_t* req) { - return req->type; -} - -void* uv_req_get_data(const uv_req_t* req) { - return req->data; -} - -void uv_req_set_data(uv_req_t* req, void* data) { - req->data = data; -} - -size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) { - return stream->write_queue_size; -} - -size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) { - return handle->send_queue_size; -} - -size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) { - return handle->send_queue_count; -} - -uv_pid_t uv_process_get_pid(const uv_process_t* proc) { - return proc->pid; -} - -uv_fs_type uv_fs_get_type(const uv_fs_t* req) { - return req->fs_type; -} - -ssize_t uv_fs_get_result(const uv_fs_t* req) { - return req->result; -} - -void* uv_fs_get_ptr(const uv_fs_t* req) { - return req->ptr; -} - -const char* uv_fs_get_path(const uv_fs_t* req) { - return req->path; -} - -uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) { - return &req->statbuf; -} - -void* uv_loop_get_data(const uv_loop_t* loop) { - return loop->data; -} - -void uv_loop_set_data(uv_loop_t* loop, void* data) { - loop->data = data; -} diff --git a/3rd/libuv-1.19.2/src/version.c b/3rd/libuv-1.19.2/src/version.c deleted file mode 100644 index 686dedd9..00000000 --- a/3rd/libuv-1.19.2/src/version.c +++ /dev/null @@ -1,45 +0,0 @@ -/* 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/3rd/libuv-1.19.2/src/win/async.c b/3rd/libuv-1.19.2/src/win/async.c deleted file mode 100644 index 0b636ed1..00000000 --- a/3rd/libuv-1.19.2/src/win/async.c +++ /dev/null @@ -1,98 +0,0 @@ -/* 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 - -#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(req, 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/3rd/libuv-1.19.2/src/win/atomicops-inl.h b/3rd/libuv-1.19.2/src/win/atomicops-inl.h deleted file mode 100644 index 6d8126f6..00000000 --- a/3rd/libuv-1.19.2/src/win/atomicops-inl.h +++ /dev/null @@ -1,57 +0,0 @@ -/* 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" -#include "internal.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 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/3rd/libuv-1.19.2/src/win/core.c b/3rd/libuv-1.19.2/src/win/core.c deleted file mode 100644 index 9ed4e824..00000000 --- a/3rd/libuv-1.19.2/src/win/core.c +++ /dev/null @@ -1,605 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) -#include -#endif - -#include "uv.h" -#include "internal.h" -#include "queue.h" -#include "handle-inl.h" -#include "req-inl.h" - -/* 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 uv_loop_t** uv__loops; -static int uv__loops_size; -static int uv__loops_capacity; -#define UV__LOOPS_CHUNK_SIZE 8 -static uv_mutex_t uv__loops_lock; - -static void uv__loops_init(void) { - uv_mutex_init(&uv__loops_lock); -} - -static int uv__loops_add(uv_loop_t* loop) { - uv_loop_t** new_loops; - int new_capacity, i; - - uv_mutex_lock(&uv__loops_lock); - - if (uv__loops_size == uv__loops_capacity) { - new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; - new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); - if (!new_loops) - goto failed_loops_realloc; - uv__loops = new_loops; - for (i = uv__loops_capacity; i < new_capacity; ++i) - uv__loops[i] = NULL; - uv__loops_capacity = new_capacity; - } - uv__loops[uv__loops_size] = loop; - ++uv__loops_size; - - uv_mutex_unlock(&uv__loops_lock); - return 0; - -failed_loops_realloc: - uv_mutex_unlock(&uv__loops_lock); - return ERROR_OUTOFMEMORY; -} - -static void uv__loops_remove(uv_loop_t* loop) { - int loop_index; - int smaller_capacity; - uv_loop_t** new_loops; - - uv_mutex_lock(&uv__loops_lock); - - for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { - if (uv__loops[loop_index] == loop) - break; - } - /* If loop was not found, ignore */ - if (loop_index == uv__loops_size) - goto loop_removed; - - uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; - uv__loops[uv__loops_size - 1] = NULL; - --uv__loops_size; - - if (uv__loops_size == 0) { - uv__loops_capacity = 0; - uv__free(uv__loops); - uv__loops = NULL; - goto loop_removed; - } - - /* If we didn't grow to big skip downsizing */ - if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) - goto loop_removed; - - /* Downsize only if more than half of buffer is free */ - smaller_capacity = uv__loops_capacity / 2; - if (uv__loops_size >= smaller_capacity) - goto loop_removed; - new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); - if (!new_loops) - goto loop_removed; - uv__loops = new_loops; - uv__loops_capacity = smaller_capacity; - -loop_removed: - uv_mutex_unlock(&uv__loops_lock); -} - -void uv__wake_all_loops(void) { - int i; - uv_loop_t* loop; - - uv_mutex_lock(&uv__loops_lock); - for (i = 0; i < uv__loops_size; ++i) { - loop = uv__loops[i]; - assert(loop); - if (loop->iocp != INVALID_HANDLE_VALUE) - PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); - } - uv_mutex_unlock(&uv__loops_lock); -} - -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 - - /* Initialize tracking of all uv loops */ - uv__loops_init(); - - /* 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(); - - /* Initialize system wakeup detection */ - uv__init_detect_system_wakeup(); -} - - -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; - - err = uv__loops_add(loop); - if (err) - goto fail_async_init; - - 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; - - uv__loops_remove(loop); - - /* 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_loop_fork(uv_loop_t* loop) { - return UV_ENOSYS; -} - - -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; - int repeat; - uint64_t timeout_time; - - timeout_time = loop->time + timeout; - - for (repeat = 0; ; repeat++) { - 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 target time is reached. - */ - uv_update_time(loop); - if (timeout_time > loop->time) { - timeout = (DWORD)(timeout_time - loop->time); - /* The first call to GetQueuedCompletionStatus should return very - * close to the target time and the second should reach it, but - * this is not stated in the documentation. To make sure a busy - * loop cannot happen, the timeout is increased exponentially - * starting on the third round. - */ - timeout += repeat ? (1 << (repeat - 1)) : 0; - continue; - } - } - break; - } -} - - -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; - int repeat; - uint64_t timeout_time; - - timeout_time = loop->time + timeout; - - for (repeat = 0; ; repeat++) { - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); - - if (success) { - for (i = 0; i < count; i++) { - /* Package was dequeued, but see if it is not a empty package - * meant only to wake us up. - */ - if (overlappeds[i].lpOverlapped) { - 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 target time is reached. - */ - uv_update_time(loop); - if (timeout_time > loop->time) { - timeout = (DWORD)(timeout_time - loop->time); - /* The first call to GetQueuedCompletionStatus should return very - * close to the target time and the second should reach it, but - * this is not stated in the documentation. To make sure a busy - * loop cannot happen, the timeout is increased exponentially - * starting on the third round. - */ - timeout += repeat ? (1 << (repeat - 1)) : 0; - continue; - } - } - break; - } -} - - -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/3rd/libuv-1.19.2/src/win/detect-wakeup.c b/3rd/libuv-1.19.2/src/win/detect-wakeup.c deleted file mode 100644 index 72dfb7a1..00000000 --- a/3rd/libuv-1.19.2/src/win/detect-wakeup.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "uv.h" -#include "internal.h" -#include "winapi.h" - -static void uv__register_system_resume_callback(void); - -void uv__init_detect_system_wakeup(void) { - /* Try registering system power event callback. This is the cleanest - * method, but it will only work on Win8 and above. - */ - uv__register_system_resume_callback(); -} - -static ULONG CALLBACK uv__system_resume_callback(PVOID Context, - ULONG Type, - PVOID Setting) { - if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) - uv__wake_all_loops(); - - return 0; -} - -static void uv__register_system_resume_callback(void) { - _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; - _HPOWERNOTIFY registration_handle; - - if (pPowerRegisterSuspendResumeNotification == NULL) - return; - - recipient.Callback = uv__system_resume_callback; - recipient.Context = NULL; - (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, - &recipient, - ®istration_handle); -} diff --git a/3rd/libuv-1.19.2/src/win/dl.c b/3rd/libuv-1.19.2/src/win/dl.c deleted file mode 100644 index 97ac1c1a..00000000 --- a/3rd/libuv-1.19.2/src/win/dl.c +++ /dev/null @@ -1,133 +0,0 @@ -/* 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, const char* filename, DWORD errorno); - - -int uv_dlopen(const char* filename, uv_lib_t* lib) { - WCHAR filename_w[32768]; - - lib->handle = NULL; - lib->errmsg = NULL; - - if (!MultiByteToWideChar(CP_UTF8, - 0, - filename, - -1, - filename_w, - ARRAY_SIZE(filename_w))) { - return uv__dlerror(lib, filename, GetLastError()); - } - - lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (lib->handle == NULL) { - return uv__dlerror(lib, filename, 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, const char* filename, DWORD errorno) { - DWORD_PTR arg; - DWORD res; - char* msg; - - if (lib->errmsg) { - LocalFree(lib->errmsg); - lib->errmsg = NULL; - } - - if (errorno == 0) - return 0; - - 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 && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) { - msg = lib->errmsg; - lib->errmsg = NULL; - arg = (DWORD_PTR) filename; - res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_ARGUMENT_ARRAY | - FORMAT_MESSAGE_FROM_STRING, - msg, - 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); - LocalFree(msg); - } - - if (!res) - uv__format_fallback_error(lib, errorno); - - return -1; -} diff --git a/3rd/libuv-1.19.2/src/win/error.c b/3rd/libuv-1.19.2/src/win/error.c deleted file mode 100644 index 9b03bfef..00000000 --- a/3rd/libuv-1.19.2/src/win/error.c +++ /dev/null @@ -1,171 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#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); - } - - DebugBreak(); - 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_ELEVATION_REQUIRED: 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/3rd/libuv-1.19.2/src/win/fs-event.c b/3rd/libuv-1.19.2/src/win/fs-event.c deleted file mode 100644 index 95f843ad..00000000 --- a/3rd/libuv-1.19.2/src/win/fs-event.c +++ /dev/null @@ -1,561 +0,0 @@ -/* 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 -#include -#include -#include - -#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 void uv_relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { - size_t relpathlen; - size_t filenamelen = wcslen(filename); - size_t dirlen = wcslen(dir); - if (dirlen > 0 && dir[dirlen - 1] == '\\') - dirlen--; - relpathlen = filenamelen - dirlen - 1; - *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); - if (!*relpath) - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - wcsncpy(*relpath, filename + dirlen + 1, relpathlen); - (*relpath)[relpathlen] = L'\0'; -} - -static int uv_split_path(const WCHAR* filename, WCHAR** dir, - WCHAR** file) { - size_t len, i; - - if (filename == NULL) { - if (dir != NULL) - *dir = NULL; - *file = NULL; - return 0; - } - - len = wcslen(filename); - 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 + 2) * sizeof(WCHAR)); - if (!*dir) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - wcsncpy(*dir, filename, i + 1); - (*dir)[i + 1] = 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(&handle->req, 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_buffer[MAX_PATH]; - WCHAR* short_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 = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * - sizeof(WCHAR); - pathw = (WCHAR*)uv__malloc(name_size); - if (!pathw) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - path, - -1, - 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. */ - 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. */ - short_path = short_path_buffer; - if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { - short_path = NULL; - } - - 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; - } - - assert(is_path_dir ? pathw != NULL : pathw == NULL); - handle->dirw = pathw; - 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; - } - - if (uv__is_active(handle)) - uv__handle_stop(handle); - - 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; -} - - -static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) { - size_t str_len; - - if (str == NULL) - return -1; - - str_len = wcslen(str); - - /* - Since we only care about equality, return early if the strings - aren't the same length - */ - if (str_len != (file_name_len / sizeof(WCHAR))) - return -1; - - return _wcsnicmp(str, file_name, str_len); -} - - -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; - char* filename = NULL; - WCHAR* filenamew = NULL; - WCHAR* 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(!filenamew); - assert(!long_filenamew); - - /* - * Fire the event only if we were asked to watch a directory, - * or if the filename filter matches. - */ - if (handle->dirw || - file_info_cmp(handle->filew, - file_info->FileName, - file_info->FileNameLength) == 0 || - file_info_cmp(handle->short_filew, - file_info->FileName, - file_info->FileNameLength) == 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 / (DWORD)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. */ - uv_relative_path(long_filenamew, - handle->dirw, - &filenamew); - uv__free(long_filenamew); - long_filenamew = filenamew; - sizew = -1; - } else { - /* We couldn't get the long filename, use the one reported. */ - 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. - */ - 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; - } - - /* Convert the filename to utf8. */ - uv__convert_utf16_to_utf8(filenamew, sizew, &filename); - - 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; - 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/3rd/libuv-1.19.2/src/win/fs.c b/3rd/libuv-1.19.2/src/win/fs.c deleted file mode 100644 index 6e0bdc7b..00000000 --- a/3rd/libuv-1.19.2/src/win/fs.c +++ /dev/null @@ -1,2426 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uv.h" -#include "internal.h" -#include "req-inl.h" -#include "handle-inl.h" - -#include - - -#define UV_FS_FREE_PATHS 0x0002 -#define UV_FS_FREE_PTR 0x0008 -#define UV_FS_CLEANEDUP 0x0010 - - -#define INIT(subtype) \ - do { \ - if (req == NULL) \ - return UV_EINVAL; \ - uv_fs_req_init(loop, req, subtype, cb); \ - } \ - while (0) - -#define POST \ - do { \ - if (cb != NULL) { \ - uv__req_register(loop, req); \ - 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) - -#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 = ((uint64_t) ((time) * 10000000ULL)) + \ - 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; - -static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; - -void uv_fs_init(void) { - _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 = 0, 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; - } - - req->path = path; - if (path != NULL && copy_path) { - memcpy(pos, path, path_len); - assert(path_len == buf_sz - (pos - buf)); - req->path = pos; - } - - 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__once_init(); - UV_REQ_INIT(req, 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; - req->fs.info.bufs = NULL; - memset(&req->fs, 0, sizeof(req->fs)); -} - - -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'\\')) { - /* \??\:\ */ - 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\\\ - make sure the final path looks like */ - /* \\\\ */ - 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 \??\:\ as symlink. */ - /* Junctions can also be used as mount points, like \??\Volume{}, */ - /* 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 & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { - case UV_FS_O_RDONLY: - access = FILE_GENERIC_READ; - break; - case UV_FS_O_WRONLY: - access = FILE_GENERIC_WRITE; - break; - case UV_FS_O_RDWR: - access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; - break; - default: - goto einval; - } - - if (flags & UV_FS_O_APPEND) { - access &= ~FILE_WRITE_DATA; - access |= FILE_APPEND_DATA; - } - - /* - * 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. - * We still support exclusive sharing mode, since it is necessary - * for opening raw block devices, otherwise Windows will prevent - * any attempt to write past the master boot record. - */ - if (flags & UV_FS_O_EXLOCK) { - share = 0; - } else { - share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - } - - switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { - case 0: - case UV_FS_O_EXCL: - disposition = OPEN_EXISTING; - break; - case UV_FS_O_CREAT: - disposition = OPEN_ALWAYS; - break; - case UV_FS_O_CREAT | UV_FS_O_EXCL: - case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL: - disposition = CREATE_NEW; - break; - case UV_FS_O_TRUNC: - case UV_FS_O_TRUNC | UV_FS_O_EXCL: - disposition = TRUNCATE_EXISTING; - break; - case UV_FS_O_CREAT | UV_FS_O_TRUNC: - disposition = CREATE_ALWAYS; - break; - default: - goto einval; - } - - attributes |= FILE_ATTRIBUTE_NORMAL; - if (flags & UV_FS_O_CREAT) { - if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { - attributes |= FILE_ATTRIBUTE_READONLY; - } - } - - if (flags & UV_FS_O_TEMPORARY ) { - attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; - access |= DELETE; - } - - if (flags & UV_FS_O_SHORT_LIVED) { - attributes |= FILE_ATTRIBUTE_TEMPORARY; - } - - switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) { - case 0: - break; - case UV_FS_O_SEQUENTIAL: - attributes |= FILE_FLAG_SEQUENTIAL_SCAN; - break; - case UV_FS_O_RANDOM: - attributes |= FILE_FLAG_RANDOM_ACCESS; - break; - default: - goto einval; - } - - if (flags & UV_FS_O_DIRECT) { - attributes |= FILE_FLAG_NO_BUFFERING; - } - - switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) { - case 0: - break; - case UV_FS_O_DSYNC: - case UV_FS_O_SYNC: - attributes |= FILE_FLAG_WRITE_THROUGH; - 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 & UV_FS_O_CREAT) && - !(flags & UV_FS_O_EXCL)) { - /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_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; - LARGE_INTEGER original_position; - LARGE_INTEGER zero_offset; - int restore_position; - - VERIFY_FD(fd, req); - - zero_offset.QuadPart = 0; - restore_position = 0; - 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; - if (SetFilePointerEx(handle, zero_offset, &original_position, - FILE_CURRENT)) { - restore_position = 1; - } - } 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 (restore_position) - SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); - - 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; - LARGE_INTEGER original_position; - LARGE_INTEGER zero_offset; - int restore_position; - - VERIFY_FD(fd, req); - - zero_offset.QuadPart = 0; - restore_position = 0; - 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; - if (SetFilePointerEx(handle, zero_offset, &original_position, - FILE_CURRENT)) { - restore_position = 1; - } - } 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 (restore_position) - SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); - - 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. It has been reported that - * the SharePoint driver includes the terminating zero byte in - * the filename length. Strip those first. - */ - while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') - wchar_len -= 1; - - if (wchar_len == 0) - continue; - 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, - int do_lstat) { - 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; - - /* - * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism - * by which filesystem drivers can intercept and alter file system requests. - * - * The only reparse points we care about are symlinks and mount points, both - * of which are treated as POSIX symlinks. Further, we only care when - * invoked via lstat, which seeks information about the link instead of its - * target. Otherwise, reparse points must be treated as regular files. - */ - if (do_lstat && - (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - /* - * If reading the link fails, the reparse point is not a symlink and needs - * to be treated as a regular file. The higher level lstat function will - * detect this failure and retry without do_lstat if appropriate. - */ - if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) - return -1; - statbuf->st_mode |= S_IFLNK; - } - - if (statbuf->st_mode == 0) { - 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. - * - * 4096 is the minimum required to be compatible with newer Advanced Format - * drives (which have 4096 bytes per physical sector), and to be backwards - * compatible with older drives (which have 512 bytes per physical sector). - */ - statbuf->st_blksize = 4096; - - /* 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, do_lstat) != 0) { - DWORD error = GetLastError(); - if (do_lstat && - (error == ERROR_SYMLINK_NOT_SUPPORTED || - error == ERROR_NOT_A_REPARSE_POINT)) { - /* 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) != 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__copyfile(uv_fs_t* req) { - int flags; - int overwrite; - - flags = req->fs.info.file_flags; - overwrite = flags & UV_FS_COPYFILE_EXCL; - - if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - return; - } - - SET_REQ_RESULT(req, 0); -} - - -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->fs.info.mode & 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(atime, &filetime_a); - TIME_T_TO_FILETIME(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; - WCHAR* new_pathw; - int flags; - int err; - - pathw = req->file.pathw; - new_pathw = req->fs.info.new_pathw; - - if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) { - fs__create_junction(req, pathw, new_pathw); - return; - } - if (!pCreateSymbolicLinkW) { - SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; - } - - if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) - flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; - else - flags = uv__file_symlink_usermode_flag; - - if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { - SET_REQ_RESULT(req, 0); - return; - } - - /* Something went wrong. We will test if it is because of user-mode - * symlinks. - */ - err = GetLastError(); - if (err == ERROR_INVALID_PARAMETER && - flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) { - /* This system does not support user-mode symlinks. We will clear the - * unsupported flag and retry. - */ - uv__file_symlink_usermode_flag = 0; - fs__symlink(req); - } else { - SET_REQ_WIN32_ERROR(req, err); - } -} - - -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 = NULL; - WCHAR* w_realpath_buf; - - w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); - if (w_realpath_len == 0) { - return -1; - } - - w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); - if (w_realpath_buf == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; - } - w_realpath_ptr = w_realpath_buf; - - if (pGetFinalPathNameByHandleW(handle, - w_realpath_ptr, - w_realpath_len, - VOLUME_NAME_DOS) == 0) { - uv__free(w_realpath_buf); - 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_realpath_ptr += 6; - *w_realpath_ptr = L'\\'; - w_realpath_len -= 6; - } else if (wcsncmp(w_realpath_ptr, - LONG_PATH_PREFIX, - LONG_PATH_PREFIX_LEN) == 0) { - w_realpath_ptr += 4; - w_realpath_len -= 4; - } else { - uv__free(w_realpath_buf); - SetLastError(ERROR_INVALID_HANDLE); - return -1; - } - - r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); - uv__free(w_realpath_buf); - 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(COPYFILE, copyfile) - 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 == NULL) - return; - - 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) { - if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) - uv__fs_scandir_cleanup(req); - else - uv__free(req->ptr); - } - - if (req->fs.info.bufs != req->fs.info.bufsml) - uv__free(req->fs.info.bufs); - - req->path = NULL; - req->file.pathw = NULL; - req->fs.info.new_pathw = NULL; - req->fs.info.bufs = 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; - - INIT(UV_FS_OPEN); - 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; - POST; -} - - -int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - INIT(UV_FS_CLOSE); - req->file.fd = fd; - POST; -} - - -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) { - INIT(UV_FS_READ); - - if (bufs == NULL || nbufs == 0) - return UV_EINVAL; - - 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; - POST; -} - - -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) { - INIT(UV_FS_WRITE); - - if (bufs == NULL || nbufs == 0) - return UV_EINVAL; - - 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; - POST; -} - - -int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_UNLINK); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_MKDIR); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - req->fs.info.mode = mode; - POST; -} - - -int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_MKDTEMP); - err = fs__capture_path(req, tpl, NULL, TRUE); - if (err) - return uv_translate_sys_error(err); - - POST; -} - - -int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { - int err; - - INIT(UV_FS_RMDIR); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_SCANDIR); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - req->fs.info.file_flags = flags; - POST; -} - - -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; - - INIT(UV_FS_LINK); - err = fs__capture_path(req, path, new_path, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - 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) { - int err; - - INIT(UV_FS_SYMLINK); - err = fs__capture_path(req, path, new_path, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - req->fs.info.file_flags = flags; - POST; -} - - -int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_READLINK); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_REALPATH); - - if (!path) { - return UV_EINVAL; - } - - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - 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) { - int err; - - INIT(UV_FS_CHOWN); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -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) { - INIT(UV_FS_FCHOWN); - POST; -} - - -int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { - int err; - - INIT(UV_FS_STAT); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { - int err; - - INIT(UV_FS_LSTAT); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - INIT(UV_FS_FSTAT); - req->file.fd = fd; - POST; -} - - -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; - - INIT(UV_FS_RENAME); - err = fs__capture_path(req, path, new_path, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - POST; -} - - -int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - INIT(UV_FS_FSYNC); - req->file.fd = fd; - POST; -} - - -int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - INIT(UV_FS_FDATASYNC); - req->file.fd = fd; - POST; -} - - -int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, - int64_t offset, uv_fs_cb cb) { - INIT(UV_FS_FTRUNCATE); - req->file.fd = fd; - req->fs.info.offset = offset; - POST; -} - - -int uv_fs_copyfile(uv_loop_t* loop, - uv_fs_t* req, - const char* path, - const char* new_path, - int flags, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_COPYFILE); - - if (flags & ~UV_FS_COPYFILE_EXCL) - return UV_EINVAL; - - err = fs__capture_path(req, path, new_path, cb != NULL); - - if (err) - return uv_translate_sys_error(err); - - req->fs.info.file_flags = flags; - POST; -} - - -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) { - INIT(UV_FS_SENDFILE); - 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; - POST; -} - - -int uv_fs_access(uv_loop_t* loop, - uv_fs_t* req, - const char* path, - int flags, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_ACCESS); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) - return uv_translate_sys_error(err); - - req->fs.info.mode = flags; - POST; -} - - -int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, - uv_fs_cb cb) { - int err; - - INIT(UV_FS_CHMOD); - err = fs__capture_path(req, path, NULL, cb != NULL); - if (err) { - return uv_translate_sys_error(err); - } - - req->fs.info.mode = mode; - POST; -} - - -int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, - uv_fs_cb cb) { - INIT(UV_FS_FCHMOD); - req->file.fd = fd; - req->fs.info.mode = mode; - POST; -} - - -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; - - INIT(UV_FS_UTIME); - 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; - POST; -} - - -int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, - double mtime, uv_fs_cb cb) { - INIT(UV_FS_FUTIME); - req->file.fd = fd; - req->fs.time.atime = atime; - req->fs.time.mtime = mtime; - POST; -} diff --git a/3rd/libuv-1.19.2/src/win/getaddrinfo.c b/3rd/libuv-1.19.2/src/win/getaddrinfo.c deleted file mode 100644 index 282d919c..00000000 --- a/3rd/libuv-1.19.2/src/win/getaddrinfo.c +++ /dev/null @@ -1,453 +0,0 @@ -/* 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 - -#include "uv.h" -#include "internal.h" -#include "req-inl.h" - -/* EAI_* constants. */ -#include - -/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */ -#include - -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) - -#ifndef NDIS_IF_MAX_STRING_SIZE -#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE -#endif - -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 = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - 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 = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - assert(name_len > 0); - assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len, - NULL, - NULL); - 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)) { - return UV_EINVAL; - } - - UV_REQ_INIT(req, UV_GETADDRINFO); - req->getaddrinfo_cb = getaddrinfo_cb; - req->addrinfo = NULL; - req->loop = loop; - req->retcode = 0; - - /* calculate required memory size for all input values */ - if (node != NULL) { - nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * - sizeof(WCHAR)); - if (nodesize == 0) { - err = GetLastError(); - goto error; - } - } - - if (service != NULL) { - servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - 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 (MultiByteToWideChar(CP_UTF8, - 0, - node, - -1, - (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 (MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - (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); -} - -int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { - NET_LUID luid; - wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ - DWORD bufsize; - int r; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - r = ConvertInterfaceIndexToLuid(ifindex, &luid); - - if (r != 0) - return uv_translate_sys_error(r); - - r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); - - if (r != 0) - return uv_translate_sys_error(r); - - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - wname, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; -} - -int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { - int r; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - r = snprintf(buffer, *size, "%d", ifindex); - - if (r < 0) - return uv_translate_sys_error(r); - - if (r >= (int) *size) { - *size = r + 1; - return UV_ENOBUFS; - } - - *size = r; - return 0; -} diff --git a/3rd/libuv-1.19.2/src/win/getnameinfo.c b/3rd/libuv-1.19.2/src/win/getnameinfo.c deleted file mode 100644 index 9f10cd2a..00000000 --- a/3rd/libuv-1.19.2/src/win/getnameinfo.c +++ /dev/null @@ -1,149 +0,0 @@ -/* 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 -#include - -#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(req, UV_GETNAMEINFO); - uv__req_register(loop, req); - - req->getnameinfo_cb = getnameinfo_cb; - req->flags = flags; - 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/3rd/libuv-1.19.2/src/win/handle-inl.h b/3rd/libuv-1.19.2/src/win/handle-inl.h deleted file mode 100644 index 8d0334cc..00000000 --- a/3rd/libuv-1.19.2/src/win/handle-inl.h +++ /dev/null @@ -1,179 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/src/win/handle.c b/3rd/libuv-1.19.2/src/win/handle.c deleted file mode 100644 index 39150702..00000000 --- a/3rd/libuv-1.19.2/src/win/handle.c +++ /dev/null @@ -1,159 +0,0 @@ -/* 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 -#include -#include - -#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)); -} - - -uv_os_fd_t uv_get_osfhandle(int fd) { - return uv__get_osfhandle(fd); -} diff --git a/3rd/libuv-1.19.2/src/win/internal.h b/3rd/libuv-1.19.2/src/win/internal.h deleted file mode 100644 index 217fcdb5..00000000 --- a/3rd/libuv-1.19.2/src/win/internal.h +++ /dev/null @@ -1,394 +0,0 @@ -/* 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 -#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 - -/* 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(void); - -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_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(void); - - -/* - * 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(void); -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(void); - - -/* - * 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(void); - -uint64_t uv__hrtime(double scale); -int uv_current_pid(void); -__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); -int uv__getpwuid_r(uv_passwd_t* pwd); -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); - - -/* - * 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(void); - - -/* - * Winsock utility functions - */ -void uv_winsock_init(void); - -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_; - -/* - * Wake all loops with fake message - */ -void uv__wake_all_loops(void); - -/* - * Init system wake-up detection - */ -void uv__init_detect_system_wakeup(void); - -#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/loop-watcher.c b/3rd/libuv-1.19.2/src/win/loop-watcher.c deleted file mode 100644 index 20e4509f..00000000 --- a/3rd/libuv-1.19.2/src/win/loop-watcher.c +++ /dev/null @@ -1,122 +0,0 @@ -/* 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 - -#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/3rd/libuv-1.19.2/src/win/pipe.c b/3rd/libuv-1.19.2/src/win/pipe.c deleted file mode 100644 index 1a7c4dc1..00000000 --- a/3rd/libuv-1.19.2/src/win/pipe.c +++ /dev/null @@ -1,2214 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#include "uv.h" -#include "internal.h" -#include "handle-inl.h" -#include "stream-inl.h" -#include "req-inl.h" - -#include -#include - -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-%lu", 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(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_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 | WRITE_DAC, - 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, ¤t_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(req, UV_ACCEPT); - req->data = handle; - req->pipeHandle = INVALID_HANDLE_VALUE; - req->next_pending = NULL; - } - - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = (WCHAR*)uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - 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 | WRITE_DAC, - 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(req, UV_CONNECT); - req->handle = (uv_stream_t*) handle; - req->cb = cb; - - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = (WCHAR*)uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - 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 | WRITE_DAC, - 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, FALSE, DUPLICATE_SAME_ACCESS)) { - handle->pipe.conn.readfile_thread = hThread; - } else { - hThread = NULL; - } - uv_mutex_unlock(m); - } -restart_readfile: - if (handle->flags & UV_HANDLE_READING) { - 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 */ - } - } - } - } else { - result = 1; /* successfully aborted read before it even started */ - } - 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(req, 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(ipc_header_req, 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_OPERATION_ABORTED) { - /* do nothing (equivalent to EINTR) */ - } - else 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); - } - } - - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, avail, &buf); - if (buf.base == NULL || 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; - - uv__once_init(); - /* 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_os_getppid(); - 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; - - uv__once_init(); - 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 + 1; - 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; - buffer[addrlen] = '\0'; - - err = 0; - -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; -} - -int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; - PACL old_dacl, new_dacl; - PSECURITY_DESCRIPTOR sd; - EXPLICIT_ACCESS ea; - PSID everyone; - int error; - - if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE) - return UV_EBADF; - - if (mode != UV_READABLE && - mode != UV_WRITABLE && - mode != (UV_WRITABLE | UV_READABLE)) - return UV_EINVAL; - - if (!AllocateAndInitializeSid(&sid_world, - 1, - SECURITY_WORLD_RID, - 0, 0, 0, 0, 0, 0, 0, - &everyone)) { - error = GetLastError(); - goto done; - } - - if (GetSecurityInfo(handle->handle, - SE_KERNEL_OBJECT, - DACL_SECURITY_INFORMATION, - NULL, - NULL, - &old_dacl, - NULL, - &sd)) { - error = GetLastError(); - goto clean_sid; - } - - memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); - if (mode & UV_READABLE) - ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; - if (mode & UV_WRITABLE) - ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; - ea.grfAccessPermissions |= SYNCHRONIZE; - ea.grfAccessMode = SET_ACCESS; - ea.grfInheritance = NO_INHERITANCE; - ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - ea.Trustee.ptstrName = (LPTSTR)everyone; - - if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { - error = GetLastError(); - goto clean_sd; - } - - if (SetSecurityInfo(handle->handle, - SE_KERNEL_OBJECT, - DACL_SECURITY_INFORMATION, - NULL, - NULL, - new_dacl, - NULL)) { - error = GetLastError(); - goto clean_dacl; - } - - error = 0; - -clean_dacl: - LocalFree((HLOCAL) new_dacl); -clean_sd: - LocalFree((HLOCAL) sd); -clean_sid: - FreeSid(everyone); -done: - return uv_translate_sys_error(error); -} diff --git a/3rd/libuv-1.19.2/src/win/poll.c b/3rd/libuv-1.19.2/src/win/poll.c deleted file mode 100644 index a648ba71..00000000 --- a/3rd/libuv-1.19.2/src/win/poll.c +++ /dev/null @@ -1,644 +0,0 @@ -/* 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 -#include - -#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(void) { - uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); - return &overlapped_dummy_; -} - - -static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) { - 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 { - /* Just wait until there's an unsubmitted req. */ - /* This will happen almost immediately as one of the 2 outstanding */ - /* requests is about to return. When this happens, */ - /* uv__fast_poll_process_poll_req will be called, and the pending */ - /* events, if needed, will be processed in a subsequent request. */ - 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; - } else { - if (handle->events & UV_DISCONNECT) { - afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; - } - } - 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_DISCONNECT) != 0) { - events |= UV_DISCONNECT; - } - } - 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 | UV_DISCONNECT)) == 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(&handle->poll_req_1, UV_POLL_REQ); - handle->poll_req_1.data = handle; - - handle->submitted_events_2 = 0; - UV_REQ_INIT(&handle->poll_req_2, 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/3rd/libuv-1.19.2/src/win/process-stdio.c b/3rd/libuv-1.19.2/src/win/process-stdio.c deleted file mode 100644 index 032e3093..00000000 --- a/3rd/libuv-1.19.2/src/win/process-stdio.c +++ /dev/null @@ -1,511 +0,0 @@ -/* 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 -#include -#include -#include - -#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; - break; - - 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/3rd/libuv-1.19.2/src/win/process.c b/3rd/libuv-1.19.2/src/win/process.c deleted file mode 100644 index 75235222..00000000 --- a/3rd/libuv-1.19.2/src/win/process.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include /* 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(&handle->exit_req, 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; - - /* If path is quoted, find quote end */ - if (*dir_start == L'"' || *dir_start == L'\'') { - dir_end = wcschr(dir_start + 1, *dir_start); - if (dir_end == NULL) { - dir_end = wcschr(dir_start, L'\0'); - } - } - /* Slice until the next ; or \0 is found */ - dir_end = wcschr(dir_end, 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); - - process_flags = CREATE_UNICODE_ENVIRONMENT; - - if (options->flags & UV_PROCESS_WINDOWS_HIDE) { - /* Avoid creating console window if stdio is not inherited. */ - for (i = 0; i < options->stdio_count; i++) { - if (options->stdio[i].flags & UV_INHERIT_FD) - break; - if (i == options->stdio_count - 1) - process_flags |= CREATE_NO_WINDOW; - } - - /* Use SW_HIDE to avoid any potential process window. */ - startup.wShowWindow = SW_HIDE; - } else { - startup.wShowWindow = SW_SHOWDEFAULT; - } - - 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) { - if (signum < 0 || signum >= NSIG) { - return UV_EINVAL; - } - - 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; - - if (pid == 0) { - process_handle = GetCurrentProcess(); - } else { - 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/3rd/libuv-1.19.2/src/win/req-inl.h b/3rd/libuv-1.19.2/src/win/req-inl.h deleted file mode 100644 index f2513b7d..00000000 --- a/3rd/libuv-1.19.2/src/win/req-inl.h +++ /dev/null @@ -1,221 +0,0 @@ -/* 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 - -#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))) - -/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency - * between src/uv-common.h and src/win/internal.h. - */ -#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 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/3rd/libuv-1.19.2/src/win/req.c b/3rd/libuv-1.19.2/src/win/req.c deleted file mode 100644 index 111cc5e2..00000000 --- a/3rd/libuv-1.19.2/src/win/req.c +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 - -#include "uv.h" -#include "internal.h" diff --git a/3rd/libuv-1.19.2/src/win/signal.c b/3rd/libuv-1.19.2/src/win/signal.c deleted file mode 100644 index a174da1f..00000000 --- a/3rd/libuv-1.19.2/src/win/signal.c +++ /dev/null @@ -1,277 +0,0 @@ -/* 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 -#include - -#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 CRITICAL_SECTION uv__signal_lock; - -static BOOL WINAPI uv__signal_control_handler(DWORD type); - -int uv__signal_start(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum, - int oneshot); - -void uv_signals_init(void) { - InitializeCriticalSection(&uv__signal_lock); - if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) - abort(); -} - - -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; - - 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 (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) - continue; - - if (!previous) { - POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); - } - - dispatched = 1; - if (handle->flags & UV__SIGNAL_ONE_SHOT) - handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; - } - - 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; - } -} - - -int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { - uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); - handle->pending_signum = 0; - handle->signum = 0; - handle->signal_cb = NULL; - - UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ); - handle->signal_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); - - 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) { - return uv__signal_start(handle, signal_cb, signum, 0); -} - - -int uv_signal_start_oneshot(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum) { - return uv__signal_start(handle, signal_cb, signum, 1); -} - - -int uv__signal_start(uv_signal_t* handle, - uv_signal_cb signal_cb, - int signum, - int oneshot) { - /* Test for invalid signal values. */ - if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) - 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); - - handle->signum = signum; - if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; - - 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__SIGNAL_ONE_SHOT) - uv_signal_stop(handle); - - 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/3rd/libuv-1.19.2/src/win/snprintf.c b/3rd/libuv-1.19.2/src/win/snprintf.c deleted file mode 100644 index 776c0e39..00000000 --- a/3rd/libuv-1.19.2/src/win/snprintf.c +++ /dev/null @@ -1,42 +0,0 @@ -/* 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 -#include - -/* 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/3rd/libuv-1.19.2/src/win/stream-inl.h b/3rd/libuv-1.19.2/src/win/stream-inl.h deleted file mode 100644 index dba03747..00000000 --- a/3rd/libuv-1.19.2/src/win/stream-inl.h +++ /dev/null @@ -1,54 +0,0 @@ -/* 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 - -#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; - handle->stream.conn.shutdown_req = NULL; -} - - -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->read_req, UV_READ); - handle->read_req.event_handle = NULL; - handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - handle->read_req.data = handle; -} - - -#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/stream.c b/3rd/libuv-1.19.2/src/win/stream.c deleted file mode 100644 index 13cbfdcb..00000000 --- a/3rd/libuv-1.19.2/src/win/stream.c +++ /dev/null @@ -1,248 +0,0 @@ -/* 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 - -#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(req, 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/3rd/libuv-1.19.2/src/win/tcp.c b/3rd/libuv-1.19.2/src/win/tcp.c deleted file mode 100644 index fd6efbaf..00000000 --- a/3rd/libuv-1.19.2/src/win/tcp.c +++ /dev/null @@ -1,1525 +0,0 @@ -/* 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 -#include - -#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->tcp.conn.read_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); - if (handle->tcp.conn.read_buffer.base == NULL || - 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) { - 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(req, 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(req, 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; - struct sockaddr_storage converted; - BOOL success; - DWORD bytes; - int err; - - err = uv__convert_to_localhost_if_unspecified(addr, &converted); - if (err) - return 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(req, 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, - (const struct sockaddr*) &converted, - 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(req, 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) { - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); - if (buf.base == NULL || 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; - struct sockaddr_storage saddr; - int saddr_len; - - /* 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); - } - - /* Support already active socket. */ - saddr_len = sizeof(saddr); - if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { - /* Socket is already bound. */ - handle->flags |= UV_HANDLE_BOUND; - saddr_len = sizeof(saddr); - if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { - /* Socket is already connected. */ - uv_connection_init((uv_stream_t*) handle); - handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; - } - } - - 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/3rd/libuv-1.19.2/src/win/thread.c b/3rd/libuv-1.19.2/src/win/thread.c deleted file mode 100644 index 9eaad77c..00000000 --- a/3rd/libuv-1.19.2/src/win/thread.c +++ /dev/null @@ -1,703 +0,0 @@ -/* 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 -#include -#include - -#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; - MemoryBarrier(); /* For feature parity with pthread_join(). */ - 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; -} - - -int uv_mutex_init_recursive(uv_mutex_t* mutex) { - return uv_mutex_init(mutex); -} - - -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 here since Win32 manual-reset events */ - /* maintain state when used with . This avoids the "lost wakeup" */ - /* bug. */ - uv_mutex_unlock(mutex); - - /* Wait for either event to become signaled due to being */ - /* called or 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 . */ - 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 . */ - 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/3rd/libuv-1.19.2/src/win/timer.c b/3rd/libuv-1.19.2/src/win/timer.c deleted file mode 100644 index 7e006fed..00000000 --- a/3rd/libuv-1.19.2/src/win/timer.c +++ /dev/null @@ -1,195 +0,0 @@ -/* 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 -#include - -#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); - assert(new_time >= loop->time); - loop->time = new_time; -} - - -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/3rd/libuv-1.19.2/src/win/tty.c b/3rd/libuv-1.19.2/src/win/tty.c deleted file mode 100644 index c822431e..00000000 --- a/3rd/libuv-1.19.2/src/win/tty.c +++ /dev/null @@ -1,2328 +0,0 @@ -/* 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 -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#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" - -#ifndef InterlockedOr -# define InterlockedOr _InterlockedOr -#endif - -#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 -#define MAX_CONSOLE_CHAR 8192 - -#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#endif - -static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); -static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); -static int uv__cancel_read_console(uv_tty_t* handle); - - -/* Null uv_buf_t */ -static const uv_buf_t uv_null_buf_ = { 0, NULL }; - -enum uv__read_console_status_e { - NOT_STARTED, - IN_PROGRESS, - TRAP_REQUESTED, - COMPLETED -}; - -static volatile LONG uv__read_console_status = NOT_STARTED; -static volatile LONG uv__restore_screen_state; -static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; - - -/* - * 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; - -/* The console window size - * We keep this separate from uv_tty_virtual_*. We use those values to only - * handle signalling SIGWINCH - */ - -static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; -static int uv__tty_console_height = -1; -static int uv__tty_console_width = -1; - -static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); -static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, - DWORD event, - HWND hwnd, - LONG idObject, - LONG idChild, - DWORD dwEventThread, - DWORD dwmsEventTime); - -/* We use a semaphore rather than a mutex or critical section because in some - cases (uv__cancel_read_console) we need take the lock in the main thread and - release it in another thread. Using a semaphore ensures that in such - scenario the main thread will still block when trying to acquire the lock. */ -static uv_sem_t uv_tty_output_lock; - -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; - -typedef enum { - UV_SUPPORTED, - UV_UNCHECKED, - UV_UNSUPPORTED -} uv_vtermstate_t; -/* Determine whether or not ANSI support is enabled. */ -static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; -static void uv__determine_vterm_state(HANDLE handle); - -void uv_console_init(void) { - if (uv_sem_init(&uv_tty_output_lock, 1)) - abort(); - uv__tty_console_handle = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (uv__tty_console_handle != NULL) { - QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, - NULL, - WT_EXECUTELONGFUNCTION); - } -} - - -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; - - uv__once_init(); - 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. */ - uv_sem_wait(&uv_tty_output_lock); - - if (uv__vterm_state == UV_UNCHECKED) - uv__determine_vterm_state(handle); - - /* Remember the original console text attributes. */ - uv_tty_capture_initial_style(&screen_buffer_info); - - uv_tty_update_virtual_window(&screen_buffer_info); - - uv_sem_post(&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; - /* TODO: remove me in v2.x. */ - tty->tty.rd.unused_ = 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 = NULL; - uv_read_cb read_cb = NULL; - 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; - default: - return UV_EINVAL; - } - - /* 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; - err = uv_tty_read_stop(tty); - if (err) { - return uv_translate_sys_error(err); - } - } else { - was_reading = 0; - } - - uv_sem_wait(&uv_tty_output_lock); - if (!SetConsoleMode(tty->handle, flags)) { - err = uv_translate_sys_error(GetLastError()); - uv_sem_post(&uv_tty_output_lock); - return err; - } - uv_sem_post(&uv_tty_output_lock); - - /* 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()); - } - - uv_sem_wait(&uv_tty_output_lock); - uv_tty_update_virtual_window(&info); - uv_sem_post(&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; - LONG status; - COORD pos; - BOOL read_console_success; - - 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; - - status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); - if (status == TRAP_REQUESTED) { - SET_REQ_SUCCESS(req); - req->u.io.overlapped.InternalHigh = 0; - POST_COMPLETION_FOR_REQ(loop, req); - return 0; - } - - read_console_success = ReadConsoleW(handle->handle, - (void*) utf16, - chars, - &read_chars, - NULL); - - if (read_console_success) { - 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()); - } - - status = InterlockedExchange(&uv__read_console_status, COMPLETED); - - if (status == TRAP_REQUESTED) { - /* If we canceled the read by sending a VK_RETURN event, restore the - screen state to undo the visual effect of the VK_RETURN */ - if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { - HANDLE active_screen_buffer; - active_screen_buffer = CreateFileA("conout$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (active_screen_buffer != INVALID_HANDLE_VALUE) { - pos = uv__saved_screen_state.dwCursorPosition; - - /* If the cursor was at the bottom line of the screen buffer, the - VK_RETURN would have caused the buffer contents to scroll up by one - line. The right position to reset the cursor to is therefore one line - higher */ - if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) - pos.Y--; - - SetConsoleCursorPosition(active_screen_buffer, pos); - CloseHandle(active_screen_buffer); - } - } - uv_sem_post(&uv_tty_output_lock); - } - 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->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); - if (handle->tty.rd.read_line_buffer.base == NULL || - 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); - - /* Reset flags No locking is required since there cannot be a line read - in progress. We are also relying on the memory barrier provided by - QueueUserWorkItem*/ - uv__restore_screen_state = FALSE; - uv__read_console_status = NOT_STARTED; - 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); - } - - 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--; - - /* Ignore other events that are not key 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) { - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); - if (buf.base == NULL || 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) { - /* 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 { - if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { - /* 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); - } else { - handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; - handle->read_cb((uv_stream_t*) handle, 0, &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); - /* Make sure no attempt is made to insert it again until it's handled. */ - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; - return 0; - } - - uv_tty_queue_read(loop, handle); - - return 0; -} - - -int uv_tty_read_stop(uv_tty_t* handle) { - INPUT_RECORD record; - DWORD written, err; - - handle->flags &= ~UV_HANDLE_READING; - DECREASE_ACTIVE_COUNT(handle->loop, handle); - - if (!(handle->flags & UV_HANDLE_READ_PENDING)) - return 0; - - if (handle->flags & UV_HANDLE_TTY_RAW) { - /* Cancel raw read */ - /* Write some bullshit event to force the console wait to return. */ - memset(&record, 0, sizeof record); - if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { - return GetLastError(); - } - } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { - /* Cancel line-buffered read if not already pending */ - err = uv__cancel_read_console(handle); - if (err) - return err; - - handle->flags |= UV_HANDLE_CANCELLATION_PENDING; - } - - return 0; -} - -static int uv__cancel_read_console(uv_tty_t* handle) { - HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; - INPUT_RECORD record; - DWORD written; - DWORD err = 0; - LONG status; - - assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); - - /* Hold the output lock during the cancellation, to ensure that further - writes don't interfere with the screen state. It will be the ReadConsole - thread's responsibility to release the lock. */ - uv_sem_wait(&uv_tty_output_lock); - status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); - if (status != IN_PROGRESS) { - /* Either we have managed to set a trap for the other thread before - ReadConsole is called, or ReadConsole has returned because the user - has pressed ENTER. In either case, there is nothing else to do. */ - uv_sem_post(&uv_tty_output_lock); - return 0; - } - - /* Save screen state before sending the VK_RETURN event */ - active_screen_buffer = CreateFileA("conout$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (active_screen_buffer != INVALID_HANDLE_VALUE && - GetConsoleScreenBufferInfo(active_screen_buffer, - &uv__saved_screen_state)) { - InterlockedOr(&uv__restore_screen_state, 1); - } - - /* Write enter key event to force the console wait to return. */ - record.EventType = KEY_EVENT; - record.Event.KeyEvent.bKeyDown = TRUE; - record.Event.KeyEvent.wRepeatCount = 1; - record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - record.Event.KeyEvent.wVirtualScanCode = - MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); - record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; - record.Event.KeyEvent.dwControlKeyState = 0; - if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) - err = GetLastError(); - - if (active_screen_buffer != INVALID_HANDLE_VALUE) - CloseHandle(active_screen_buffer); - - return err; -} - - -static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { - 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; - } -} - - -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[MAX_CONSOLE_CHAR]; - WCHAR* utf16_buffer; - DWORD utf16_buf_used = 0; - unsigned int i, len, max_len, pos; - int allocate = 0; - -#define FLUSH_TEXT() \ - do { \ - pos = 0; \ - do { \ - len = utf16_buf_used - pos; \ - if (len > MAX_CONSOLE_CHAR) \ - len = MAX_CONSOLE_CHAR; \ - uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \ - pos += len; \ - } while (pos < utf16_buf_used); \ - if (allocate) { \ - uv__free(utf16_buffer); \ - allocate = 0; \ - utf16_buffer = utf16_buf; \ - } \ - 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; - - utf16_buffer = utf16_buf; - - uv_sem_wait(&uv_tty_output_lock); - - for (i = 0; i < nbufs; i++) { - uv_buf_t buf = bufs[i]; - unsigned int j; - - if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { - utf16_buf_used = MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - NULL, - 0); - - if (utf16_buf_used == 0) { - *error = GetLastError(); - break; - } - - max_len = (utf16_buf_used + 1) * sizeof(WCHAR); - allocate = max_len > MAX_CONSOLE_CHAR; - if (allocate) - utf16_buffer = uv__malloc(max_len); - if (!MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - utf16_buffer, - utf16_buf_used)) { - if (allocate) - uv__free(utf16_buffer); - *error = GetLastError(); - break; - } - - FLUSH_TEXT(); - - continue; - } - - 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; - - uv_sem_post(&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(req, 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 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; -} - -/* Determine whether or not this version of windows supports - * proper ANSI color codes. Should be supported as of windows - * 10 version 1511, build number 10.0.10586. - */ -static void uv__determine_vterm_state(HANDLE handle) { - DWORD dwMode = 0; - - if (!GetConsoleMode(handle, &dwMode)) { - uv__vterm_state = UV_UNSUPPORTED; - return; - } - - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(handle, dwMode)) { - uv__vterm_state = UV_UNSUPPORTED; - return; - } - - uv__vterm_state = UV_SUPPORTED; -} - -static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { - CONSOLE_SCREEN_BUFFER_INFO sb_info; - MSG msg; - - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) - return 0; - - uv__tty_console_width = sb_info.dwSize.X; - uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; - - if (pSetWinEventHook == NULL) - return 0; - - if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, - EVENT_CONSOLE_LAYOUT, - NULL, - uv__tty_console_resize_event, - 0, - 0, - WINEVENT_OUTOFCONTEXT)) - return 0; - - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return 0; -} - -static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, - DWORD event, - HWND hwnd, - LONG idObject, - LONG idChild, - DWORD dwEventThread, - DWORD dwmsEventTime) { - CONSOLE_SCREEN_BUFFER_INFO sb_info; - int width, height; - - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) - return; - - width = sb_info.dwSize.X; - height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; - - if (width != uv__tty_console_width || height != uv__tty_console_height) { - uv__tty_console_width = width; - uv__tty_console_height = height; - uv__signal_dispatch(SIGWINCH); - } -} diff --git a/3rd/libuv-1.19.2/src/win/udp.c b/3rd/libuv-1.19.2/src/win/udp.c deleted file mode 100644 index cd1d0e07..00000000 --- a/3rd/libuv-1.19.2/src/win/udp.c +++ /dev/null @@ -1,965 +0,0 @@ -/* 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 -#include - -#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(&handle->recv_req, 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->recv_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); - if (handle->recv_buffer.base == NULL || 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(req, 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? */ - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); - if (buf.base == NULL || 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 - return UV_EINVAL; - 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) { - DWORD bytes; - const struct sockaddr* bind_addr; - struct sockaddr_storage converted; - int err; - - assert(nbufs > 0); - - err = uv__convert_to_localhost_if_unspecified(addr, &converted); - if (err) - return err; - - /* Already sending a message.*/ - if (handle->send_queue_count != 0) - return UV_EAGAIN; - - 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 - return UV_EINVAL; - err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); - if (err) - return uv_translate_sys_error(err); - } - - err = WSASendTo(handle->socket, - (WSABUF*)bufs, - nbufs, - &bytes, - 0, - (const struct sockaddr*) &converted, - addrlen, - NULL, - NULL); - - if (err) - return uv_translate_sys_error(WSAGetLastError()); - - return bytes; -} diff --git a/3rd/libuv-1.19.2/src/win/util.c b/3rd/libuv-1.19.2/src/win/util.c deleted file mode 100644 index 3100bc23..00000000 --- a/3rd/libuv-1.19.2/src/win/util.c +++ /dev/null @@ -1,1581 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include - -#include "uv.h" -#include "internal.h" - -#include -#include -#include -#include -#include -#include -#include - - -/* - * 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 - -/* Max user name length, from iphlpapi.h */ -#ifndef UNLEN -# define UNLEN 256 -#endif - -/* - Max hostname length. The Windows gethostname() documentation states that 256 - bytes will always be large enough to hold the null-terminated hostname. -*/ -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 -#endif - -/* Maximum environment variable size, including the terminating null */ -#define MAX_ENV_VAR_LENGTH 32767 - -/* 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(void) { - 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_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, - (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; - 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; -} - - -uv_pid_t uv_os_getpid(void) { - return GetCurrentProcessId(); -} - - -uv_pid_t uv_os_getppid(void) { - 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(void) { - 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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(void) { - WCHAR title_w[MAX_TITLE_LENGTH]; - - if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { - return -1; - } - - if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) - return -1; - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - 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); - len = strlen(process_title) + 1; - - if (size < len) { - LeaveCriticalSection(&process_title_lock); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - 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; - - uv__convert_utf16_to_utf8(cpu_brand, - cpu_brand_size / sizeof(WCHAR), - &(cpu_info->model)); - } - - 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; - PROCESS_MEMORY_COUNTERS memCounters; - IO_COUNTERS ioCounters; - 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()); - } - - ret = GetProcessMemoryInfo(GetCurrentProcess(), - &memCounters, - sizeof(memCounters)); - if (ret == 0) { - return uv_translate_sys_error(GetLastError()); - } - - ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); - 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; - - uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; - uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; - - uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; - uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; - - return 0; -} - - -int uv_os_homedir(char* buffer, size_t* size) { - uv_passwd_t pwd; - 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 { - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; - } - - /* USERPROFILE is not set, so call uv__getpwuid_r() */ - r = uv__getpwuid_r(&pwd); - - if (r != 0) { - return r; - } - - len = strlen(pwd.homedir); - - if (len >= *size) { - *size = len + 1; - uv_os_free_passwd(&pwd); - return UV_ENOBUFS; - } - - memcpy(buffer, pwd.homedir, len + 1); - *size = len; - uv_os_free_passwd(&pwd); - - return 0; -} - - -int uv_os_tmpdir(char* buffer, size_t* size) { - wchar_t path[MAX_PATH + 1]; - DWORD bufsize; - size_t len; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - len = GetTempPathW(MAX_PATH + 1, path); - - if (len == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (len > MAX_PATH + 1) { - /* This should not be possible */ - 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 (path[len - 1] == L'\\' && - !(len == 3 && path[1] == L':')) { - len--; - path[len] = L'\0'; - } - - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; -} - - -void uv_os_free_passwd(uv_passwd_t* pwd) { - if (pwd == NULL) - return; - - uv__free(pwd->username); - uv__free(pwd->homedir); - pwd->username = NULL; - pwd->homedir = NULL; -} - - -/* - * Converts a UTF-16 string into a UTF-8 one. The resulting string is - * null-terminated. - * - * If utf16 is null terminated, utf16len can be set to -1, otherwise it must - * be specified. - */ -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { - DWORD bufsize; - - if (utf16 == NULL) - return UV_EINVAL; - - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - NULL, - 0, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so - * we do it ourselves always, just in case. */ - *utf8 = uv__malloc(bufsize + 1); - - if (*utf8 == NULL) - return UV_ENOMEM; - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - *utf8, - bufsize, - NULL, - NULL); - - if (bufsize == 0) { - uv__free(*utf8); - *utf8 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf8)[bufsize] = '\0'; - return 0; -} - - -/* - * Converts a UTF-8 string into a UTF-16 one. The resulting string is - * null-terminated. - * - * If utf8 is null terminated, utf8len can be set to -1, otherwise it must - * be specified. - */ -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { - int bufsize; - - if (utf8 == NULL) - return UV_EINVAL; - - /* Check how much space we need */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so - * we do it ourselves always, just in case. */ - *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1)); - - if (*utf16 == NULL) - return UV_ENOMEM; - - /* Convert to UTF-16 */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); - - if (bufsize == 0) { - uv__free(*utf16); - *utf16 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf16)[bufsize] = '\0'; - return 0; -} - - -int uv__getpwuid_r(uv_passwd_t* pwd) { - HANDLE token; - wchar_t username[UNLEN + 1]; - wchar_t path[MAX_PATH]; - DWORD bufsize; - int r; - - if (pwd == NULL) - return UV_EINVAL; - - /* Get the home directory using GetUserProfileDirectoryW() */ - if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) - return uv_translate_sys_error(GetLastError()); - - bufsize = ARRAY_SIZE(path); - if (!GetUserProfileDirectoryW(token, path, &bufsize)) { - r = GetLastError(); - CloseHandle(token); - - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_ENOMEM; - - return uv_translate_sys_error(r); - } - - CloseHandle(token); - - /* Get the username using GetUserNameW() */ - bufsize = ARRAY_SIZE(username); - if (!GetUserNameW(username, &bufsize)) { - r = GetLastError(); - - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_ENOMEM; - - return uv_translate_sys_error(r); - } - - pwd->homedir = NULL; - r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); - - if (r != 0) - return r; - - pwd->username = NULL; - r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); - - if (r != 0) { - uv__free(pwd->homedir); - return r; - } - - pwd->shell = NULL; - pwd->uid = -1; - pwd->gid = -1; - - return 0; -} - - -int uv_os_get_passwd(uv_passwd_t* pwd) { - return uv__getpwuid_r(pwd); -} - - -int uv_os_getenv(const char* name, char* buffer, size_t* size) { - wchar_t var[MAX_ENV_VAR_LENGTH]; - wchar_t* name_w; - DWORD bufsize; - size_t len; - int r; - - if (name == NULL || buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - r = uv__convert_utf8_to_utf16(name, -1, &name_w); - - if (r != 0) - return r; - - len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); - uv__free(name_w); - assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ - - if (len == 0) { - r = GetLastError(); - - if (r == ERROR_ENVVAR_NOT_FOUND) - return UV_ENOENT; - - return uv_translate_sys_error(r); - } - - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - var, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; -} - - -int uv_os_setenv(const char* name, const char* value) { - wchar_t* name_w; - wchar_t* value_w; - int r; - - if (name == NULL || value == NULL) - return UV_EINVAL; - - r = uv__convert_utf8_to_utf16(name, -1, &name_w); - - if (r != 0) - return r; - - r = uv__convert_utf8_to_utf16(value, -1, &value_w); - - if (r != 0) { - uv__free(name_w); - return r; - } - - r = SetEnvironmentVariableW(name_w, value_w); - uv__free(name_w); - uv__free(value_w); - - if (r == 0) - return uv_translate_sys_error(GetLastError()); - - return 0; -} - - -int uv_os_unsetenv(const char* name) { - wchar_t* name_w; - int r; - - if (name == NULL) - return UV_EINVAL; - - r = uv__convert_utf8_to_utf16(name, -1, &name_w); - - if (r != 0) - return r; - - r = SetEnvironmentVariableW(name_w, NULL); - uv__free(name_w); - - if (r == 0) - return uv_translate_sys_error(GetLastError()); - - return 0; -} - - -int uv_os_gethostname(char* buffer, size_t* size) { - char buf[MAXHOSTNAMELEN + 1]; - size_t len; - - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - uv__once_init(); /* Initialize winsock */ - - if (gethostname(buf, sizeof(buf)) != 0) - return uv_translate_sys_error(WSAGetLastError()); - - buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, buf, len + 1); - *size = len; - return 0; -} diff --git a/3rd/libuv-1.19.2/src/win/winapi.c b/3rd/libuv-1.19.2/src/win/winapi.c deleted file mode 100644 index 4ccdf0a5..00000000 --- a/3rd/libuv-1.19.2/src/win/winapi.c +++ /dev/null @@ -1,169 +0,0 @@ -/* 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 - -#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; - - -/* Powrprof.dll function pointer */ -sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; - -/* User32.dll function pointer */ -sSetWinEventHook pSetWinEventHook; - - -void uv_winapi_init(void) { - HMODULE ntdll_module; - HMODULE kernel32_module; - HMODULE powrprof_module; - HMODULE user32_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"); - - - powrprof_module = LoadLibraryA("powrprof.dll"); - if (powrprof_module != NULL) { - pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) - GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); - } - - user32_module = LoadLibraryA("user32.dll"); - if (user32_module != NULL) { - pSetWinEventHook = (sSetWinEventHook) - GetProcAddress(user32_module, "SetWinEventHook"); - } - -} diff --git a/3rd/libuv-1.19.2/src/win/winapi.h b/3rd/libuv-1.19.2/src/win/winapi.h deleted file mode 100644 index cc54b79b..00000000 --- a/3rd/libuv-1.19.2/src/win/winapi.h +++ /dev/null @@ -1,4778 +0,0 @@ -/* 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 - - -/* - * 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 - -#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE -# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002 -#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; - }; - } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#endif - -typedef struct _IO_STATUS_BLOCK { - union { - NTSTATUS Status; - PVOID Pointer; - }; - 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_ELEVATION_REQUIRED -# define ERROR_ELEVATION_REQUIRED 740 -#endif - -#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); - -/* from powerbase.h */ -#ifndef DEVICE_NOTIFY_CALLBACK -# define DEVICE_NOTIFY_CALLBACK 2 -#endif - -#ifndef PBT_APMRESUMEAUTOMATIC -# define PBT_APMRESUMEAUTOMATIC 18 -#endif - -#ifndef PBT_APMRESUMESUSPEND -# define PBT_APMRESUMESUSPEND 7 -#endif - -typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( - PVOID Context, - ULONG Type, - PVOID Setting -); -typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; - -typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { - _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; - PVOID Context; -} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; - -typedef PVOID _HPOWERNOTIFY; -typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; - -typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) - (DWORD Flags, - HANDLE Recipient, - _PHPOWERNOTIFY RegistrationHandle); - -/* from Winuser.h */ -typedef VOID (CALLBACK* WINEVENTPROC) - (HWINEVENTHOOK hWinEventHook, - DWORD event, - HWND hwnd, - LONG idObject, - LONG idChild, - DWORD idEventThread, - DWORD dwmsEventTime); - -typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) - (UINT eventMin, - UINT eventMax, - HMODULE hmodWinEventProc, - WINEVENTPROC lpfnWinEventProc, - DWORD idProcess, - DWORD idThread, - UINT 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; - - -/* Powrprof.dll function pointer */ -extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; - -/* User32.dll function pointer */ -extern sSetWinEventHook pSetWinEventHook; - -#endif /* UV_WIN_WINAPI_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/winsock.c b/3rd/libuv-1.19.2/src/win/winsock.c deleted file mode 100644 index 84188954..00000000 --- a/3rd/libuv-1.19.2/src/win/winsock.c +++ /dev/null @@ -1,591 +0,0 @@ -/* 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 -#include - -#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(void) { - 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; - } -} - -int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, - struct sockaddr_storage* storage) { - struct sockaddr_in* dest4; - struct sockaddr_in6* dest6; - - if (addr == NULL) - return UV_EINVAL; - - switch (addr->sa_family) { - case AF_INET: - dest4 = (struct sockaddr_in*) storage; - memcpy(dest4, addr, sizeof(*dest4)); - if (dest4->sin_addr.s_addr == 0) - dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - return 0; - case AF_INET6: - dest6 = (struct sockaddr_in6*) storage; - memcpy(dest6, addr, sizeof(*dest6)); - if (memcmp(&dest6->sin6_addr, - &uv_addr_ip6_any_.sin6_addr, - sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) { - struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT; - dest6->sin6_addr = init_sin6_addr; - } - return 0; - default: - return UV_EINVAL; - } -} diff --git a/3rd/libuv-1.19.2/src/win/winsock.h b/3rd/libuv-1.19.2/src/win/winsock.h deleted file mode 100644 index 7ecb755b..00000000 --- a/3rd/libuv-1.19.2/src/win/winsock.h +++ /dev/null @@ -1,193 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#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 - -int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, - struct sockaddr_storage* storage); - -#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/3rd/libuv-1.19.2/stdafx.cpp b/3rd/libuv-1.19.2/stdafx.cpp deleted file mode 100644 index 4b229caa6bec1b2d6a1f924a89ba58c5712cda48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 586 zcmZ{iK~IA~6olt&;(s7|*519D7~{=@J$R)8VH*TOsmh;Mzu8SeG^W|^?%Vff=FQ{l zbEAzi9W<&?u1X)e){A<6nQr1sr=td9CAUgJO+1aN$sdUYwY)ZD6}%jX>^U1TW7RR+ zx12n44E+DCI@cLWtfc{Q2f`aldXQ^k?~%9Rw42$jrw6Un6MN*)C8}!xT2zdK#83R5zE|Om+^h^DbvL-*J~oD?Bv8&kGf-d z4(_vJdAHwYw4+np3px!mXO4$!2RxMtJxBJI+H#&jrYCJ-xz)X%as1(jTWMmh=)g`L NCQm|~^XY4_>Td)>WN82Z diff --git a/3rd/libuv-1.19.2/stdafx.h b/3rd/libuv-1.19.2/stdafx.h deleted file mode 100644 index b642ffd7561e1b2e1b298f3df787d6071939e14f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 736 zcmaJn-A*y9?P zxFEOKJFFcMBHoFgQH_vxwyumfJB#L+v7rX#Nr}|9Ldc_N7?D|h)DD0N%ka4AIfEfw0WxN;+co0fK2Vs4B9U*sm0{`t1wOo&Foy0~*EXI^K{ z&F{}p2USW{Xp2p>*G`#oJ!s%(q!H-M(Ty4fmG}kNtEQTB%)V1m=}BwwfWPvrT#@e@ zH0NG}74Ao{glS)#QXA|NYdIfY7hrMp+Ji@H`t9kzWx_SD6;~Ri;cvXH)6CO{-I1p_IJPQ#X=r zigZeSqQguJz35q;zt9^Q_C^^>*mmuXUCp&pw^fPoGX+dho4RCrySs7j@9_UipWkA5 OQDt4mH~x-^Z~X_?9czaG diff --git a/3rd/libuv-1.19.2/test/benchmark-async-pummel.c b/3rd/libuv-1.19.2/test/benchmark-async-pummel.c deleted file mode 100644 index cca3de10..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-async-pummel.c +++ /dev/null @@ -1,119 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-async.c b/3rd/libuv-1.19.2/test/benchmark-async.c deleted file mode 100644 index e44165f2..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-async.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-fs-stat.c b/3rd/libuv-1.19.2/test/benchmark-fs-stat.c deleted file mode 100644 index 32d25895..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-fs-stat.c +++ /dev/null @@ -1,136 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c b/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c deleted file mode 100644 index 1dbc23dd..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c +++ /dev/null @@ -1,92 +0,0 @@ -/* 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 - -#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/3rd/libuv-1.19.2/test/benchmark-list.h b/3rd/libuv-1.19.2/test/benchmark-list.h deleted file mode 100644 index 1e843071..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-list.h +++ /dev/null @@ -1,163 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-loop-count.c b/3rd/libuv-1.19.2/test/benchmark-loop-count.c deleted file mode 100644 index 970a94c2..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-loop-count.c +++ /dev/null @@ -1,92 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-million-async.c b/3rd/libuv-1.19.2/test/benchmark-million-async.c deleted file mode 100644 index 5395ed54..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-million-async.c +++ /dev/null @@ -1,112 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-million-timers.c b/3rd/libuv-1.19.2/test/benchmark-million-timers.c deleted file mode 100644 index 60a308be..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-million-timers.c +++ /dev/null @@ -1,86 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-multi-accept.c b/3rd/libuv-1.19.2/test/benchmark-multi-accept.c deleted file mode 100644 index 2f32c0ca..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-multi-accept.c +++ /dev/null @@ -1,447 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c b/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c deleted file mode 100644 index 646a7df9..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c +++ /dev/null @@ -1,221 +0,0 @@ -/* 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 -#include - -/* 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/3rd/libuv-1.19.2/test/benchmark-pound.c b/3rd/libuv-1.19.2/test/benchmark-pound.c deleted file mode 100644 index 79f36345..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-pound.c +++ /dev/null @@ -1,351 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-pump.c b/3rd/libuv-1.19.2/test/benchmark-pump.c deleted file mode 100644 index 8685258e..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-pump.c +++ /dev/null @@ -1,476 +0,0 @@ -/* 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 -#include - - -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(void); - -static uv_req_t* req_alloc(void); -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/3rd/libuv-1.19.2/test/benchmark-sizes.c b/3rd/libuv-1.19.2/test/benchmark-sizes.c deleted file mode 100644 index 9bf42f91..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-sizes.c +++ /dev/null @@ -1,46 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-spawn.c b/3rd/libuv-1.19.2/test/benchmark-spawn.c deleted file mode 100644 index ed9ad608..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-spawn.c +++ /dev/null @@ -1,164 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c b/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c deleted file mode 100644 index 96921b70..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c +++ /dev/null @@ -1,144 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-thread.c b/3rd/libuv-1.19.2/test/benchmark-thread.c deleted file mode 100644 index b37a7fd6..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-thread.c +++ /dev/null @@ -1,64 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c b/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c deleted file mode 100644 index 68a2373d..00000000 --- a/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c +++ /dev/null @@ -1,243 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/blackhole-server.c b/3rd/libuv-1.19.2/test/blackhole-server.c deleted file mode 100644 index ad878b35..00000000 --- a/3rd/libuv-1.19.2/test/blackhole-server.c +++ /dev/null @@ -1,121 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/dns-server.c b/3rd/libuv-1.19.2/test/dns-server.c deleted file mode 100644 index 80052c70..00000000 --- a/3rd/libuv-1.19.2/test/dns-server.c +++ /dev/null @@ -1,340 +0,0 @@ -/* 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 -#include -#include - - -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/3rd/libuv-1.19.2/test/echo-server.c b/3rd/libuv-1.19.2/test/echo-server.c deleted file mode 100644 index bfed6767..00000000 --- a/3rd/libuv-1.19.2/test/echo-server.c +++ /dev/null @@ -1,378 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/fixtures/empty_file b/3rd/libuv-1.19.2/test/fixtures/empty_file deleted file mode 100644 index e69de29b..00000000 diff --git a/3rd/libuv-1.19.2/test/fixtures/load_error.node b/3rd/libuv-1.19.2/test/fixtures/load_error.node deleted file mode 100644 index 323fae03..00000000 --- a/3rd/libuv-1.19.2/test/fixtures/load_error.node +++ /dev/null @@ -1 +0,0 @@ -foobar diff --git a/3rd/libuv-1.19.2/test/run-benchmarks.c b/3rd/libuv-1.19.2/test/run-benchmarks.c deleted file mode 100644 index 6e42623d..00000000 --- a/3rd/libuv-1.19.2/test/run-benchmarks.c +++ /dev/null @@ -1,65 +0,0 @@ -/* 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 -#include - -#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/3rd/libuv-1.19.2/test/run-tests.c b/3rd/libuv-1.19.2/test/run-tests.c deleted file mode 100644 index da4ac82e..00000000 --- a/3rd/libuv-1.19.2/test/run-tests.c +++ /dev/null @@ -1,204 +0,0 @@ -/* 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 -#include -#include - -#ifdef _WIN32 -# include -#else -# include -#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_helper_closed_handle(void); -int ipc_send_recv_helper(void); -int ipc_helper_bind_twice(void); -int stdio_over_pipes_helper(void); -int spawn_stdin_stdout(void); -int spawn_tcp_server_helper(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]); - case 4: return maybe_run_test(argc, argv); - 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_closed_handle") == 0) { - return ipc_helper_closed_handle(); - } - - 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_tcp_server_helper") == 0) { - return spawn_tcp_server_helper(); - } - - 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(); - } - -#ifndef _WIN32 - if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) { - uv_uid_t uid = atoi(argv[2]); - uv_gid_t gid = atoi(argv[3]); - - ASSERT(uid == getuid()); - ASSERT(gid == getgid()); - - return 1; - } -#endif /* !_WIN32 */ - - return run_test(argv[1], 0, 1); -} diff --git a/3rd/libuv-1.19.2/test/runner-unix.c b/3rd/libuv-1.19.2/test/runner-unix.c deleted file mode 100644 index 3167ed44..00000000 --- a/3rd/libuv-1.19.2/test/runner-unix.c +++ /dev/null @@ -1,400 +0,0 @@ -/* 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 -#include /* uintptr_t */ - -#include -#include /* readlink, usleep */ -#include /* strdup */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* Do platform-specific initialization. */ -int platform_init(int argc, char **argv) { - /* 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; - int stdout_fd; - const char* arg; - char* args[16]; - int n; - pid_t pid; - - stdout_file = tmpfile(); - stdout_fd = fileno(stdout_file); - 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(stdout_fd, STDOUT_FILENO); - dup2(stdout_fd, 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 defined(__MVS__) - if (pthread_attr_setstacksize(&attr, 1024 * 1024)) -#else - if (pthread_attr_setstacksize(&attr, 256 * 1024)) -#endif - 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, FILE* stream) { - 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) - print_lines(buf, strlen(buf), stream); - - 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) { -#if defined(__MVS__) - fprintf(stderr, "\047[2K\r"); -#else - fprintf(stderr, "\033[2K\r"); -#endif -} - - -/* Pause the calling thread for a number of milliseconds. */ -void uv_sleep(int msec) { - int sec; - int usec; - - sec = msec / 1000; - usec = (msec % 1000) * 1000; - if (sec > 0) - sleep(sec); - if (usec > 0) - usleep(usec); -} diff --git a/3rd/libuv-1.19.2/test/runner-unix.h b/3rd/libuv-1.19.2/test/runner-unix.h deleted file mode 100644 index e21847f9..00000000 --- a/3rd/libuv-1.19.2/test/runner-unix.h +++ /dev/null @@ -1,36 +0,0 @@ -/* 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 -#include /* 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/3rd/libuv-1.19.2/test/runner-win.c b/3rd/libuv-1.19.2/test/runner-win.c deleted file mode 100644 index d86fda3c..00000000 --- a/3rd/libuv-1.19.2/test/runner-win.c +++ /dev/null @@ -1,351 +0,0 @@ -/* 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 -#include -#include -#include -#include -#if !defined(__MINGW32__) -# include -#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) { - /* 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, FILE* stream) { - char buf[1024]; - int fd, r; - FILE* f; - - fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); - if (fd == -1) - return -1; - f = _fdopen(fd, "rt"); - if (f == NULL) { - _close(fd); - return -1; - } - - r = fseek(f, 0, SEEK_SET); - if (r < 0) - return -1; - - while (fgets(buf, sizeof(buf), f) != NULL) - print_lines(buf, strlen(buf), stream); - - if (ferror(f)) - return -1; - - fclose(f); - 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); -} - - -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/3rd/libuv-1.19.2/test/runner-win.h b/3rd/libuv-1.19.2/test/runner-win.h deleted file mode 100644 index 8cc4c16e..00000000 --- a/3rd/libuv-1.19.2/test/runner-win.h +++ /dev/null @@ -1,39 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/runner.c b/3rd/libuv-1.19.2/test/runner.c deleted file mode 100644 index f017902a..00000000 --- a/3rd/libuv-1.19.2/test/runner.c +++ /dev/null @@ -1,434 +0,0 @@ -/* 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 -#include - -#include "runner.h" -#include "task.h" -#include "uv.h" - -char executable_path[sizeof(executable_path)]; - - -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); -} - - -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 ""; - - 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 actual; - int total; - int passed; - int failed; - int skipped; - int current; - int test_result; - int skip; - task_entry_t* task; - - /* Count the number of tests. */ - actual = 0; - total = 0; - for (task = TASKS; task->main; task++, actual++) { - if (!task->is_helper) { - total++; - } - } - - /* Keep platform_output first. */ - skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output")); - qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task); - - fprintf(stderr, "1..%d\n", total); - fflush(stderr); - - /* Run all tests. */ - passed = 0; - failed = 0; - skipped = 0; - current = 1; - for (task = TASKS; task->main; task++) { - if (task->is_helper) { - continue; - } - - test_result = run_test(task->task_name, benchmark_output, current); - switch (test_result) { - case TEST_OK: passed++; break; - case TEST_SKIP: skipped++; break; - default: failed++; - } - current++; - } - - 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]; - int reason_length; - - switch (status) { - case TEST_OK: - result = "ok"; - directive = ""; - break; - case TEST_SKIP: - result = "ok"; - directive = " # SKIP "; - break; - default: - result = "not ok"; - directive = ""; - } - - if (status == TEST_SKIP && process_output_size(process) > 0) { - process_read_last_line(process, reason, sizeof reason); - reason_length = strlen(reason); - if (reason_length > 0 && reason[reason_length - 1] == '\n') - reason[reason_length - 1] = '\0'; - } 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] = ""; - 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"); - } - - log_tap_result(test_count, test, status, &processes[i]); - - /* Show error and output from processes if the test failed. */ - if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { - if (strlen(errmsg) > 0) - fprintf(stderr, "# %s\n", errmsg); - fprintf(stderr, "# "); - 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], stderr); - break; - } - } - - /* 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], 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 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); - } - } -} - - -void print_lines(const char* buffer, size_t size, FILE* stream) { - const char* start; - const char* end; - - start = buffer; - while ((end = memchr(start, '\n', &buffer[size] - start))) { - fprintf(stream, "# %.*s\n", (int) (end - start), start); - fflush(stream); - start = end + 1; - } - - if (start < &buffer[size]) { - fprintf(stream, "# %s\n", start); - fflush(stream); - } -} diff --git a/3rd/libuv-1.19.2/test/runner.h b/3rd/libuv-1.19.2/test/runner.h deleted file mode 100644 index 555f2f8e..00000000 --- a/3rd/libuv-1.19.2/test/runner.h +++ /dev/null @@ -1,177 +0,0 @@ -/* 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 /* PATH_MAX */ -#include /* 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); - -/* Print lines in |buffer| as TAP diagnostics to |stream|. */ -void print_lines(const char* buffer, size_t size, FILE* stream); - -/* - * Stuff that should be implemented by test-runner-.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 `stream`. */ -int process_copy_output(process_info_t* p, FILE* stream); - -/* 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); - -#endif /* RUNNER_H_ */ diff --git a/3rd/libuv-1.19.2/test/task.h b/3rd/libuv-1.19.2/test/task.h deleted file mode 100644 index af99d92f..00000000 --- a/3rd/libuv-1.19.2/test/task.h +++ /dev/null @@ -1,232 +0,0 @@ -/* 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 -#include -#include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" -#else -# include -#endif - -#if !defined(_WIN32) -# include -# include /* 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 -# 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()); \ - ASSERT(0 == uv_loop_close(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_SKIP -}; - -#define RETURN_OK() \ - do { \ - return TEST_OK; \ - } 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 0; /* Assume no 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; -} - -#if defined(__CYGWIN__) || defined(__MSYS__) -# define NO_FS_EVENTS "Filesystem watching not supported on this platform." -#endif - -#if defined(__MSYS__) -# define NO_SEND_HANDLE_ON_PIPE \ - "MSYS2 runtime does not support sending handles on pipes." -#elif defined(__CYGWIN__) -# define NO_SEND_HANDLE_ON_PIPE \ - "Cygwin runtime does not support sending handles on pipes." -#endif - -#if defined(__MSYS__) -# define NO_SELF_CONNECT \ - "MSYS2 runtime hangs on listen+connect in same process." -#elif defined(__CYGWIN__) -# define NO_SELF_CONNECT \ - "Cygwin runtime hangs on listen+connect in same process." -#endif - -#endif /* TASK_H_ */ diff --git a/3rd/libuv-1.19.2/test/test-active.c b/3rd/libuv-1.19.2/test/test-active.c deleted file mode 100644 index b17bd176..00000000 --- a/3rd/libuv-1.19.2/test/test-active.c +++ /dev/null @@ -1,84 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-async-null-cb.c b/3rd/libuv-1.19.2/test/test-async-null-cb.c deleted file mode 100644 index 52652d91..00000000 --- a/3rd/libuv-1.19.2/test/test-async-null-cb.c +++ /dev/null @@ -1,64 +0,0 @@ -/* 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 - -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) { - /* - * Fill async_handle with garbage values. - * uv_async_init() should properly initialize struct fields regardless of - * initial values. - * This is added to verify paddings between fields do not affect behavior. - */ - memset(&async_handle, 0xff, sizeof(async_handle)); - - 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/3rd/libuv-1.19.2/test/test-async.c b/3rd/libuv-1.19.2/test/test-async.c deleted file mode 100644 index 6f5351bf..00000000 --- a/3rd/libuv-1.19.2/test/test-async.c +++ /dev/null @@ -1,134 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-barrier.c b/3rd/libuv-1.19.2/test/test-barrier.c deleted file mode 100644 index dfd2dbde..00000000 --- a/3rd/libuv-1.19.2/test/test-barrier.c +++ /dev/null @@ -1,106 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-callback-order.c b/3rd/libuv-1.19.2/test/test-callback-order.c deleted file mode 100644 index 8bc2c4f7..00000000 --- a/3rd/libuv-1.19.2/test/test-callback-order.c +++ /dev/null @@ -1,77 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-callback-stack.c b/3rd/libuv-1.19.2/test/test-callback-stack.c deleted file mode 100644 index 8855c084..00000000 --- a/3rd/libuv-1.19.2/test/test-callback-stack.c +++ /dev/null @@ -1,205 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-close-fd.c b/3rd/libuv-1.19.2/test/test-close-fd.c deleted file mode 100644 index 93a7bd7c..00000000 --- a/3rd/libuv-1.19.2/test/test-close-fd.c +++ /dev/null @@ -1,76 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-close-order.c b/3rd/libuv-1.19.2/test/test-close-order.c deleted file mode 100644 index 2b24f6d6..00000000 --- a/3rd/libuv-1.19.2/test/test-close-order.c +++ /dev/null @@ -1,80 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-condvar.c b/3rd/libuv-1.19.2/test/test-condvar.c deleted file mode 100644 index d956efef..00000000 --- a/3rd/libuv-1.19.2/test/test-condvar.c +++ /dev/null @@ -1,245 +0,0 @@ -/* 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 -#include - -typedef struct worker_config { - uv_mutex_t mutex; - uv_cond_t cond; - int signal_delay; - int wait_delay; - int use_broadcast; - volatile int posted_1; - volatile int posted_2; - void (*signal_cond)(struct worker_config* c, volatile int* flag); - int (*wait_cond)(struct worker_config* c, const volatile int* flag); -} worker_config; - - -static void worker(void* arg) { - worker_config* c = arg; - c->signal_cond(c, &c->posted_1); - c->wait_cond(c, &c->posted_2); -} - -static void noop_worker(void* arg) { - return; -} - -static void condvar_signal(worker_config* c, volatile int* flag) { - if (c->signal_delay) - uv_sleep(c->signal_delay); - - uv_mutex_lock(&c->mutex); - ASSERT(*flag == 0); - *flag = 1; - if (c->use_broadcast) - uv_cond_broadcast(&c->cond); - else - uv_cond_signal(&c->cond); - uv_mutex_unlock(&c->mutex); -} - - -static int condvar_wait(worker_config* c, const volatile int* flag) { - uv_mutex_lock(&c->mutex); - if (c->wait_delay) - uv_sleep(c->wait_delay); - while (*flag == 0) { - uv_cond_wait(&c->cond, &c->mutex); - } - ASSERT(*flag == 1); - uv_mutex_unlock(&c->mutex); - - return 0; -} - - -TEST_IMPL(condvar_1) { - uv_thread_t thread; - worker_config wc; - - memset(&wc, 0, sizeof(wc)); - wc.wait_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); - wc.signal_cond(&wc, &wc.posted_2); - - 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.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); - wc.signal_cond(&wc, &wc.posted_2); - - ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); - - return 0; -} - - -static int condvar_timedwait(worker_config* c, const volatile int* flag) { - int r; - - r = 0; - - uv_mutex_lock(&c->mutex); - if (c->wait_delay) - uv_sleep(c->wait_delay); - while (*flag == 0) { - r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0 || r == UV_ETIMEDOUT); - if (r == UV_ETIMEDOUT) - break; - } - uv_mutex_unlock(&c->mutex); - - return r; -} - -/* Test that uv_cond_timedwait will return early when cond is signaled. */ -TEST_IMPL(condvar_3) { - uv_thread_t thread; - worker_config wc; - - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); - wc.signal_cond(&wc, &wc.posted_2); - - 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; - - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - wc.wait_cond(&wc, &wc.posted_1); - wc.signal_cond(&wc, &wc.posted_2); - - 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; - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - wc.wait_cond(&wc, &wc.posted_1); - wc.signal_cond(&wc, &wc.posted_2); - - ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); - - return 0; -} - -/* Test that uv_cond_timedwait will time out when cond is not signaled. */ -TEST_IMPL(condvar_6) { - uv_thread_t thread; - worker_config wc; - int r; - - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, noop_worker, &wc)); - - /* This can only return having timed out, because otherwise we - * loop forever in condvar_timedwait. */ - r = wc.wait_cond(&wc, &wc.posted_1); - ASSERT(r == UV_ETIMEDOUT); - - ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-connect-unspecified.c b/3rd/libuv-1.19.2/test/test-connect-unspecified.c deleted file mode 100644 index 04e1c8a5..00000000 --- a/3rd/libuv-1.19.2/test/test-connect-unspecified.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 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. -*/ - -#include "uv.h" -#include "task.h" - -static void connect_4(uv_connect_t* req, int status) { - ASSERT(status != UV_EADDRNOTAVAIL); -} - -static void connect_6(uv_connect_t* req, int status) { - ASSERT(status != UV_EADDRNOTAVAIL); -} - -TEST_IMPL(connect_unspecified) { - uv_loop_t* loop; - uv_tcp_t socket4; - struct sockaddr_in addr4; - uv_connect_t connect4; - uv_tcp_t socket6; - struct sockaddr_in6 addr6; - uv_connect_t connect6; - - loop = uv_default_loop(); - - ASSERT(uv_tcp_init(loop, &socket4) == 0); - ASSERT(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4) == 0); - ASSERT(uv_tcp_connect(&connect4, - &socket4, - (const struct sockaddr*) &addr4, - connect_4) == 0); - - ASSERT(uv_tcp_init(loop, &socket6) == 0); - ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); - ASSERT(uv_tcp_connect(&connect6, - &socket6, - (const struct sockaddr*) &addr6, - connect_6) == 0); - - ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-connection-fail.c b/3rd/libuv-1.19.2/test/test-connection-fail.c deleted file mode 100644 index 328bff46..00000000 --- a/3rd/libuv-1.19.2/test/test-connection-fail.c +++ /dev/null @@ -1,151 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c b/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c deleted file mode 100644 index 1e95043c..00000000 --- a/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c +++ /dev/null @@ -1,51 +0,0 @@ -/* 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 - -#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/3rd/libuv-1.19.2/test/test-default-loop-close.c b/3rd/libuv-1.19.2/test/test-default-loop-close.c deleted file mode 100644 index fd11cfa8..00000000 --- a/3rd/libuv-1.19.2/test/test-default-loop-close.c +++ /dev/null @@ -1,59 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-delayed-accept.c b/3rd/libuv-1.19.2/test/test-delayed-accept.c deleted file mode 100644 index 4a799890..00000000 --- a/3rd/libuv-1.19.2/test/test-delayed-accept.c +++ /dev/null @@ -1,189 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-dlerror.c b/3rd/libuv-1.19.2/test/test-dlerror.c deleted file mode 100644 index 8f7697b5..00000000 --- a/3rd/libuv-1.19.2/test/test-dlerror.c +++ /dev/null @@ -1,57 +0,0 @@ -/* 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 - - -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, path) != 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, path) != NULL); - ASSERT(strstr(msg, dlerror_no_error) == NULL); - - uv_dlclose(&lib); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-eintr-handling.c b/3rd/libuv-1.19.2/test/test-eintr-handling.c deleted file mode 100644 index 1aaf623b..00000000 --- a/3rd/libuv-1.19.2/test/test-eintr-handling.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" - -#ifdef _WIN32 - -TEST_IMPL(eintr_handling) { - RETURN_SKIP("Test not implemented on Windows."); -} - -#else /* !_WIN32 */ - -#include -#include - -static uv_loop_t* loop; -static uv_fs_t read_req; -static uv_buf_t iov; - -static char buf[32]; -static char test_buf[] = "test-buffer\n"; -int pipe_fds[2]; - -struct thread_ctx { - uv_barrier_t barrier; - int fd; -}; - -static void thread_main(void* arg) { - int nwritten; - ASSERT(0 == kill(getpid(), SIGUSR1)); - - do - nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); - while (nwritten == -1 && errno == EINTR); - - ASSERT(nwritten == sizeof(test_buf)); -} - -static void sig_func(uv_signal_t* handle, int signum) { - uv_signal_stop(handle); -} - -TEST_IMPL(eintr_handling) { - struct thread_ctx ctx; - uv_thread_t thread; - uv_signal_t signal; - int nread; - - iov = uv_buf_init(buf, sizeof(buf)); - loop = uv_default_loop(); - - ASSERT(0 == uv_signal_init(loop, &signal)); - ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); - - ASSERT(0 == pipe(pipe_fds)); - ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); - - nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); - - ASSERT(nread == sizeof(test_buf)); - ASSERT(0 == strcmp(buf, test_buf)); - - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - - ASSERT(0 == close(pipe_fds[0])); - ASSERT(0 == close(pipe_fds[1])); - uv_close((uv_handle_t*) &signal, NULL); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-embed.c b/3rd/libuv-1.19.2/test/test-embed.c deleted file mode 100644 index c6ddceb1..00000000 --- a/3rd/libuv-1.19.2/test/test-embed.c +++ /dev/null @@ -1,139 +0,0 @@ -/* 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 -#include -#include - -#ifndef HAVE_KQUEUE -# if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - 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 -# include -# include -#endif - -#if defined(HAVE_EPOLL) -# include -#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/3rd/libuv-1.19.2/test/test-emfile.c b/3rd/libuv-1.19.2/test/test-emfile.c deleted file mode 100644 index 8e44ac5c..00000000 --- a/3rd/libuv-1.19.2/test/test-emfile.c +++ /dev/null @@ -1,117 +0,0 @@ -/* 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 -#include -#include - -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) { -#if defined(_AIX) || defined(__MVS__) - /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket - * which causes uv__emfile_trick to not work as intended and this test - * to fail. - */ - RETURN_SKIP("uv__emfile_trick does not work on this OS"); -#endif - 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/3rd/libuv-1.19.2/test/test-env-vars.c b/3rd/libuv-1.19.2/test/test-env-vars.c deleted file mode 100644 index 641050e6..00000000 --- a/3rd/libuv-1.19.2/test/test-env-vars.c +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" -#include - -#define BUF_SIZE 10 - -TEST_IMPL(env_vars) { - const char* name = "UV_TEST_FOO"; - char buf[BUF_SIZE]; - size_t size; - int r; - - /* Reject invalid inputs when setting an environment variable */ - r = uv_os_setenv(NULL, "foo"); - ASSERT(r == UV_EINVAL); - r = uv_os_setenv(name, NULL); - ASSERT(r == UV_EINVAL); - r = uv_os_setenv(NULL, NULL); - ASSERT(r == UV_EINVAL); - - /* Reject invalid inputs when retrieving an environment variable */ - size = BUF_SIZE; - r = uv_os_getenv(NULL, buf, &size); - ASSERT(r == UV_EINVAL); - r = uv_os_getenv(name, NULL, &size); - ASSERT(r == UV_EINVAL); - r = uv_os_getenv(name, buf, NULL); - ASSERT(r == UV_EINVAL); - size = 0; - r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_EINVAL); - - /* Reject invalid inputs when deleting an environment variable */ - r = uv_os_unsetenv(NULL); - ASSERT(r == UV_EINVAL); - - /* Successfully set an environment variable */ - r = uv_os_setenv(name, "123456789"); - ASSERT(r == 0); - - /* Successfully read an environment variable */ - size = BUF_SIZE; - buf[0] = '\0'; - r = uv_os_getenv(name, buf, &size); - ASSERT(r == 0); - ASSERT(strcmp(buf, "123456789") == 0); - ASSERT(size == BUF_SIZE - 1); - - /* Return UV_ENOBUFS if the buffer cannot hold the environment variable */ - size = BUF_SIZE - 1; - buf[0] = '\0'; - r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_ENOBUFS); - ASSERT(size == BUF_SIZE); - - /* Successfully delete an environment variable */ - r = uv_os_unsetenv(name); - ASSERT(r == 0); - - /* Return UV_ENOENT retrieving an environment variable that does not exist */ - r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_ENOENT); - - /* Successfully delete an environment variable that does not exist */ - r = uv_os_unsetenv(name); - ASSERT(r == 0); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-error.c b/3rd/libuv-1.19.2/test/test-error.c deleted file mode 100644 index a2d559a4..00000000 --- a/3rd/libuv-1.19.2/test/test-error.c +++ /dev/null @@ -1,73 +0,0 @@ -/* 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" -#if defined(_WIN32) -# include "../src/win/winapi.h" -#endif - -#include -#include -#include - - -/* - * 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; -} - - -TEST_IMPL(sys_error) { -#if defined(_WIN32) - ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); - ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); - ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); - ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); -#else - ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM); - ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE); - ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL); -#endif - ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL); - ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE); - ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES); - ASSERT(uv_translate_sys_error(0) == 0); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-fail-always.c b/3rd/libuv-1.19.2/test/test-fail-always.c deleted file mode 100644 index 0008459e..00000000 --- a/3rd/libuv-1.19.2/test/test-fail-always.c +++ /dev/null @@ -1,29 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-fork.c b/3rd/libuv-1.19.2/test/test-fork.c deleted file mode 100644 index 39b59c8f..00000000 --- a/3rd/libuv-1.19.2/test/test-fork.c +++ /dev/null @@ -1,681 +0,0 @@ -/* Copyright 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. - */ - -/* These tests are Unix only. */ -#ifndef _WIN32 - -#include -#include -#include -#include - -#include "uv.h" -#include "task.h" - -static int timer_cb_called; -static int socket_cb_called; - -static void timer_cb(uv_timer_t* timer) { - timer_cb_called++; - uv_close((uv_handle_t*) timer, NULL); -} - - -static int socket_cb_read_fd; -static int socket_cb_read_size; -static char socket_cb_read_buf[1024]; - - -static void socket_cb(uv_poll_t* poll, int status, int events) { - ssize_t cnt; - socket_cb_called++; - ASSERT(0 == status); - printf("Socket cb got events %d\n", events); - ASSERT(UV_READABLE == (events & UV_READABLE)); - if (socket_cb_read_fd) { - cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size); - ASSERT(cnt == socket_cb_read_size); - } - uv_close((uv_handle_t*) poll, NULL); -} - - -static void run_timer_loop_once(void) { - uv_loop_t* loop; - uv_timer_t timer_handle; - - loop = uv_default_loop(); - - timer_cb_called = 0; /* Reset for the child. */ - - 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); -} - - -static void assert_wait_child(pid_t child_pid) { - pid_t waited_pid; - int child_stat; - - waited_pid = waitpid(child_pid, &child_stat, 0); - printf("Waited pid is %d with status %d\n", waited_pid, child_stat); - if (waited_pid == -1) { - perror("Failed to wait"); - } - ASSERT(child_pid == waited_pid); - ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ - ASSERT(!WIFSIGNALED(child_stat)); - ASSERT(0 == WEXITSTATUS(child_stat)); -} - - -TEST_IMPL(fork_timer) { - /* Timers continue to work after we fork. */ - - /* - * Establish the loop before we fork to make sure that it - * has state to get reset after the fork. - */ - pid_t child_pid; - - run_timer_loop_once(); - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - assert_wait_child(child_pid); - } else { - /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - run_timer_loop_once(); - } - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -TEST_IMPL(fork_socketpair) { - /* A socket opened in the parent and accept'd in the - child works after a fork. */ - pid_t child_pid; - int socket_fds[2]; - uv_poll_t poll_handle; - - /* Prime the loop. */ - run_timer_loop_once(); - - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); - - /* Create the server watcher in the parent, use it in the child. */ - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); - - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); - assert_wait_child(child_pid); - } else { - /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(0 == socket_cb_called); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); - printf("Going to run the loop in the child\n"); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == socket_cb_called); - } - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -TEST_IMPL(fork_socketpair_started) { - /* A socket opened in the parent and accept'd in the - child works after a fork, even if the watcher was already - started, and then stopped in the parent. */ - pid_t child_pid; - int socket_fds[2]; - int sync_pipe[2]; - char sync_buf[1]; - uv_poll_t poll_handle; - - ASSERT(0 == pipe(sync_pipe)); - - /* Prime the loop. */ - run_timer_loop_once(); - - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); - - /* Create and start the server watcher in the parent, use it in the child. */ - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); - - /* Run the loop AFTER the poll watcher is registered to make sure it - gets passed to the kernel. Use NOWAIT and expect a non-zero - return to prove the poll watcher is active. - */ - ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - ASSERT(0 == uv_poll_stop(&poll_handle)); - uv_close((uv_handle_t*)&poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == socket_cb_called); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */ - ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); - - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == socket_cb_called); - - assert_wait_child(child_pid); - } else { - /* child */ - printf("Child is %d\n", getpid()); - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(0 == socket_cb_called); - - printf("Going to run the loop in the child\n"); - socket_cb_read_fd = socket_fds[0]; - socket_cb_read_size = 3; - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == socket_cb_called); - printf("Buf %s\n", socket_cb_read_buf); - ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); - } - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -static int fork_signal_cb_called; - -void fork_signal_to_child_cb(uv_signal_t* handle, int signum) -{ - fork_signal_cb_called = signum; - uv_close((uv_handle_t*)handle, NULL); -} - - -TEST_IMPL(fork_signal_to_child) { - /* A signal handler installed before forking - is run only in the child when the child is signalled. */ - uv_signal_t signal_handle; - pid_t child_pid; - int sync_pipe[2]; - char sync_buf[1]; - - fork_signal_cb_called = 0; /* reset */ - - ASSERT(0 == pipe(sync_pipe)); - - /* Prime the loop. */ - run_timer_loop_once(); - - ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); - ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); - - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ - ASSERT(0 == kill(child_pid, SIGUSR1)); - /* Run the loop, make sure we don't get the signal. */ - printf("Running loop in parent\n"); - uv_unref((uv_handle_t*)&signal_handle); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - ASSERT(0 == fork_signal_cb_called); - printf("Waiting for child in parent\n"); - assert_wait_child(child_pid); - } else { - /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ - /* Get the signal. */ - ASSERT(0 != uv_loop_alive(uv_default_loop())); - printf("Running loop in child\n"); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(SIGUSR1 == fork_signal_cb_called); - } - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -TEST_IMPL(fork_signal_to_child_closed) { - /* A signal handler installed before forking - doesn't get received anywhere when the child is signalled, - but isnt running the loop. */ - uv_signal_t signal_handle; - pid_t child_pid; - int sync_pipe[2]; - int sync_pipe2[2]; - char sync_buf[1]; - - fork_signal_cb_called = 0; /* reset */ - - ASSERT(0 == pipe(sync_pipe)); - ASSERT(0 == pipe(sync_pipe2)); - - /* Prime the loop. */ - run_timer_loop_once(); - - ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); - ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); - - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - printf("Wating on child in parent\n"); - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ - printf("Parent killing child\n"); - ASSERT(0 == kill(child_pid, SIGUSR1)); - /* Run the loop, make sure we don't get the signal. */ - printf("Running loop in parent\n"); - uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit; - we *shouldn't* get any signals */ - run_timer_loop_once(); /* but while we share a pipe, we do, so - have something active. */ - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - printf("Signal in parent %d\n", fork_signal_cb_called); - ASSERT(0 == fork_signal_cb_called); - ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */ - printf("Waiting for child in parent\n"); - assert_wait_child(child_pid); - } else { - /* child */ - /* Our signal handler should still be installed. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - printf("Checking loop in child\n"); - ASSERT(0 != uv_loop_alive(uv_default_loop())); - printf("Alerting parent in child\n"); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ - /* Don't run the loop. Wait for the parent to call us */ - printf("Waiting on parent in child\n"); - /* Wait for parent. read may fail if the parent tripped an ASSERT - and exited, so this isn't in an ASSERT. - */ - read(sync_pipe2[0], sync_buf, 1); - ASSERT(0 == fork_signal_cb_called); - printf("Exiting child \n"); - /* Note that we're deliberately not running the loop - * in the child, and also not closing the loop's handles, - * so the child default loop can't be cleanly closed. - * We need to explicitly exit to avoid an automatic failure - * in that case. - */ - exit(0); - } - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -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 int timer_cb_touch_called; - -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 int fs_event_cb_called; - -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(status == 0); -#if defined(__APPLE__) || defined(__linux__) - ASSERT(strcmp(filename, "watch_file") == 0); -#else - ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); -#endif - uv_close((uv_handle_t*)handle, NULL); -} - - -static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) { - uv_timer_t timer; - uv_fs_event_t fs_event; - int r; - - /* Setup */ - remove("watch_file"); - create_file("watch_file"); - - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - /* watching a dir is the only way to get fsevents involved on apple - platforms */ - r = uv_fs_event_start(&fs_event, - fs_event_cb_file_current_dir, - file_or_dir == 1 ? "." : "watch_file", - 0); - ASSERT(r == 0); - - r = uv_timer_init(loop, &timer); - ASSERT(r == 0); - - r = uv_timer_start(&timer, timer_cb_touch, 100, 0); - ASSERT(r == 0); - - ASSERT(timer_cb_touch_called == 0); - ASSERT(fs_event_cb_called == 0); - - uv_run(loop, UV_RUN_DEFAULT); - - ASSERT(timer_cb_touch_called == 1); - ASSERT(fs_event_cb_called == 1); - - /* Cleanup */ - remove("watch_file"); - fs_event_cb_called = 0; - timer_cb_touch_called = 0; - uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */ -} - - -#define FS_TEST_FILE 0 -#define FS_TEST_DIR 1 - -static int _do_fork_fs_events_child(int file_or_dir) { - /* basic fsevents work in the child after a fork */ - pid_t child_pid; - uv_loop_t loop; - - /* Watch in the parent, prime the loop and/or threads. */ - assert_watch_file_current_dir(uv_default_loop(), file_or_dir); - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - assert_wait_child(child_pid); - } else { - /* child */ - /* Ee can watch in a new loop, but dirs only work - if we're on linux. */ -#if defined(__APPLE__) - file_or_dir = FS_TEST_FILE; -#endif - printf("Running child\n"); - uv_loop_init(&loop); - printf("Child first watch\n"); - assert_watch_file_current_dir(&loop, file_or_dir); - ASSERT(0 == uv_loop_close(&loop)); - printf("Child second watch default loop\n"); - /* Ee can watch in the default loop. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - /* On some platforms (OS X), if we don't update the time now, - * the timer cb fires before the event loop enters uv__io_poll, - * instead of after, meaning we don't see the change! This may be - * a general race. - */ - uv_update_time(uv_default_loop()); - assert_watch_file_current_dir(uv_default_loop(), file_or_dir); - - /* We can close the parent loop successfully too. This is - especially important on Apple platforms where if we're not - careful trying to touch the CFRunLoop, even just to shut it - down, that we allocated in the FS_TEST_DIR case would crash. */ - ASSERT(0 == uv_loop_close(uv_default_loop())); - - printf("Exiting child \n"); - } - - MAKE_VALGRIND_HAPPY(); - return 0; - -} - - -TEST_IMPL(fork_fs_events_child) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - return _do_fork_fs_events_child(FS_TEST_FILE); -} - - -TEST_IMPL(fork_fs_events_child_dir) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif -#if defined(__APPLE__) || defined (__linux__) - return _do_fork_fs_events_child(FS_TEST_DIR); -#else - /* You can't spin up a cfrunloop thread on an apple platform - and then fork. See - http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale - */ - return 0; -#endif -} - - -TEST_IMPL(fork_fs_events_file_parent_child) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif -#if defined(__sun) || defined(_AIX) || defined(__MVS__) - /* It's not possible to implement this without additional - * bookkeeping on SunOS. For AIX it is possible, but has to be - * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 - * TODO: On z/OS, we need to open another message queue and subscribe to the - * same events as the parent. - */ - return 0; -#else - /* Establishing a started fs events watcher in the parent should - still work in the child. */ - uv_timer_t timer; - uv_fs_event_t fs_event; - int r; - pid_t child_pid; - uv_loop_t* loop; - - 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); - - child_pid = fork(); - ASSERT(child_pid != -1); - if (child_pid != 0) { - /* parent */ - assert_wait_child(child_pid); - } else { - /* child */ - printf("Running child\n"); - ASSERT(0 == uv_loop_fork(loop)); - - r = uv_timer_start(&timer, timer_cb_touch, 100, 0); - ASSERT(r == 0); - - ASSERT(timer_cb_touch_called == 0); - ASSERT(fs_event_cb_called == 0); - printf("Running loop in child \n"); - uv_run(loop, UV_RUN_DEFAULT); - - ASSERT(timer_cb_touch_called == 1); - ASSERT(fs_event_cb_called == 1); - - /* Cleanup */ - remove("watch_file"); - fs_event_cb_called = 0; - timer_cb_touch_called = 0; - uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */ - } - - - MAKE_VALGRIND_HAPPY(); - return 0; -#endif -} - - -static int work_cb_count; -static int after_work_cb_count; - - -static void work_cb(uv_work_t* req) { - work_cb_count++; -} - - -static void after_work_cb(uv_work_t* req, int status) { - ASSERT(status == 0); - after_work_cb_count++; -} - - -static void assert_run_work(uv_loop_t* const loop) { - uv_work_t work_req; - int r; - - ASSERT(work_cb_count == 0); - ASSERT(after_work_cb_count == 0); - printf("Queue in %d\n", getpid()); - r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); - ASSERT(r == 0); - printf("Running in %d\n", getpid()); - uv_run(loop, UV_RUN_DEFAULT); - - ASSERT(work_cb_count == 1); - ASSERT(after_work_cb_count == 1); - - /* cleanup */ - work_cb_count = 0; - after_work_cb_count = 0; -} - - -#ifndef __MVS__ -TEST_IMPL(fork_threadpool_queue_work_simple) { - /* The threadpool works in a child process. */ - - pid_t child_pid; - uv_loop_t loop; - - /* Prime the pool and default loop. */ - assert_run_work(uv_default_loop()); - - child_pid = fork(); - ASSERT(child_pid != -1); - - if (child_pid != 0) { - /* parent */ - /* We can still run work. */ - assert_run_work(uv_default_loop()); - assert_wait_child(child_pid); - } else { - /* child */ - /* We can work in a new loop. */ - printf("Running child in %d\n", getpid()); - uv_loop_init(&loop); - printf("Child first watch\n"); - assert_run_work(&loop); - uv_loop_close(&loop); - printf("Child second watch default loop\n"); - /* We can work in the default loop. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - assert_run_work(uv_default_loop()); - printf("Exiting child \n"); - } - - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif /* !__MVS__ */ - - -#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-fs-copyfile.c b/3rd/libuv-1.19.2/test/test-fs-copyfile.c deleted file mode 100644 index 4b1fdc5e..00000000 --- a/3rd/libuv-1.19.2/test/test-fs-copyfile.c +++ /dev/null @@ -1,173 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" - -#if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) || defined(__MVS__) -#include /* unlink, etc. */ -#else -# include -# include -# define unlink _unlink -#endif - -static const char fixture[] = "test/fixtures/load_error.node"; -static const char dst[] = "test_file_dst"; -static int result_check_count; - - -static void fail_cb(uv_fs_t* req) { - FATAL("fail_cb should not have been called"); -} - -static void handle_result(uv_fs_t* req) { - uv_fs_t stat_req; - uint64_t size; - uint64_t mode; - int r; - - ASSERT(req->fs_type == UV_FS_COPYFILE); - ASSERT(req->result == 0); - - /* Verify that the file size and mode are the same. */ - r = uv_fs_stat(NULL, &stat_req, req->path, NULL); - ASSERT(r == 0); - size = stat_req.statbuf.st_size; - mode = stat_req.statbuf.st_mode; - uv_fs_req_cleanup(&stat_req); - r = uv_fs_stat(NULL, &stat_req, dst, NULL); - ASSERT(r == 0); - ASSERT(stat_req.statbuf.st_size == size); - ASSERT(stat_req.statbuf.st_mode == mode); - uv_fs_req_cleanup(&stat_req); - uv_fs_req_cleanup(req); - result_check_count++; -} - - -static void touch_file(const char* name, unsigned int size) { - uv_file file; - uv_fs_t req; - uv_buf_t buf; - int r; - unsigned int i; - - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, - S_IWUSR | S_IRUSR, NULL); - uv_fs_req_cleanup(&req); - ASSERT(r >= 0); - file = r; - - buf = uv_buf_init("a", 1); - - /* Inefficient but simple. */ - for (i = 0; i < size; i++) { - r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL); - uv_fs_req_cleanup(&req); - ASSERT(r >= 0); - } - - r = uv_fs_close(NULL, &req, file, NULL); - uv_fs_req_cleanup(&req); - ASSERT(r == 0); -} - - -TEST_IMPL(fs_copyfile) { - const char src[] = "test_file_src"; - uv_loop_t* loop; - uv_fs_t req; - int r; - - loop = uv_default_loop(); - - /* Fails with EINVAL if bad flags are passed. */ - r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); - ASSERT(r == UV_EINVAL); - uv_fs_req_cleanup(&req); - - /* Fails with ENOENT if source does not exist. */ - unlink(src); - unlink(dst); - r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(req.result == UV_ENOENT); - ASSERT(r == UV_ENOENT); - uv_fs_req_cleanup(&req); - /* The destination should not exist. */ - r = uv_fs_stat(NULL, &req, dst, NULL); - ASSERT(r != 0); - uv_fs_req_cleanup(&req); - - /* Copies file synchronously. Creates new file. */ - unlink(dst); - r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); - ASSERT(r == 0); - handle_result(&req); - - /* Copies a file of size zero. */ - unlink(dst); - touch_file(src, 0); - r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); - handle_result(&req); - - /* Copies file synchronously. Overwrites existing file. */ - r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); - ASSERT(r == 0); - handle_result(&req); - - /* Fails to overwrites existing file. */ - r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); - ASSERT(r == UV_EEXIST); - uv_fs_req_cleanup(&req); - - /* Truncates when an existing destination is larger than the source file. */ - touch_file(src, 1); - r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); - handle_result(&req); - - /* Copies a larger file. */ - unlink(dst); - touch_file(src, 4096 * 2); - r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); - handle_result(&req); - unlink(src); - - /* Copies file asynchronously */ - unlink(dst); - r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); - ASSERT(r == 0); - ASSERT(result_check_count == 5); - uv_run(loop, UV_RUN_DEFAULT); - ASSERT(result_check_count == 6); - - /* If the flags are invalid, the loop should not be kept open */ - unlink(dst); - r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb); - ASSERT(r == UV_EINVAL); - uv_run(loop, UV_RUN_DEFAULT); - unlink(dst); /* Cleanup */ - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-fs-event.c b/3rd/libuv-1.19.2/test/test-fs-event.c deleted file mode 100644 index 39d73300..00000000 --- a/3rd/libuv-1.19.2/test/test-fs-event.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* 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 -#include - -#ifndef HAVE_KQUEUE -# if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# define HAVE_KQUEUE 1 -# endif -#endif - -#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */ -# define CREATE_TIMEOUT 100 -#else -# define CREATE_TIMEOUT 1 -#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 int timer_cb_exact_called; - -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 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, - CREATE_TIMEOUT, - 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 || events == 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) { -#ifdef _WIN32 - /* Each file created (or deleted) will cause this callback to be called twice - * under Windows: once with the name of the file, and second time with the - * name of the directory. We will ignore the callback for the directory - * itself. */ - if (filename && strcmp(filename, file_prefix_in_subdir) == 0) - return; -#endif - fs_event_cb_called++; - ASSERT(handle == &fs_event); - ASSERT(status == 0); - ASSERT(events == UV_CHANGE || events == 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_exact(uv_timer_t* handle) { - int r; - - if (timer_cb_exact_called == 0) { - touch_file("watch_dir/file.js"); - } else { - uv_close((uv_handle_t*)handle, NULL); - r = uv_fs_event_stop(&fs_event); - ASSERT(r == 0); - uv_close((uv_handle_t*) &fs_event, NULL); - } - - ++timer_cb_exact_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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#elif defined(__MVS__) - RETURN_SKIP("Directory watching not supported on this platform."); -#endif - - 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - - 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_exact_path) { - /* - This test watches a file named "file.jsx" and modifies a file named - "file.js". The test verifies that no events occur for file.jsx. - */ - -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - - uv_loop_t* loop; - int r; - - loop = uv_default_loop(); - - /* Setup */ - remove("watch_dir/file.js"); - remove("watch_dir/file.jsx"); - remove("watch_dir/"); - create_dir("watch_dir"); - create_file("watch_dir/file.js"); - create_file("watch_dir/file.jsx"); - - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); - ASSERT(r == 0); - r = uv_timer_init(loop, &timer); - ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_exact, 100, 100); - ASSERT(r == 0); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(timer_cb_exact_called == 2); - - /* Cleanup */ - remove("watch_dir/file.js"); - remove("watch_dir/file.jsx"); - remove("watch_dir/"); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(fs_event_watch_file_twice) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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, 100, 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; -} - -#ifdef _WIN32 -TEST_IMPL(fs_event_watch_file_root_dir) { - uv_loop_t* loop; - int r; - - const char* sys_drive = getenv("SystemDrive"); - char path[] = "\\\\?\\X:\\bootsect.bak"; - - ASSERT(sys_drive != NULL); - strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); - - loop = uv_default_loop(); - - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - r = uv_fs_event_start(&fs_event, fail_cb, path, 0); - if (r == UV_ENOENT) - RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); - ASSERT(r == 0); - - uv_close((uv_handle_t*) &fs_event, NULL); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif - -TEST_IMPL(fs_event_no_callback_after_close) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - - 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - - 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 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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; -} - -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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#elif defined(__MVS__) - RETURN_SKIP("Directory watching not supported on this platform."); -#endif - uv_loop_t* loop; - int r; - - loop = uv_default_loop(); - - fs_event_unlink_files(NULL); - 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_close, "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); - - uv_close((uv_handle_t*)&timer, close_cb); - - uv_run(loop, UV_RUN_ONCE); - - ASSERT(close_cb_called == 2); - ASSERT(fs_event_cb_called == 3); - - /* Clean up */ - fs_event_unlink_files(NULL); - remove("watch_dir/"); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(fs_event_start_and_close) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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(buf[len] == '\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__) */ - -TEST_IMPL(fs_event_watch_invalid_path) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - - uv_loop_t* loop; - int r; - - loop = uv_default_loop(); - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0); - ASSERT(r != 0); - ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-fs-poll.c b/3rd/libuv-1.19.2/test/test-fs-poll.c deleted file mode 100644 index 737d50df..00000000 --- a/3rd/libuv-1.19.2/test/test-fs-poll.c +++ /dev/null @@ -1,187 +0,0 @@ -/* 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 - -#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(buf[len] == '\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/3rd/libuv-1.19.2/test/test-fs.c b/3rd/libuv-1.19.2/test/test-fs.c deleted file mode 100644 index 3318b866..00000000 --- a/3rd/libuv-1.19.2/test/test-fs.c +++ /dev/null @@ -1,3174 +0,0 @@ -/* 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 -#include /* memset */ -#include -#include - -/* FIXME we shouldn't need to branch in this file */ -#if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) || defined(__MVS__) -#include /* unlink, rmdir, etc. */ -#else -# include -# include -# include -# ifndef ERROR_SYMLINK_NOT_SUPPORTED -# define ERROR_SYMLINK_NOT_SUPPORTED 1464 -# endif -# 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; - -#ifdef _WIN32 -/* - * This tag and guid have no special meaning, and don't conflict with - * reserved ids. -*/ -static unsigned REPARSE_TAG = 0x9913; -static GUID REPARSE_GUID = { - 0x1bf6205f, 0x46ae, 0x4527, - 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }; -#endif - -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; -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) - /* - * 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); -#if defined(_WIN32) || defined(__MSYS__) - /* 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 -# if defined(__CYGWIN__) - /* On Cygwin, uid 0 is invalid (no root). */ - ASSERT(req->result == UV_EINVAL); -# else - ASSERT(req->result == UV_EPERM); -# endif -#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 fail_cb(uv_fs_t* req) { - FATAL("fail_cb should not have been called"); -} - -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 non_existent_scandir_cb(uv_fs_t* req) { - uv_dirent_t dent; - - ASSERT(req == &scandir_req); - ASSERT(req->fs_type == UV_FS_SCANDIR); - ASSERT(req->result == UV_ENOENT); - ASSERT(req->ptr == NULL); - ASSERT(UV_ENOENT == 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; -#elif defined(__MSYS__) - /* MSYS2's approximation of symlinks with copies does not work for broken - links. */ - if (r == UV_ENOENT) - 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 + (s->st_atim.tv_nsec / 1000000000.0) == atime); - ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == 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(__ANDROID__) - ASSERT(s->st_atim.tv_sec == t.st_atime); - ASSERT(s->st_atim.tv_nsec == t.st_atimensec); - ASSERT(s->st_mtim.tv_sec == t.st_mtime); - ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec); - ASSERT(s->st_ctim.tv_sec == t.st_ctime); - ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec); -#elif defined(__sun) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) || \ - defined(_GNU_SOURCE) || \ - 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(__FreeBSD__) || \ - 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); - -#ifndef __MVS__ - /* chown to root (fail) */ - chown_cb_count = 0; - r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); - ASSERT(r == 0); - uv_run(loop, UV_RUN_DEFAULT); - ASSERT(chown_cb_count == 1); -#endif - - /* 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); - -#if defined(__MSYS__) - RETURN_SKIP("symlink reading is not supported on MSYS2"); -#endif - - 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; -} - - -int test_symlink_dir_impl(int type) { - 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", type, NULL); - if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) { - uv_fs_req_cleanup(&req); - RETURN_SKIP("this version of Windows doesn't support unprivileged " - "creation of directory symlinks"); - } - 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); -#if defined(__MSYS__) - RETURN_SKIP("symlink reading is not supported on MSYS2"); -#endif - 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_symlink_dir) { - return test_symlink_dir_impl(UV_FS_SYMLINK_DIR); -} - -TEST_IMPL(fs_symlink_junction) { - return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION); -} - -#ifdef _WIN32 -TEST_IMPL(fs_non_symlink_reparse_point) { - uv_fs_t req; - int r; - HANDLE file_handle; - REPARSE_GUID_DATA_BUFFER reparse_buffer; - DWORD bytes_returned; - uv_dirent_t dent; - - /* set-up */ - unlink("test_dir/test_file"); - rmdir("test_dir"); - - loop = uv_default_loop(); - - uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); - uv_fs_req_cleanup(&req); - - file_handle = CreateFile("test_dir/test_file", - GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, - 0, - NULL, - CREATE_ALWAYS, - FILE_FLAG_OPEN_REPARSE_POINT | - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - ASSERT(file_handle != INVALID_HANDLE_VALUE); - - memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); - reparse_buffer.ReparseTag = REPARSE_TAG; - reparse_buffer.ReparseDataLength = 0; - reparse_buffer.ReparseGuid = REPARSE_GUID; - - r = DeviceIoControl(file_handle, - FSCTL_SET_REPARSE_POINT, - &reparse_buffer, - REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, - NULL, - 0, - &bytes_returned, - NULL); - ASSERT(r != 0); - - CloseHandle(file_handle); - - r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL); - ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED); - uv_fs_req_cleanup(&req); - -/* - Placeholder tests for exercising the behavior fixed in issue #995. - To run, update the path with the IP address of a Mac with the hard drive - shared via SMB as "Macintosh HD". - - r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); - ASSERT(r == 0); - uv_fs_req_cleanup(&req); - - r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); - ASSERT(r == 0); - uv_fs_req_cleanup(&req); -*/ - -/* - uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse - points when a minifilter driver is registered which intercepts - associated filesystem requests. Installing a driver is beyond - the scope of this test. - - r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); - ASSERT(r == 0); - uv_fs_req_cleanup(&req); - - r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); - ASSERT(r == 0); - uv_fs_req_cleanup(&req); -*/ - - r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); - ASSERT(r == 1); - ASSERT(scandir_req.result == 1); - ASSERT(scandir_req.ptr); - while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { - ASSERT(strcmp(dent.name, "test_file") == 0); - /* uv_fs_scandir incorrectly identifies non-symlink reparse points - as links because it doesn't open the file and verify the reparse - point tag. The PowerShell Get-ChildItem command shares this - behavior, so it's reasonable to leave it as is. */ - ASSERT(dent.type == UV_DIRENT_LINK); - } - uv_fs_req_cleanup(&scandir_req); - ASSERT(!scandir_req.ptr); - - /* clean-up */ - unlink("test_dir/test_file"); - rmdir("test_dir"); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif - - -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 */ - - /* - * Test sub-second timestamps only on Windows (assuming NTFS). Some other - * platforms support sub-second timestamps, but that support is filesystem- - * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. - */ -#ifdef _WIN32 - mtime += 0.444; /* 1982-09-10 11:22:33.444 */ -#endif - - 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; - - 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) { -#if defined(_AIX) && !defined(_AIX71) - RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); -#else - 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 */ - - /* - * Test sub-second timestamps only on Windows (assuming NTFS). Some other - * platforms support sub-second timestamps, but that support is filesystem- - * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. - */ -#ifdef _WIN32 - mtime += 0.444; /* 1982-09-10 11:22:33.444 */ -#endif - - 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); -#if defined(__CYGWIN__) || defined(__MSYS__) - ASSERT(r == UV_ENOSYS); - RETURN_SKIP("futime not supported on Cygwin"); -#else - ASSERT(r == 0); - ASSERT(req.result == 0); -#endif - 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; -#endif -} - - -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_non_existent_dir) { - const char* path; - uv_fs_t req; - uv_dirent_t dent; - int r; - - path = "./non_existent_dir/"; - loop = uv_default_loop(); - - uv_fs_rmdir(NULL, &req, path, 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 == UV_ENOENT); - ASSERT(req.result == UV_ENOENT); - ASSERT(req.ptr == NULL); - ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent)); - uv_fs_req_cleanup(&req); - - r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_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_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) { -#if defined(__CYGWIN__) || defined(__MSYS__) - RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!"); -#endif - 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((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); - - 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, &read_req, 0, NULL, 0, -1, NULL); - ASSERT(r == UV_EINVAL); - uv_fs_req_cleanup(&read_req); - - r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL); - /* Validate some memory management on failed input validation before sending - fs work to the thread pool. */ - ASSERT(r == UV_EINVAL); - ASSERT(write_req.path == NULL); - ASSERT(write_req.ptr == NULL); -#ifdef _WIN32 - ASSERT(write_req.file.pathw == NULL); - ASSERT(write_req.fs.info.new_pathw == NULL); - ASSERT(write_req.fs.info.bufs == NULL); -#else - ASSERT(write_req.new_path == NULL); - ASSERT(write_req.bufs == NULL); -#endif - uv_fs_req_cleanup(&write_req); - - iov = uv_buf_init(NULL, 0); - r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL); - ASSERT(r == UV_EINVAL); - uv_fs_req_cleanup(&read_req); - - iov = uv_buf_init(NULL, 0); - r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL); - ASSERT(r == UV_EINVAL); - uv_fs_req_cleanup(&write_req); - - /* If the arguments are invalid, the loop should not be kept open */ - loop = uv_default_loop(); - - r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); - uv_run(loop, UV_RUN_DEFAULT); - uv_fs_req_cleanup(&read_req); - - r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); - uv_run(loop, UV_RUN_DEFAULT); - uv_fs_req_cleanup(&write_req); - - iov = uv_buf_init(NULL, 0); - r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); - uv_run(loop, UV_RUN_DEFAULT); - uv_fs_req_cleanup(&read_req); - - iov = uv_buf_init(NULL, 0); - r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); - uv_run(loop, UV_RUN_DEFAULT); - uv_fs_req_cleanup(&write_req); - - return 0; -} - - -TEST_IMPL(get_osfhandle_valid_handle) { - int r; - uv_os_fd_t fd; - - /* Setup. */ - unlink("test_file"); - - loop = uv_default_loop(); - - 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); - - fd = uv_get_osfhandle(open_req1.result); -#ifdef _WIN32 - ASSERT(fd != INVALID_HANDLE_VALUE); -#else - ASSERT(fd >= 0); -#endif - - 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_file_pos_after_op_with_offset) { - int r; - - /* Setup. */ - unlink("test_file"); - loop = uv_default_loop(); - - r = uv_fs_open(loop, - &open_req1, - "test_file", - O_RDWR | O_CREAT, - S_IWUSR | S_IRUSR, - NULL); - ASSERT(r > 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, 0, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); - uv_fs_req_cleanup(&write_req); - - iov = uv_buf_init(buf, sizeof(buf)); - r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(strcmp(buf, test_buf) == 0); - ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); - uv_fs_req_cleanup(&read_req); - - r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - uv_fs_req_cleanup(&close_req); - - /* Cleanup */ - unlink("test_file"); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(fs_null_req) { - /* Verify that all fs functions return UV_EINVAL when the request is NULL. */ - int r; - - r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_close(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - 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); - - r = uv_fs_unlink(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_rmdir(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_link(NULL, NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_readlink(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_realpath(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_stat(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_lstat(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_fstat(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_fsync(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_fdatasync(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_access(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL); - ASSERT(r == UV_EINVAL); - - r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL); - ASSERT(r == UV_EINVAL); - - /* This should be a no-op. */ - uv_fs_req_cleanup(NULL); - - return 0; -} - -#ifdef _WIN32 -TEST_IMPL(fs_exclusive_sharing_mode) { - int r; - - /* Setup. */ - unlink("test_file"); - - ASSERT(UV_FS_O_EXLOCK > 0); - - r = uv_fs_open(NULL, - &open_req1, - "test_file", - O_RDWR | O_CREAT | UV_FS_O_EXLOCK, - S_IWUSR | S_IRUSR, - NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); - uv_fs_req_cleanup(&open_req1); - - r = uv_fs_open(NULL, - &open_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, - S_IWUSR | S_IRUSR, - NULL); - ASSERT(r < 0); - ASSERT(open_req2.result < 0); - uv_fs_req_cleanup(&open_req2); - - 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_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, - S_IWUSR | S_IRUSR, - NULL); - ASSERT(r >= 0); - ASSERT(open_req2.result >= 0); - uv_fs_req_cleanup(&open_req2); - - r = uv_fs_close(NULL, &close_req, open_req2.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; -} -#endif diff --git a/3rd/libuv-1.19.2/test/test-get-currentexe.c b/3rd/libuv-1.19.2/test/test-get-currentexe.c deleted file mode 100644 index 0e9d6965..00000000 --- a/3rd/libuv-1.19.2/test/test-get-currentexe.c +++ /dev/null @@ -1,86 +0,0 @@ -/* 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 - -#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/3rd/libuv-1.19.2/test/test-get-loadavg.c b/3rd/libuv-1.19.2/test/test-get-loadavg.c deleted file mode 100644 index 4762e475..00000000 --- a/3rd/libuv-1.19.2/test/test-get-loadavg.c +++ /dev/null @@ -1,35 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-get-memory.c b/3rd/libuv-1.19.2/test/test-get-memory.c deleted file mode 100644 index 2396939b..00000000 --- a/3rd/libuv-1.19.2/test/test-get-memory.c +++ /dev/null @@ -1,38 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-get-passwd.c b/3rd/libuv-1.19.2/test/test-get-passwd.c deleted file mode 100644 index 8e16fb83..00000000 --- a/3rd/libuv-1.19.2/test/test-get-passwd.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" -#include - -TEST_IMPL(get_passwd) { - uv_passwd_t pwd; - size_t len; - int r; - - /* Test the normal case */ - r = uv_os_get_passwd(&pwd); - ASSERT(r == 0); - len = strlen(pwd.username); - ASSERT(len > 0); - -#ifdef _WIN32 - ASSERT(pwd.shell == NULL); -#else - len = strlen(pwd.shell); - ASSERT(len > 0); -#endif - - len = strlen(pwd.homedir); - ASSERT(len > 0); - -#ifdef _WIN32 - if (len == 3 && pwd.homedir[1] == ':') - ASSERT(pwd.homedir[2] == '\\'); - else - ASSERT(pwd.homedir[len - 1] != '\\'); -#else - if (len == 1) - ASSERT(pwd.homedir[0] == '/'); - else - ASSERT(pwd.homedir[len - 1] != '/'); -#endif - -#ifdef _WIN32 - ASSERT(pwd.uid == -1); - ASSERT(pwd.gid == -1); -#else - ASSERT(pwd.uid >= 0); - ASSERT(pwd.gid >= 0); -#endif - - /* Test uv_os_free_passwd() */ - uv_os_free_passwd(&pwd); - - ASSERT(pwd.username == NULL); - ASSERT(pwd.shell == NULL); - ASSERT(pwd.homedir == NULL); - - /* Test a double free */ - uv_os_free_passwd(&pwd); - - ASSERT(pwd.username == NULL); - ASSERT(pwd.shell == NULL); - ASSERT(pwd.homedir == NULL); - - /* Test invalid input */ - r = uv_os_get_passwd(NULL); - ASSERT(r == UV_EINVAL); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-getaddrinfo.c b/3rd/libuv-1.19.2/test/test-getaddrinfo.c deleted file mode 100644 index 03dc1269..00000000 --- a/3rd/libuv-1.19.2/test/test-getaddrinfo.c +++ /dev/null @@ -1,191 +0,0 @@ -/* 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 - -#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; - - ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), - &req, - (uv_getaddrinfo_cb) abort, - NULL, - NULL, - NULL)); - - /* 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/3rd/libuv-1.19.2/test/test-gethostname.c b/3rd/libuv-1.19.2/test/test-gethostname.c deleted file mode 100644 index 5229804b..00000000 --- a/3rd/libuv-1.19.2/test/test-gethostname.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" -#include - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 -#endif - -TEST_IMPL(gethostname) { - char buf[MAXHOSTNAMELEN + 1]; - size_t size; - size_t enobufs_size; - int r; - - /* Reject invalid inputs */ - size = 1; - r = uv_os_gethostname(NULL, &size); - ASSERT(r == UV_EINVAL); - r = uv_os_gethostname(buf, NULL); - ASSERT(r == UV_EINVAL); - size = 0; - r = uv_os_gethostname(buf, &size); - ASSERT(r == UV_EINVAL); - - /* Return UV_ENOBUFS if the buffer cannot hold the hostname */ - enobufs_size = 1; - buf[0] = '\0'; - r = uv_os_gethostname(buf, &enobufs_size); - ASSERT(r == UV_ENOBUFS); - ASSERT(buf[0] == '\0'); - ASSERT(enobufs_size > 1); - - /* Successfully get the hostname */ - size = MAXHOSTNAMELEN + 1; - r = uv_os_gethostname(buf, &size); - ASSERT(r == 0); - ASSERT(size > 1 && size == strlen(buf)); - ASSERT(size + 1 == enobufs_size); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-getnameinfo.c b/3rd/libuv-1.19.2/test/test-getnameinfo.c deleted file mode 100644 index b1391616..00000000 --- a/3rd/libuv-1.19.2/test/test-getnameinfo.c +++ /dev/null @@ -1,101 +0,0 @@ -/* 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 -#include -#include - - -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/3rd/libuv-1.19.2/test/test-getsockname.c b/3rd/libuv-1.19.2/test/test-getsockname.c deleted file mode 100644 index 565c17fe..00000000 --- a/3rd/libuv-1.19.2/test/test-getsockname.c +++ /dev/null @@ -1,361 +0,0 @@ -/* 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 -#include -#include - -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/3rd/libuv-1.19.2/test/test-getters-setters.c b/3rd/libuv-1.19.2/test/test-getters-setters.c deleted file mode 100644 index 60a1b926..00000000 --- a/3rd/libuv-1.19.2/test/test-getters-setters.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "uv.h" -#include "task.h" -#include -#include - -int cookie1; -int cookie2; -int cookie3; - - -TEST_IMPL(handle_type_name) { - ASSERT(strcmp(uv_handle_type_name(UV_NAMED_PIPE), "pipe") == 0); - ASSERT(strcmp(uv_handle_type_name(UV_UDP), "udp") == 0); - ASSERT(strcmp(uv_handle_type_name(UV_FILE), "file") == 0); - ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX) == NULL); - ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX + 1) == NULL); - ASSERT(uv_handle_type_name(UV_UNKNOWN_HANDLE) == NULL); - return 0; -} - - -TEST_IMPL(req_type_name) { - ASSERT(strcmp(uv_req_type_name(UV_REQ), "req") == 0); - ASSERT(strcmp(uv_req_type_name(UV_UDP_SEND), "udp_send") == 0); - ASSERT(strcmp(uv_req_type_name(UV_WORK), "work") == 0); - ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX) == NULL); - ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX + 1) == NULL); - ASSERT(uv_req_type_name(UV_UNKNOWN_REQ) == NULL); - return 0; -} - - -TEST_IMPL(getters_setters) { - uv_loop_t* loop; - uv_pipe_t* pipe; - uv_fs_t* fs; - int r; - - loop = malloc(uv_loop_size()); - ASSERT(loop != NULL); - r = uv_loop_init(loop); - ASSERT(r == 0); - - uv_loop_set_data(loop, &cookie1); - ASSERT(loop->data == &cookie1); - ASSERT(uv_loop_get_data(loop) == &cookie1); - - pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); - r = uv_pipe_init(loop, pipe, 0); - ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); - - ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); - pipe->data = &cookie2; - ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie2); - uv_handle_set_data((uv_handle_t*)pipe, &cookie1); - ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie1); - ASSERT(pipe->data == &cookie1); - - ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 0); - pipe->write_queue_size++; - ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 1); - pipe->write_queue_size--; - uv_close((uv_handle_t*)pipe, NULL); - - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - - fs = malloc(uv_req_size(UV_FS)); - uv_fs_stat(loop, fs, ".", NULL); - - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - - ASSERT(uv_fs_get_type(fs) == UV_FS_STAT); - ASSERT(uv_fs_get_result(fs) == 0); - ASSERT(uv_fs_get_ptr(fs) == uv_fs_get_statbuf(fs)); - ASSERT(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); - ASSERT(strcmp(uv_fs_get_path(fs), ".") == 0); - uv_fs_req_cleanup(fs); - - r = uv_loop_close(loop); - ASSERT(r == 0); - - free(pipe); - free(fs); - free(loop); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-handle-fileno.c b/3rd/libuv-1.19.2/test/test-handle-fileno.c deleted file mode 100644 index 3fe933ad..00000000 --- a/3rd/libuv-1.19.2/test/test-handle-fileno.c +++ /dev/null @@ -1,121 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-homedir.c b/3rd/libuv-1.19.2/test/test-homedir.c deleted file mode 100644 index 856534a4..00000000 --- a/3rd/libuv-1.19.2/test/test-homedir.c +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" -#include - -#define PATHMAX 1024 -#define SMALLPATH 1 - -TEST_IMPL(homedir) { - char homedir[PATHMAX]; - size_t len; - 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'); - -#ifdef _WIN32 - if (len == 3 && homedir[1] == ':') - ASSERT(homedir[2] == '\\'); - else - ASSERT(homedir[len - 1] != '\\'); -#else - if (len == 1) - ASSERT(homedir[0] == '/'); - else - ASSERT(homedir[len - 1] != '/'); -#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/3rd/libuv-1.19.2/test/test-hrtime.c b/3rd/libuv-1.19.2/test/test-hrtime.c deleted file mode 100644 index 72a4d4b1..00000000 --- a/3rd/libuv-1.19.2/test/test-hrtime.c +++ /dev/null @@ -1,54 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-idle.c b/3rd/libuv-1.19.2/test/test-idle.c deleted file mode 100644 index f49d1964..00000000 --- a/3rd/libuv-1.19.2/test/test-idle.c +++ /dev/null @@ -1,99 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-ip4-addr.c b/3rd/libuv-1.19.2/test/test-ip4-addr.c deleted file mode 100644 index 3d6e0cf2..00000000 --- a/3rd/libuv-1.19.2/test/test-ip4-addr.c +++ /dev/null @@ -1,46 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-ip6-addr.c b/3rd/libuv-1.19.2/test/test-ip6-addr.c deleted file mode 100644 index 25570dca..00000000 --- a/3rd/libuv-1.19.2/test/test-ip6-addr.c +++ /dev/null @@ -1,162 +0,0 @@ -/* 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 -#include - -#ifdef __linux__ -# include -# include -#endif - - -TEST_IMPL(ip6_addr_link_local) { -#if defined(__CYGWIN__) || defined(__MSYS__) - /* FIXME: Does Cygwin support this? */ - RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); -#endif - 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]; - size_t scoped_addr_len; - char interface_id[UV_IF_NAMESIZE]; - size_t interface_id_len; - int count; - int ix; - int r; - - 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; - - scoped_addr_len = sizeof(scoped_addr); - ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr, &scoped_addr_len)); -#ifndef _WIN32 - /* This assert fails on Windows, as Windows semantics are different. */ - ASSERT(0 == strcmp(device_name, scoped_addr)); -#endif - - interface_id_len = sizeof(interface_id); - r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); - ASSERT(0 == r); -#ifdef _WIN32 - /* On Windows, the interface identifier is the numeric string of the index. */ - ASSERT(strtol(interface_id, NULL, 10) == iface_index); -#else - /* On Unix/Linux, the interface identifier is the interface device name. */ - ASSERT(0 == strcmp(device_name, interface_id)); -#endif - - snprintf(scoped_addr, - sizeof(scoped_addr), - "%s%%%s", - string_address, - interface_id); - - 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); - - scoped_addr_len = sizeof(scoped_addr); - ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); - - 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/3rd/libuv-1.19.2/test/test-ipc-send-recv.c b/3rd/libuv-1.19.2/test/test-ipc-send-recv.c deleted file mode 100644 index 917744cb..00000000 --- a/3rd/libuv-1.19.2/test/test-ipc-send-recv.c +++ /dev/null @@ -1,428 +0,0 @@ -/* 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 -#include - -/* 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_count; -static int recv_cb_count; -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; - - pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx.channel); - - do { - if (++recv_cb_count == 1) { - recv = &ctx.recv; - } else { - recv = &ctx.recv2; - } - - /* 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_count == 2); - } else { - ASSERT(nread >= 0); - ASSERT(uv_pipe_pending_count(pipe) > 0); - - 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); - } - } while (uv_pipe_pending_count(pipe) > 0); - - /* Close after two writes received */ - if (recv_cb_count == 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_count == 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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - return run_ipc_send_recv_pipe(0); -} - -TEST_IMPL(ipc_send_recv_pipe_inprocess) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - return run_ipc_send_recv_tcp(0); -} - -TEST_IMPL(ipc_send_recv_tcp_inprocess) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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; - } - - pipe = (uv_pipe_t*) handle; - do { - if (++read_cb_count == 2) { - recv = &ctx2.recv; - write_req = &ctx2.write_req; - } else { - recv = &ctx2.recv2; - write_req = &ctx2.write_req2; - } - - ASSERT(pipe == &ctx2.channel); - ASSERT(nread >= 0); - ASSERT(uv_pipe_pending_count(pipe) > 0); - - 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); - } while (uv_pipe_pending_count(pipe) > 0); -} - -static void send_recv_start(void) { - 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/3rd/libuv-1.19.2/test/test-ipc.c b/3rd/libuv-1.19.2/test/test-ipc.c deleted file mode 100644 index 88d63d4d..00000000 --- a/3rd/libuv-1.19.2/test/test-ipc.c +++ /dev/null @@ -1,887 +0,0 @@ -/* 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 -#include - -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; -static int closed_handle_data_read; - -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 -#define LARGE_SIZE 1000000 - - -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); -} - - -#ifndef _WIN32 -static void on_read_closed_handle(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - if (nread == 0 || nread == UV_EOF) { - free(buf->base); - return; - } - - if (nread < 0) { - printf("error recving on channel: %s\n", uv_strerror(nread)); - abort(); - } - - closed_handle_data_read += nread; - free(buf->base); -} -#endif - - -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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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; -} - -#ifndef _WIN32 -TEST_IMPL(ipc_closed_handle) { - int r; - r = run_ipc_test("ipc_helper_closed_handle", on_read_closed_handle); - ASSERT(r == 0); - return 0; -} -#endif - - -#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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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 closed_handle_large_write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); - ASSERT(closed_handle_data_read = LARGE_SIZE); -} - - -static void closed_handle_write_cb(uv_write_t* req, int status) { - ASSERT(status == UV_EBADF); -} - - -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_closed_handle(void) { - int r; - struct sockaddr_in addr; - uv_write_t write_req; - uv_write_t write_req2; - uv_buf_t buf; - char buffer[LARGE_SIZE]; - - 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)); - - memset(buffer, '.', LARGE_SIZE); - buf = uv_buf_init(buffer, LARGE_SIZE); - - 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_write(&write_req, - (uv_stream_t*)&channel, - &buf, - 1, - closed_handle_large_write_cb); - ASSERT(r == 0); - - r = uv_write2(&write_req2, - (uv_stream_t*)&channel, - &buf, - 1, - (uv_stream_t*)&tcp_server, - closed_handle_write_cb); - ASSERT(r == 0); - - uv_close((uv_handle_t*)&tcp_server, NULL); - - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - - 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/3rd/libuv-1.19.2/test/test-list.h b/3rd/libuv-1.19.2/test/test-list.h deleted file mode 100644 index ff0a31d1..00000000 --- a/3rd/libuv-1.19.2/test/test-list.h +++ /dev/null @@ -1,905 +0,0 @@ -/* 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" - -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_instant_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 (condvar_6) -TEST_DECLARE (semaphore_1) -TEST_DECLARE (semaphore_2) -TEST_DECLARE (semaphore_3) -TEST_DECLARE (tty) -#ifdef _WIN32 -TEST_DECLARE (tty_raw) -TEST_DECLARE (tty_empty_write) -TEST_DECLARE (tty_large_write) -#endif -TEST_DECLARE (tty_file) -TEST_DECLARE (tty_pty) -TEST_DECLARE (stdio_over_pipes) -TEST_DECLARE (ip6_pton) -TEST_DECLARE (connect_unspecified) -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) -#ifndef _WIN32 -TEST_DECLARE (ipc_closed_handle) -#endif -TEST_DECLARE (tcp_alloc_cb_fail) -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_open_bound) -TEST_DECLARE (tcp_open_connected) -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_alloc_cb_fail) -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_hang_loop) -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 (env_vars) -TEST_DECLARE (error_message) -TEST_DECLARE (sys_error) -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 (timer_early_check) -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 (pipe_set_chmod) -TEST_DECLARE (process_ref) -TEST_DECLARE (has_ref) -TEST_DECLARE (active) -TEST_DECLARE (embed) -TEST_DECLARE (async) -TEST_DECLARE (async_null_cb) -TEST_DECLARE (eintr_handling) -TEST_DECLARE (get_currentexe) -TEST_DECLARE (process_title) -TEST_DECLARE (process_title_threadsafe) -TEST_DECLARE (cwd_and_chdir) -TEST_DECLARE (get_memory) -TEST_DECLARE (get_passwd) -TEST_DECLARE (handle_fileno) -TEST_DECLARE (homedir) -TEST_DECLARE (tmpdir) -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 (gethostname) -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 (spawn_quoted_path) -TEST_DECLARE (spawn_tcp_server) -TEST_DECLARE (fs_poll) -TEST_DECLARE (fs_poll_getpath) -TEST_DECLARE (kill) -TEST_DECLARE (kill_invalid_signum) -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_copyfile) -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) -#ifdef _WIN32 -TEST_DECLARE (fs_symlink_junction) -TEST_DECLARE (fs_non_symlink_reparse_point) -#endif -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_exact_path) -TEST_DECLARE (fs_event_watch_file_twice) -TEST_DECLARE (fs_event_watch_file_current_dir) -#ifdef _WIN32 -TEST_DECLARE (fs_event_watch_file_root_dir) -#endif -TEST_DECLARE (fs_event_watch_invalid_path) -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_non_existent_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 (get_osfhandle_valid_handle) -TEST_DECLARE (fs_write_alotof_bufs) -TEST_DECLARE (fs_write_alotof_bufs_with_offset) -TEST_DECLARE (fs_file_pos_after_op_with_offset) -TEST_DECLARE (fs_null_req) -#ifdef _WIN32 -TEST_DECLARE (fs_exclusive_sharing_mode) -#endif -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_stack_size) -TEST_DECLARE (thread_mutex) -TEST_DECLARE (thread_mutex_recursive) -TEST_DECLARE (thread_rwlock) -TEST_DECLARE (thread_rwlock_trylock) -TEST_DECLARE (thread_create) -TEST_DECLARE (thread_equal) -TEST_DECLARE (dlerror) -#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ - !defined(__sun) -TEST_DECLARE (poll_oob) -#endif -TEST_DECLARE (poll_duplex) -TEST_DECLARE (poll_unidirectional) -TEST_DECLARE (poll_close) -TEST_DECLARE (poll_bad_fdtype) -#ifdef __linux__ -TEST_DECLARE (poll_nested_epoll) -#endif -#ifdef UV_HAVE_KQUEUE -TEST_DECLARE (poll_nested_kqueue) -#endif - -TEST_DECLARE (ip4_addr) -TEST_DECLARE (ip6_addr_link_local) - -TEST_DECLARE (poll_close_doesnt_corrupt_stack) -TEST_DECLARE (poll_closesocket) -#ifdef _WIN32 -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) -TEST_DECLARE (win32_signum_number) -#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 (we_get_signal_one_shot) -TEST_DECLARE (we_get_signals_mixed) -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) - -TEST_DECLARE (handle_type_name) -TEST_DECLARE (req_type_name) -TEST_DECLARE (getters_setters) - -#ifndef _WIN32 -TEST_DECLARE (fork_timer) -TEST_DECLARE (fork_socketpair) -TEST_DECLARE (fork_socketpair_started) -TEST_DECLARE (fork_signal_to_child) -TEST_DECLARE (fork_signal_to_child_closed) -TEST_DECLARE (fork_fs_events_child) -TEST_DECLARE (fork_fs_events_child_dir) -TEST_DECLARE (fork_fs_events_file_parent_child) -#ifndef __MVS__ -TEST_DECLARE (fork_threadpool_queue_work_simple) -#endif -#endif - -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_instant_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 (condvar_6) - 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 (pipe_set_chmod) - TEST_ENTRY (tty) -#ifdef _WIN32 - TEST_ENTRY (tty_raw) - TEST_ENTRY (tty_empty_write) - TEST_ENTRY (tty_large_write) -#endif - TEST_ENTRY (tty_file) - TEST_ENTRY (tty_pty) - TEST_ENTRY (stdio_over_pipes) - TEST_ENTRY (ip6_pton) - TEST_ENTRY (connect_unspecified) - 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) -#ifndef _WIN32 - TEST_ENTRY (ipc_closed_handle) -#endif - - TEST_ENTRY (tcp_alloc_cb_fail) - - 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 - -#ifdef __MVS__ - TEST_ENTRY_CUSTOM (tcp_writealot, 0, 0, 20000) -#else - TEST_ENTRY (tcp_writealot) -#endif - 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_open_bound) - TEST_ENTRY (tcp_open_connected) - TEST_HELPER (tcp_open_connected, tcp4_echo_server) - - 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_alloc_cb_fail) - 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_hang_loop) - 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 (env_vars) - - TEST_ENTRY (error_message) - TEST_ENTRY (sys_error) - - 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 (timer_early_check) - - 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 (eintr_handling) - - TEST_ENTRY (get_currentexe) - - TEST_ENTRY (process_title) - TEST_ENTRY (process_title_threadsafe) - - TEST_ENTRY (cwd_and_chdir) - - TEST_ENTRY (get_memory) - - TEST_ENTRY (get_passwd) - - TEST_ENTRY (get_loadavg) - - TEST_ENTRY (handle_fileno) - - TEST_ENTRY (homedir) - - TEST_ENTRY (tmpdir) - - 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 (gethostname) - - 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 (poll_bad_fdtype) -#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ - !defined(__sun) - TEST_ENTRY (poll_oob) -#endif - -#ifdef __linux__ - TEST_ENTRY (poll_nested_epoll) -#endif -#ifdef UV_HAVE_KQUEUE - TEST_ENTRY (poll_nested_kqueue) -#endif - - 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 (spawn_quoted_path) - TEST_ENTRY (spawn_tcp_server) - TEST_ENTRY (fs_poll) - TEST_ENTRY (fs_poll_getpath) - TEST_ENTRY (kill) - TEST_ENTRY (kill_invalid_signum) - - TEST_ENTRY (poll_close_doesnt_corrupt_stack) - TEST_ENTRY (poll_closesocket) -#ifdef _WIN32 - 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) - TEST_ENTRY (win32_signum_number) -#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 (we_get_signal_one_shot) - TEST_ENTRY (we_get_signals_mixed) - 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_copyfile) - 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) -#ifdef _WIN32 - TEST_ENTRY (fs_symlink_junction) - TEST_ENTRY (fs_non_symlink_reparse_point) -#endif - 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_exact_path) - TEST_ENTRY (fs_event_watch_file_twice) - TEST_ENTRY (fs_event_watch_file_current_dir) -#ifdef _WIN32 - TEST_ENTRY (fs_event_watch_file_root_dir) -#endif - TEST_ENTRY (fs_event_watch_invalid_path) - 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_non_existent_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 (fs_file_pos_after_op_with_offset) - TEST_ENTRY (fs_null_req) -#ifdef _WIN32 - TEST_ENTRY (fs_exclusive_sharing_mode) -#endif - TEST_ENTRY (get_osfhandle_valid_handle) - 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_stack_size) - TEST_ENTRY (thread_mutex) - TEST_ENTRY (thread_mutex_recursive) - 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) - - TEST_ENTRY (handle_type_name) - TEST_ENTRY (req_type_name) - TEST_ENTRY (getters_setters) - -#ifndef _WIN32 - TEST_ENTRY (fork_timer) - TEST_ENTRY (fork_socketpair) - TEST_ENTRY (fork_socketpair_started) - TEST_ENTRY (fork_signal_to_child) - TEST_ENTRY (fork_signal_to_child_closed) - TEST_ENTRY (fork_fs_events_child) - TEST_ENTRY (fork_fs_events_child_dir) - TEST_ENTRY (fork_fs_events_file_parent_child) -#ifndef __MVS__ - TEST_ENTRY (fork_threadpool_queue_work_simple) -#endif -#endif - -#if 0 - /* These are for testing the test runner. */ - TEST_ENTRY (fail_always) - TEST_ENTRY (pass_always) -#endif -TASK_LIST_END diff --git a/3rd/libuv-1.19.2/test/test-loop-alive.c b/3rd/libuv-1.19.2/test/test-loop-alive.c deleted file mode 100644 index cf4d3019..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-alive.c +++ /dev/null @@ -1,67 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-loop-close.c b/3rd/libuv-1.19.2/test/test-loop-close.c deleted file mode 100644 index f0f3e627..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-close.c +++ /dev/null @@ -1,75 +0,0 @@ -/* 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; - - loop.data = &loop; - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(loop.data == (void*) &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(loop.data == (void*) &loop); - ASSERT(0 == uv_loop_close(&loop)); - ASSERT(loop.data == (void*) &loop); - - return 0; -} - -static void loop_instant_close_work_cb(uv_work_t* req) { -} - -static void loop_instant_close_after_work_cb(uv_work_t* req, int status) { -} - -TEST_IMPL(loop_instant_close) { - static uv_loop_t loop; - static uv_work_t req; - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_queue_work(&loop, - &req, - loop_instant_close_work_cb, - loop_instant_close_after_work_cb)); - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-loop-configure.c b/3rd/libuv-1.19.2/test/test-loop-configure.c deleted file mode 100644 index d057c1ed..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-configure.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2014, Ben Noordhuis - * - * 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/3rd/libuv-1.19.2/test/test-loop-handles.c b/3rd/libuv-1.19.2/test/test-loop-handles.c deleted file mode 100644 index c3e8498a..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-handles.c +++ /dev/null @@ -1,337 +0,0 @@ -/* 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 - - -#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/3rd/libuv-1.19.2/test/test-loop-stop.c b/3rd/libuv-1.19.2/test/test-loop-stop.c deleted file mode 100644 index 14b8c111..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-stop.c +++ /dev/null @@ -1,71 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-loop-time.c b/3rd/libuv-1.19.2/test/test-loop-time.c deleted file mode 100644 index a2db42cc..00000000 --- a/3rd/libuv-1.19.2/test/test-loop-time.c +++ /dev/null @@ -1,63 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-multiple-listen.c b/3rd/libuv-1.19.2/test/test-multiple-listen.c deleted file mode 100644 index 4ae5fa67..00000000 --- a/3rd/libuv-1.19.2/test/test-multiple-listen.c +++ /dev/null @@ -1,109 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-mutexes.c b/3rd/libuv-1.19.2/test/test-mutexes.c deleted file mode 100644 index 975222ca..00000000 --- a/3rd/libuv-1.19.2/test/test-mutexes.c +++ /dev/null @@ -1,182 +0,0 @@ -/* 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 -#include - -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_mutex_recursive) { - uv_mutex_t mutex; - int r; - - r = uv_mutex_init_recursive(&mutex); - ASSERT(r == 0); - - uv_mutex_lock(&mutex); - uv_mutex_lock(&mutex); - ASSERT(0 == uv_mutex_trylock(&mutex)); - - uv_mutex_unlock(&mutex); - uv_mutex_unlock(&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/3rd/libuv-1.19.2/test/test-osx-select.c b/3rd/libuv-1.19.2/test/test-osx-select.c deleted file mode 100644 index a0afda91..00000000 --- a/3rd/libuv-1.19.2/test/test-osx-select.c +++ /dev/null @@ -1,140 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-pass-always.c b/3rd/libuv-1.19.2/test/test-pass-always.c deleted file mode 100644 index 4fb58ff9..00000000 --- a/3rd/libuv-1.19.2/test/test-pass-always.c +++ /dev/null @@ -1,28 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-ping-pong.c b/3rd/libuv-1.19.2/test/test-ping-pong.c deleted file mode 100644 index 508f0db6..00000000 --- a/3rd/libuv-1.19.2/test/test-ping-pong.c +++ /dev/null @@ -1,274 +0,0 @@ -/* 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 -#include - -static int completed_pingers = 0; - -#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__) -#define NUM_PINGS 100 /* fewer pings to avoid timeout */ -#else -#define NUM_PINGS 1000 -#endif - -/* 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/3rd/libuv-1.19.2/test/test-pipe-bind-error.c b/3rd/libuv-1.19.2/test/test-pipe-bind-error.c deleted file mode 100644 index 9cf93165..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-bind-error.c +++ /dev/null @@ -1,139 +0,0 @@ -/* 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 -#include - - -#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) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - 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/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c b/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c deleted file mode 100644 index 4ab14789..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c +++ /dev/null @@ -1,107 +0,0 @@ -/* 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 -#include -#include -#include - -#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; - char buf; - 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]); - /* block until write end of pipe is closed */ - read(fd[0], &buf, 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/3rd/libuv-1.19.2/test/test-pipe-connect-error.c b/3rd/libuv-1.19.2/test/test-pipe-connect-error.c deleted file mode 100644 index ebb2a6ca..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-connect-error.c +++ /dev/null @@ -1,95 +0,0 @@ -/* 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 -#include - - -#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/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c b/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c deleted file mode 100644 index 0a60d4a9..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (c) 2015 Saúl Ibarra Corretgé . - * 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 -#include - - -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) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - 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/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c b/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c deleted file mode 100644 index a86e7284..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2015 Saúl Ibarra Corretgé . - * 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 -#include - - -#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/3rd/libuv-1.19.2/test/test-pipe-getsockname.c b/3rd/libuv-1.19.2/test/test-pipe-getsockname.c deleted file mode 100644 index d1628a67..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-getsockname.c +++ /dev/null @@ -1,266 +0,0 @@ -/* 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 -#include -#include - -#if defined(__linux__) - #include - #include -#endif - -#ifndef _WIN32 -# include /* close */ -#else -# include -#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) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - 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(buf[len] == '\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(len1 == 0); /* It's an annonymous pipe. */ - - 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(len2 == 0); /* It's an annonymous pipe. */ - - 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); - - CloseHandle(writeh); -#endif - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c b/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c deleted file mode 100644 index b6ff911a..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (c) 2015 Saúl Ibarra Corretgé . - * 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/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c b/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c deleted file mode 100644 index 3bf427f8..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c +++ /dev/null @@ -1,172 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include - - -/* 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) { -#if defined(NO_SEND_HANDLE_ON_PIPE) - RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); -#endif - 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/3rd/libuv-1.19.2/test/test-pipe-server-close.c b/3rd/libuv-1.19.2/test/test-pipe-server-close.c deleted file mode 100644 index ea9977dd..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-server-close.c +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 -#include - - -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) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - 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/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c b/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c deleted file mode 100644 index 59f0e6f5..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 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. -*/ - - -#include "uv.h" -#include "task.h" - -TEST_IMPL(pipe_set_chmod) { - uv_pipe_t pipe_handle; - uv_loop_t* loop; - int r; - - loop = uv_default_loop(); - - r = uv_pipe_init(loop, &pipe_handle, 0); - ASSERT(r == 0); - - r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); - ASSERT(r == 0); - - /* No easy way to test if this works, we will only make sure that */ - /* the call is successful. */ - r = uv_pipe_chmod(&pipe_handle, UV_READABLE); - if (r == UV_EPERM) { - MAKE_VALGRIND_HAPPY(); - RETURN_SKIP("Insufficient privileges to alter pipe fmode"); - } - ASSERT(r == 0); - - r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); - ASSERT(r == 0); - - r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); - ASSERT(r == 0); - - r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); - ASSERT(r == UV_EBADF); - - r = uv_pipe_chmod(&pipe_handle, 12345678); - ASSERT(r == UV_EINVAL); - - uv_close((uv_handle_t*)&pipe_handle, NULL); - r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); - ASSERT(r == UV_EBADF); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c b/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c deleted file mode 100644 index fcc9fc0d..00000000 --- a/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (c) 2015, Ben Noordhuis - * - * 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 -#include -#include -#include -#include -#include - -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/3rd/libuv-1.19.2/test/test-platform-output.c b/3rd/libuv-1.19.2/test/test-platform-output.c deleted file mode 100644 index 4025fba5..00000000 --- a/3rd/libuv-1.19.2/test/test-platform-output.c +++ /dev/null @@ -1,157 +0,0 @@ -/* 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 - - -TEST_IMPL(platform_output) { - char buffer[512]; - size_t rss; - size_t size; - double uptime; - uv_pid_t pid; - uv_pid_t ppid; - uv_rusage_t rusage; - uv_cpu_info_t* cpus; - uv_interface_address_t* interfaces; - uv_passwd_t pwd; - 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); -#if defined(__CYGWIN__) || defined(__MSYS__) - ASSERT(err == UV_ENOSYS); -#else - ASSERT(err == 0); - printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); -#endif - - 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); - printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); - printf(" maximum resident set size: %llu\n", - (unsigned long long) rusage.ru_maxrss); - - err = uv_cpu_info(&cpus, &count); -#if defined(__CYGWIN__) || defined(__MSYS__) - ASSERT(err == UV_ENOSYS); -#else - 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); - } -#endif - 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); - - err = uv_os_get_passwd(&pwd); - ASSERT(err == 0); - - printf("uv_os_get_passwd:\n"); - printf(" euid: %ld\n", pwd.uid); - printf(" gid: %ld\n", pwd.gid); - printf(" username: %s\n", pwd.username); - printf(" shell: %s\n", pwd.shell); - printf(" home directory: %s\n", pwd.homedir); - - pid = uv_os_getpid(); - ASSERT(pid > 0); - printf("uv_os_getpid: %d\n", (int) pid); - ppid = uv_os_getppid(); - ASSERT(ppid > 0); - printf("uv_os_getppid: %d\n", (int) ppid); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c b/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c deleted file mode 100644 index 1dfc80e3..00000000 --- a/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c +++ /dev/null @@ -1,116 +0,0 @@ -/* 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. - */ - -#include -#include - -#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; - -#ifdef _WIN32 -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); -} -#endif - - -TEST_IMPL(poll_close_doesnt_corrupt_stack) { -#ifndef _WIN32 - RETURN_SKIP("Test only relevant on Windows"); -#else - 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 -} diff --git a/3rd/libuv-1.19.2/test/test-poll-close.c b/3rd/libuv-1.19.2/test/test-poll-close.c deleted file mode 100644 index 2eccddf5..00000000 --- a/3rd/libuv-1.19.2/test/test-poll-close.c +++ /dev/null @@ -1,73 +0,0 @@ -/* 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 - -#ifndef _WIN32 -# include -# include -# include -#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/3rd/libuv-1.19.2/test/test-poll-closesocket.c b/3rd/libuv-1.19.2/test/test-poll-closesocket.c deleted file mode 100644 index ecaa9e54..00000000 --- a/3rd/libuv-1.19.2/test/test-poll-closesocket.c +++ /dev/null @@ -1,93 +0,0 @@ -/* 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 - -#include "uv.h" -#include "task.h" - -uv_os_sock_t sock; -uv_poll_t handle; - -#ifdef _WIN32 -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); - -} -#endif - - -TEST_IMPL(poll_closesocket) { -#ifndef _WIN32 - RETURN_SKIP("Test only relevant on Windows"); -#else - 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/3rd/libuv-1.19.2/test/test-poll-oob.c b/3rd/libuv-1.19.2/test/test-poll-oob.c deleted file mode 100644 index 2a6da843..00000000 --- a/3rd/libuv-1.19.2/test/test-poll-oob.c +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright 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(_WIN32) - -#include "uv.h" -#include "task.h" - -#include -#include -#include -#include -#include - -static uv_tcp_t server_handle; -static uv_tcp_t client_handle; -static uv_tcp_t peer_handle; -static uv_poll_t poll_req[2]; -static uv_idle_t idle; -static uv_os_fd_t client_fd; -static uv_os_fd_t server_fd; -static int ticks; -static const int kMaxTicks = 10; -static int cli_pr_check = 0; -static int cli_rd_check = 0; -static int srv_rd_check = 0; - -static int got_eagain(void) { - return errno == EAGAIN - || errno == EINPROGRESS -#ifdef EWOULDBLOCK - || errno == EWOULDBLOCK -#endif - ; -} - -static void idle_cb(uv_idle_t* idle) { - uv_sleep(100); - if (++ticks < kMaxTicks) - return; - - uv_poll_stop(&poll_req[0]); - uv_poll_stop(&poll_req[1]); - 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 poll_cb(uv_poll_t* handle, int status, int events) { - char buffer[5]; - int n; - int fd; - - ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); - memset(buffer, 0, 5); - - if (events & UV_PRIORITIZED) { - do - n = recv(client_fd, &buffer, 5, MSG_OOB); - while (n == -1 && errno == EINTR); - ASSERT(n >= 0 || errno != EINVAL); - cli_pr_check = 1; - ASSERT(0 == uv_poll_stop(&poll_req[0])); - ASSERT(0 == uv_poll_start(&poll_req[0], - UV_READABLE | UV_WRITABLE, - poll_cb)); - } - if (events & UV_READABLE) { - if (fd == client_fd) { - do - n = recv(client_fd, &buffer, 5, 0); - while (n == -1 && errno == EINTR); - ASSERT(n >= 0 || errno != EINVAL); - if (cli_rd_check == 1) { - ASSERT(strncmp(buffer, "world", n) == 0); - ASSERT(5 == n); - cli_rd_check = 2; - } - if (cli_rd_check == 0) { - ASSERT(n == 4); - ASSERT(strncmp(buffer, "hello", n) == 0); - cli_rd_check = 1; - do { - do - n = recv(server_fd, &buffer, 5, 0); - while (n == -1 && errno == EINTR); - if (n > 0) { - ASSERT(n == 5); - ASSERT(strncmp(buffer, "world", n) == 0); - cli_rd_check = 2; - } - } while (n > 0); - - ASSERT(got_eagain()); - } - } - if (fd == server_fd) { - do - n = recv(server_fd, &buffer, 3, 0); - while (n == -1 && errno == EINTR); - ASSERT(n >= 0 || errno != EINVAL); - ASSERT(3 == n); - ASSERT(strncmp(buffer, "foo", n) == 0); - srv_rd_check = 1; - uv_poll_stop(&poll_req[1]); - } - } - if (events & UV_WRITABLE) { - do { - n = send(client_fd, "foo", 3, 0); - } while (n < 0 && errno == EINTR); - ASSERT(3 == n); - } -} - -static void connection_cb(uv_stream_t* handle, int status) { - int r; - - ASSERT(0 == status); - ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); - ASSERT(0 == uv_poll_start(&poll_req[0], - UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, - poll_cb)); - ASSERT(0 == uv_poll_start(&poll_req[1], - UV_READABLE, - poll_cb)); - do { - r = send(server_fd, "hello", 5, MSG_OOB); - } while (r < 0 && errno == EINTR); - ASSERT(5 == r); - - do { - r = send(server_fd, "world", 5, 0); - } while (r < 0 && errno == EINTR); - ASSERT(5 == r); - - ASSERT(0 == uv_idle_start(&idle, idle_cb)); -} - - -TEST_IMPL(poll_oob) { - struct sockaddr_in addr; - int r = 0; - 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)); - - client_fd = socket(PF_INET, SOCK_STREAM, 0); - ASSERT(client_fd >= 0); - do { - errno = 0; - r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); - } while (r == -1 && errno == EINTR); - ASSERT(r == 0); - - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - - ASSERT(ticks == kMaxTicks); - - /* Did client receive the POLLPRI message */ - ASSERT(cli_pr_check == 1); - /* Did client receive the POLLIN message */ - ASSERT(cli_rd_check == 2); - /* Could we write with POLLOUT and did the server receive our POLLOUT message - * through POLLIN. - */ - ASSERT(srv_rd_check == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif diff --git a/3rd/libuv-1.19.2/test/test-poll.c b/3rd/libuv-1.19.2/test/test-poll.c deleted file mode 100644 index e828addb..00000000 --- a/3rd/libuv-1.19.2/test/test-poll.c +++ /dev/null @@ -1,665 +0,0 @@ -/* 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 - -#ifdef _WIN32 -# include -#else -# include -# include -#endif - -#include "uv.h" -#include "task.h" - -#ifdef __linux__ -# include -#endif - -#ifdef UV_HAVE_KQUEUE -# include -# include -# include -#endif - - -#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, got_disconnect; - 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; - -#if !defined(_AIX) && !defined(__MVS__) -static int disconnects = 0; -#endif /* !_AIX && !__MVS__ */ - -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; - context->got_disconnect = 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 !defined(_AIX) && !defined(__MVS__) - if (events & UV_DISCONNECT) { - context->got_disconnect = 1; - ++disconnects; - new_events &= ~UV_DISCONNECT; - } - - if (context->got_fin && context->sent_fin && context->got_disconnect) { -#else /* _AIX && __MVS__ */ - if (context->got_fin && context->sent_fin) { -#endif /* !_AIX && !__MVS__ */ - /* 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 | UV_DISCONNECT; - r = uv_poll_start(&connection_context->poll_handle, - UV_READABLE | UV_WRITABLE | UV_DISCONNECT, - 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 | UV_DISCONNECT; - r = uv_poll_start(&context->poll_handle, - UV_READABLE | UV_WRITABLE | UV_DISCONNECT, - 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); -#if !defined(_AIX) && !defined(__MVS__) - ASSERT(disconnects == NUM_CLIENTS * 2); -#endif - MAKE_VALGRIND_HAPPY(); -} - - -TEST_IMPL(poll_duplex) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - test_mode = DUPLEX; - start_poll_test(); - return 0; -} - - -TEST_IMPL(poll_unidirectional) { -#if defined(NO_SELF_CONNECT) - RETURN_SKIP(NO_SELF_CONNECT); -#endif - test_mode = UNIDIRECTIONAL; - start_poll_test(); - return 0; -} - - -/* Windows won't let you open a directory so we open a file instead. - * OS X lets you poll a file so open the $PWD instead. Both fail - * on Linux so it doesn't matter which one we pick. Both succeed - * on FreeBSD, Solaris and AIX so skip the test on those platforms. - */ -TEST_IMPL(poll_bad_fdtype) { -#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ - !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) && \ - !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ - !defined(__NetBSD__) - uv_poll_t poll_handle; - int fd; - -#if defined(_WIN32) - fd = open("test/fixtures/empty_file", O_RDONLY); -#else - fd = open(".", O_RDONLY); -#endif - ASSERT(fd != -1); - ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == close(fd)); -#endif - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -#ifdef __linux__ -TEST_IMPL(poll_nested_epoll) { - uv_poll_t poll_handle; - int fd; - - fd = epoll_create(1); - ASSERT(fd != -1); - - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); - ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - - uv_close((uv_handle_t*) &poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == close(fd)); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif /* __linux__ */ - - -#ifdef UV_HAVE_KQUEUE -TEST_IMPL(poll_nested_kqueue) { - uv_poll_t poll_handle; - int fd; - - fd = kqueue(); - ASSERT(fd != -1); - - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); - ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - - uv_close((uv_handle_t*) &poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == close(fd)); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif /* UV_HAVE_KQUEUE */ diff --git a/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c b/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c deleted file mode 100644 index d986576e..00000000 --- a/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright 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. -*/ - - -#include "uv.h" -#include "task.h" - -#include - -#ifdef __APPLE__ -# define NUM_ITERATIONS 20 -#else -# define NUM_ITERATIONS 50 -#endif - -static const char* titles[] = { - "8L2NY0Kdj0XyNFZnmUZigIOfcWjyNr0SkMmUhKw99VLUsZFrvCQQC3XIRfNR8pjyMjXObllled", - "jUAcscJN49oLSN8GdmXj2Wo34XX2T2vp2j5khfajNQarlOulp57cE130yiY53ipJFnPyTn5i82", - "9niCI5icXGFS72XudhXqo5alftmZ1tpE7B3cwUmrq0CCDjC84FzBNB8XAHqvpNQfI2QAQG6ztT", - "n8qXVXuG6IEHDpabJgTEiwtpY6LHMZ8MgznnMpdHARu5EywufA6hcBaQfetb0YhEsK0ykDd7JU" -}; - -static void getter_thread_body(void* arg) { - char buffer[512]; - - for (;;) { - ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); - ASSERT( - 0 == strcmp(buffer, titles[0]) || - 0 == strcmp(buffer, titles[1]) || - 0 == strcmp(buffer, titles[2]) || - 0 == strcmp(buffer, titles[3])); - - uv_sleep(0); - } -} - - -static void setter_thread_body(void* arg) { - int i; - - for (i = 0; i < NUM_ITERATIONS; i++) { - ASSERT(0 == uv_set_process_title(titles[0])); - ASSERT(0 == uv_set_process_title(titles[1])); - ASSERT(0 == uv_set_process_title(titles[2])); - ASSERT(0 == uv_set_process_title(titles[3])); - } -} - - -TEST_IMPL(process_title_threadsafe) { - uv_thread_t setter_threads[4]; - uv_thread_t getter_thread; - int i; - -#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ - defined(__MVS__) - RETURN_SKIP("uv_(get|set)_process_title is not implemented."); -#else - - ASSERT(0 == uv_set_process_title(titles[0])); - ASSERT(0 == uv_thread_create(&getter_thread, getter_thread_body, NULL)); - - for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) - ASSERT(0 == uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); - - for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) - ASSERT(0 == uv_thread_join(&setter_threads[i])); - - return 0; -#endif -} diff --git a/3rd/libuv-1.19.2/test/test-process-title.c b/3rd/libuv-1.19.2/test/test-process-title.c deleted file mode 100644 index 886f83a7..00000000 --- a/3rd/libuv-1.19.2/test/test-process-title.c +++ /dev/null @@ -1,75 +0,0 @@ -/* 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 - - -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); -} - - -static void uv_get_process_title_edge_cases(void) { - char buffer[512]; - int r; - - /* Test a NULL buffer */ - r = uv_get_process_title(NULL, 100); - ASSERT(r == UV_EINVAL); - - /* Test size of zero */ - r = uv_get_process_title(buffer, 0); - ASSERT(r == UV_EINVAL); - - /* Test for insufficient buffer size */ - r = uv_get_process_title(buffer, 1); - ASSERT(r == UV_ENOBUFS); -} - - -TEST_IMPL(process_title) { -#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) - 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"); - - /* Check uv_get_process_title() edge cases */ - uv_get_process_title_edge_cases(); - - return 0; -#endif -} diff --git a/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c b/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c deleted file mode 100644 index 45da2253..00000000 --- a/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c +++ /dev/null @@ -1,200 +0,0 @@ -/* 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 - - -/* - * 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/3rd/libuv-1.19.2/test/test-ref.c b/3rd/libuv-1.19.2/test/test-ref.c deleted file mode 100644 index 05728c83..00000000 --- a/3rd/libuv-1.19.2/test/test-ref.c +++ /dev/null @@ -1,445 +0,0 @@ -/* 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 -#include - - -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) { -#if defined(NO_FS_EVENTS) - RETURN_SKIP(NO_FS_EVENTS); -#endif - 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/3rd/libuv-1.19.2/test/test-run-nowait.c b/3rd/libuv-1.19.2/test/test-run-nowait.c deleted file mode 100644 index 43524f63..00000000 --- a/3rd/libuv-1.19.2/test/test-run-nowait.c +++ /dev/null @@ -1,45 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-run-once.c b/3rd/libuv-1.19.2/test/test-run-once.c deleted file mode 100644 index 10cbf95e..00000000 --- a/3rd/libuv-1.19.2/test/test-run-once.c +++ /dev/null @@ -1,48 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-semaphore.c b/3rd/libuv-1.19.2/test/test-semaphore.c deleted file mode 100644 index ac03bb08..00000000 --- a/3rd/libuv-1.19.2/test/test-semaphore.c +++ /dev/null @@ -1,111 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-shutdown-close.c b/3rd/libuv-1.19.2/test/test-shutdown-close.c deleted file mode 100644 index 78c369be..00000000 --- a/3rd/libuv-1.19.2/test/test-shutdown-close.c +++ /dev/null @@ -1,108 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-shutdown-eof.c b/3rd/libuv-1.19.2/test/test-shutdown-eof.c deleted file mode 100644 index 9f95e756..00000000 --- a/3rd/libuv-1.19.2/test/test-shutdown-eof.c +++ /dev/null @@ -1,182 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-shutdown-twice.c b/3rd/libuv-1.19.2/test/test-shutdown-twice.c deleted file mode 100644 index d7aae899..00000000 --- a/3rd/libuv-1.19.2/test/test-shutdown-twice.c +++ /dev/null @@ -1,85 +0,0 @@ -/* 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); - 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(shutdown_cb_called == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c b/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c deleted file mode 100644 index 1272d457..00000000 --- a/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c +++ /dev/null @@ -1,298 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include - -/* 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) { -#if defined(__CYGWIN__) || defined(__MSYS__) - /* FIXME: This test needs more investigation. Somehow the `read` in - uv__signal_lock fails spuriously with EACCES or even EAGAIN even - though it is supposed to be blocking. Also the test hangs during - thread setup occasionally. */ - RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); -#endif - 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); - } - - uv_sem_destroy(&sem); - 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/3rd/libuv-1.19.2/test/test-signal.c b/3rd/libuv-1.19.2/test/test-signal.c deleted file mode 100644 index c2ce5ec0..00000000 --- a/3rd/libuv-1.19.2/test/test-signal.c +++ /dev/null @@ -1,325 +0,0 @@ -/* 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 -#endif - -TEST_IMPL(kill_invalid_signum) { - uv_pid_t pid; - - pid = uv_os_getpid(); - - ASSERT(uv_kill(pid, -1) == UV_EINVAL); -#ifdef _WIN32 - /* NSIG is not available on all platforms. */ - ASSERT(uv_kill(pid, NSIG) == UV_EINVAL); -#endif - ASSERT(uv_kill(pid, 4096) == UV_EINVAL); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -/* For Windows we test only signum handling */ -#ifdef _WIN32 -static void signum_test_cb(uv_signal_t* handle, int signum) { - FATAL("signum_test_cb should not be called"); -} - -TEST_IMPL(win32_signum_number) { - uv_signal_t signal; - uv_loop_t* loop; - - loop = uv_default_loop(); - uv_signal_init(loop, &signal); - - ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); - MAKE_VALGRIND_HAPPY(); - return 0; -} -#else -#include -#include -#include -#include -#include -#include -#include - -#define NSIGNALS 10 - -struct timer_ctx { - unsigned int ncalls; - uv_timer_t handle; - int signum; -}; - -struct signal_ctx { - enum { CLOSE, STOP, NOOP } stop_or_close; - unsigned int ncalls; - uv_signal_t handle; - int signum; - int one_shot; -}; - - -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 signal_cb_one_shot(uv_signal_t* handle, int signum) { - struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); - ASSERT(signum == ctx->signum); - ASSERT(++ctx->ncalls == 1); - if (ctx->stop_or_close == CLOSE) - uv_close((uv_handle_t*)handle, NULL); -} - - -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, - int one_shot) { - ctx->ncalls = 0; - ctx->signum = signum; - ctx->stop_or_close = CLOSE; - ctx->one_shot = one_shot; - ASSERT(0 == uv_signal_init(loop, &ctx->handle)); - if (one_shot) - ASSERT(0 == uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); - else - 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, 0); - 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, 0); - start_watcher(loop, SIGUSR1, sc + 1, 0); - start_watcher(loop, SIGUSR2, sc + 2, 0); - start_watcher(loop, SIGUSR2, sc + 3, 0); - 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; -} - -TEST_IMPL(we_get_signal_one_shot) { - 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, 1); - sc.stop_or_close = NOOP; - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == 1); - - start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(sc.ncalls == 1); - - sc.ncalls = 0; - sc.stop_or_close = CLOSE; /* now close it when it's done */ - uv_signal_start_oneshot(&sc.handle, signal_cb_one_shot, SIGCHLD); - start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(we_get_signals_mixed) { - struct signal_ctx sc[4]; - struct timer_ctx tc; - uv_loop_t* loop; - - loop = uv_default_loop(); - - /* 2 one-shot */ - start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, sc + 0, 1); - start_watcher(loop, SIGCHLD, sc + 1, 1); - sc[0].stop_or_close = CLOSE; - sc[1].stop_or_close = CLOSE; - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 1); - ASSERT(sc[1].ncalls == 1); - - /* 2 one-shot, 1 normal then remove normal */ - start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, sc + 0, 1); - start_watcher(loop, SIGCHLD, sc + 1, 1); - sc[0].stop_or_close = CLOSE; - sc[1].stop_or_close = CLOSE; - start_watcher(loop, SIGCHLD, sc + 2, 0); - uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 1); - ASSERT(sc[1].ncalls == 1); - ASSERT(sc[2].ncalls == 0); - - /* 2 normal, 1 one-shot then remove one-shot */ - start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, sc + 0, 0); - start_watcher(loop, SIGCHLD, sc + 1, 0); - sc[0].stop_or_close = CLOSE; - sc[1].stop_or_close = CLOSE; - start_watcher(loop, SIGCHLD, sc + 2, 1); - uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == NSIGNALS); - ASSERT(sc[1].ncalls == NSIGNALS); - ASSERT(sc[2].ncalls == 0); - - /* 2 normal, 2 one-shot then remove 2 normal */ - start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, sc + 0, 0); - start_watcher(loop, SIGCHLD, sc + 1, 0); - start_watcher(loop, SIGCHLD, sc + 2, 1); - start_watcher(loop, SIGCHLD, sc + 3, 1); - sc[2].stop_or_close = CLOSE; - sc[3].stop_or_close = CLOSE; - uv_close((uv_handle_t*)&(sc[0]).handle, NULL); - uv_close((uv_handle_t*)&(sc[1]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 0); - ASSERT(sc[1].ncalls == 0); - ASSERT(sc[2].ncalls == 1); - ASSERT(sc[2].ncalls == 1); - - /* 1 normal, 1 one-shot, 2 normal then remove 1st normal, 2nd normal */ - start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, sc + 0, 0); - start_watcher(loop, SIGCHLD, sc + 1, 1); - start_watcher(loop, SIGCHLD, sc + 2, 0); - start_watcher(loop, SIGCHLD, sc + 3, 0); - sc[3].stop_or_close = CLOSE; - uv_close((uv_handle_t*)&(sc[0]).handle, NULL); - uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 0); - ASSERT(sc[1].ncalls == 1); - ASSERT(sc[2].ncalls == 0); - ASSERT(sc[3].ncalls == NSIGNALS); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -#endif /* _WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-socket-buffer-size.c b/3rd/libuv-1.19.2/test/test-socket-buffer-size.c deleted file mode 100644 index 72f8c252..00000000 --- a/3rd/libuv-1.19.2/test/test-socket-buffer-size.c +++ /dev/null @@ -1,77 +0,0 @@ -/* 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 -#include -#include - -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/3rd/libuv-1.19.2/test/test-spawn.c b/3rd/libuv-1.19.2/test/test-spawn.c deleted file mode 100644 index 4a2869a1..00000000 --- a/3rd/libuv-1.19.2/test/test-spawn.c +++ /dev/null @@ -1,1875 +0,0 @@ - -/* 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 -#include -#include -#include -#include - -#ifdef _WIN32 -# if defined(__MINGW32__) -# include -# endif -# include -# include -#else -# include -# include -#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[5]; -static int no_term_signal; -static int timer_counter; -static uv_tcp_t tcp_server; - -#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 -#if defined(__APPLE__) || defined(__MVS__) - /* - * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a - * process that is still starting up kills it with SIGKILL instead of SIGTERM. - * See: https://github.com/libuv/libuv/issues/1226 - */ - ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL); -#else - ASSERT(no_term_signal || term_signal == SIGTERM); -#endif - 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; - args[3] = NULL; - args[4] = 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*)∈ - 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; -} - - -int spawn_tcp_server_helper(void) { - uv_tcp_t tcp; - uv_os_sock_t handle; - int r; - - r = uv_tcp_init(uv_default_loop(), &tcp); - ASSERT(r == 0); - -#ifdef _WIN32 - handle = _get_osfhandle(3); -#else - handle = 3; -#endif - r = uv_tcp_open(&tcp, handle); - ASSERT(r == 0); - - /* Make sure that we can listen on a socket that was - * passed down from the parent process - */ - r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL); - ASSERT(r == 0); - - return 1; -} - - -TEST_IMPL(spawn_tcp_server) { - uv_stdio_container_t stdio[4]; - struct sockaddr_in addr; - int fd; - int r; -#ifdef _WIN32 - uv_os_fd_t handle; -#endif - - init_process_options("spawn_tcp_server_helper", exit_cb); - - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - - fd = -1; - r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET); - ASSERT(r == 0); - r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); -#ifdef _WIN32 - r = uv_fileno((uv_handle_t*)&tcp_server, &handle); - fd = _open_osfhandle((intptr_t) handle, 0); -#else - r = uv_fileno((uv_handle_t*)&tcp_server, &fd); - #endif - ASSERT(r == 0); - ASSERT(fd > 0); - - options.stdio = stdio; - options.stdio[0].flags = UV_INHERIT_FD; - options.stdio[0].data.fd = 0; - options.stdio[1].flags = UV_INHERIT_FD; - options.stdio[1].data.fd = 1; - options.stdio[2].flags = UV_INHERIT_FD; - options.stdio[2].data.fd = 2; - options.stdio[3].flags = UV_INHERIT_FD; - options.stdio[3].data.fd = fd; - options.stdio_count = 4; - - 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_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); - - ASSERT(process.pid == uv_process_get_pid(&process)); - - 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*)∈ - 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*)∈ - 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*)∈ - 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*) ∈ - 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); - - /* Verify that uv_spawn() resets the signal disposition. */ -#ifndef _WIN32 - { - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGTERM); - ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL)); - } - ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); -#endif - - r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); - -#ifndef _WIN32 - { - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGTERM); - ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); - } - ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); -#endif - - /* 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; - char uidstr[10]; - char gidstr[10]; - - /* if not root, then this will fail. */ - uv_uid_t uid = getuid(); - if (uid != 0) { - RETURN_SKIP("It should be run as root user"); - } - - init_process_options("spawn_helper_setuid_setgid", exit_cb); - - /* become the "nobody" user. */ - pw = getpwnam("nobody"); - ASSERT(pw != NULL); - options.uid = pw->pw_uid; - options.gid = pw->pw_gid; - snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); - snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); - options.args[2] = uidstr; - options.args[3] = gidstr; - 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); -#if defined(__CYGWIN__) - ASSERT(r == UV_EINVAL); -#else - ASSERT(r == UV_EPERM); -#endif - - 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; -#if defined(__MVS__) - options.gid = -1; -#else - options.gid = 0; -#endif - - r = uv_spawn(uv_default_loop(), &process, &options); -#if defined(__CYGWIN__) || defined(__MVS__) - ASSERT(r == UV_EINVAL); -#else - ASSERT(r == UV_EPERM); -#endif - - 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*) ∈ - 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"; -#elif defined __MVS__ - static const char dyld_path_var[] = "LIBPATH"; -#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); -#if defined(__CYGWIN__) || defined(__MSYS__) - /* Carry over the dynamic linker path in case the test runner - is linked against cyguv-1.dll or msys-uv-1.dll, see above. */ - { - char* syspath = getenv("PATH"); - if (syspath != NULL) { - strcat(path, ":"); - strcat(path, syspath); - } - } -#endif - - 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; -} - -TEST_IMPL(spawn_quoted_path) { -#ifndef _WIN32 - RETURN_SKIP("Test for Windows"); -#else - char* quoted_path_env[2]; - args[0] = "not_existing"; - args[1] = NULL; - options.file = args[0]; - options.args = args; - options.exit_cb = exit_cb; - options.flags = 0; - /* We test if search_path works correctly with semicolons in quoted path. */ - /* We will use invalid drive, so we are sure no executable is spawned */ - quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; - quoted_path_env[1] = NULL; - options.env = quoted_path_env; - - /* We test if libuv will not segfault. */ - uv_spawn(uv_default_loop(), &process, &options); - - MAKE_VALGRIND_HAPPY(); - return 0; -#endif -} - -/* 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/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c b/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c deleted file mode 100644 index 15744761..00000000 --- a/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c +++ /dev/null @@ -1,255 +0,0 @@ -/* 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 -#include - - -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*)∈ - 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/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c deleted file mode 100644 index 61ca667a..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright 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 -#include -#include - -#include "uv.h" -#include "task.h" - -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 uv_write_t write_req; - -static char hello[] = "HELLO!"; - - -static void close_cb(uv_handle_t* handle) { - close_cb_called++; -} - -static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); -} - -static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { - /* Do nothing, read_cb should be called with UV_ENOBUFS. */ -} - -static void conn_read_cb(uv_stream_t* stream, - ssize_t nread, - const uv_buf_t* buf) { - ASSERT(nread == UV_ENOBUFS); - ASSERT(buf->base == NULL); - ASSERT(buf->len == 0); - - uv_close((uv_handle_t*) &incoming, close_cb); - uv_close((uv_handle_t*) &client, close_cb); - uv_close((uv_handle_t*) &server, close_cb); -} - -static void connect_cb(uv_connect_t* req, int status) { - int r; - uv_buf_t buf; - - ASSERT(status == 0); - connect_cb_called++; - - buf = uv_buf_init(hello, sizeof(hello)); - r = uv_write(&write_req, 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)); - ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, - conn_alloc_cb, - conn_read_cb)); - - 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_alloc_cb_fail) { - 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(connection_cb_called == 1); - ASSERT(close_cb_called == 3); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-tcp-bind-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind-error.c deleted file mode 100644 index 10ed68e1..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-bind-error.c +++ /dev/null @@ -1,216 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c deleted file mode 100644 index b762bcb3..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c +++ /dev/null @@ -1,176 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-close-accept.c b/3rd/libuv-1.19.2/test/test-tcp-close-accept.c deleted file mode 100644 index e4878398..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-close-accept.c +++ /dev/null @@ -1,194 +0,0 @@ -/* 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 -#include - -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 unsigned int pending_incoming; - -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); - - /* - * Time to finish the test: close both the check and pending incoming - * connections - */ - uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], 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; - - pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; - ASSERT(pending_incoming < got_connections); - ASSERT(0 == uv_read_stop(stream)); - ASSERT(1 == nread); - - loop = stream->loop; - read_cb_called++; - - /* Close all active incomings, except current one */ - for (i = 0; i < got_connections; i++) { - if (i != pending_incoming) - uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); - } - - /* Close server, so no one will connect to it */ - uv_close((uv_handle_t*) &tcp_server, 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)); -} - -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/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c b/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c deleted file mode 100644 index 8d0b8270..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c +++ /dev/null @@ -1,97 +0,0 @@ -/* 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 int netunreach_errors; - - -static void close_cb(uv_handle_t* handle) { - close_cb_called++; -} - - -static void connect_cb(uv_connect_t* req, int status) { - /* The expected error is UV_ECANCELED but the test tries to connect to what - * is basically an arbitrary address in the expectation that no network path - * exists, so UV_ENETUNREACH is an equally plausible outcome. - */ - ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH); - uv_timer_stop(&timer2_handle); - connect_cb_called++; - if (status == UV_ENETUNREACH) - netunreach_errors++; -} - - -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, 1, 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(); - - if (netunreach_errors > 0) - RETURN_SKIP("Network unreachable."); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-tcp-close.c b/3rd/libuv-1.19.2/test/test-tcp-close.c deleted file mode 100644 index e65885aa..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-close.c +++ /dev/null @@ -1,136 +0,0 @@ -/* 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 -#include /* 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/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c deleted file mode 100644 index 3f2e3572..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c +++ /dev/null @@ -1,98 +0,0 @@ -/* 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 -#include -#include - -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/3rd/libuv-1.19.2/test/test-tcp-connect-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error.c deleted file mode 100644 index eab1eeb2..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-connect-error.c +++ /dev/null @@ -1,73 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c b/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c deleted file mode 100644 index 081424b8..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c +++ /dev/null @@ -1,91 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c deleted file mode 100644 index 91ac0a3a..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c +++ /dev/null @@ -1,71 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c deleted file mode 100644 index b87e7324..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright (c) 2015 Saúl Ibarra Corretgé . - * 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 - -#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; - - if (!can_ipv6()) - RETURN_SKIP("IPv6 not supported"); - - 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); -#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) - 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/3rd/libuv-1.19.2/test/test-tcp-flags.c b/3rd/libuv-1.19.2/test/test-tcp-flags.c deleted file mode 100644 index 68afb39f..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-flags.c +++ /dev/null @@ -1,52 +0,0 @@ -/* 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 -#include - - -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/3rd/libuv-1.19.2/test/test-tcp-oob.c b/3rd/libuv-1.19.2/test/test-tcp-oob.c deleted file mode 100644 index 4f1397a8..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-oob.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 -#include -#include - -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) { -#ifdef __MVS__ - char lbuf[12]; -#endif - uv_os_fd_t fd; - - ASSERT(nread > 0); - ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); - ASSERT(0 == uv_idle_start(&idle, idle_cb)); - -#ifdef __MVS__ - /* Need to flush out the OOB data. Otherwise, this callback will get - * triggered on every poll with nread = 0. - */ - ASSERT(-1 != recv(fd, lbuf, sizeof(lbuf), MSG_OOB)); -#endif -} - - -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/3rd/libuv-1.19.2/test/test-tcp-open.c b/3rd/libuv-1.19.2/test/test-tcp-open.c deleted file mode 100644 index cb74c50e..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-open.c +++ /dev/null @@ -1,277 +0,0 @@ -/* 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 -#include -#include - -#ifndef _WIN32 -# include -#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; -} - - -TEST_IMPL(tcp_open_bound) { - struct sockaddr_in addr; - uv_tcp_t server; - uv_os_sock_t sock; - - startup(); - sock = create_tcp_socket(); - - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); - - ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); - - ASSERT(0 == uv_tcp_open(&server, sock)); - - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -TEST_IMPL(tcp_open_connected) { - struct sockaddr_in addr; - uv_tcp_t client; - uv_os_sock_t sock; - uv_buf_t buf = uv_buf_init("PING", 4); - - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - - startup(); - sock = create_tcp_socket(); - - ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); - - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); - - ASSERT(0 == uv_tcp_open(&client, sock)); - - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); - - ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); - - ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); - - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - ASSERT(shutdown_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-tcp-read-stop.c b/3rd/libuv-1.19.2/test/test-tcp-read-stop.c deleted file mode 100644 index 488e8fb4..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-read-stop.c +++ /dev/null @@ -1,76 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c deleted file mode 100644 index 463b4b0d..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c +++ /dev/null @@ -1,138 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-tcp-try-write.c b/3rd/libuv-1.19.2/test/test-tcp-try-write.c deleted file mode 100644 index 97a1d6e3..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-try-write.c +++ /dev/null @@ -1,135 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c b/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c deleted file mode 100644 index c7b98145..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c +++ /dev/null @@ -1,117 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c b/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c deleted file mode 100644 index aa03228f..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c +++ /dev/null @@ -1,68 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-tcp-write-fail.c b/3rd/libuv-1.19.2/test/test-tcp-write-fail.c deleted file mode 100644 index 5256a9f4..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-write-fail.c +++ /dev/null @@ -1,115 +0,0 @@ -/* 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 -#include -#ifndef _WIN32 -# include -#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/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c b/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c deleted file mode 100644 index 5119be6d..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c +++ /dev/null @@ -1,139 +0,0 @@ -/* 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 -#include -#include - -#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++; -} - -static 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); -} - -static 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)); - - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb, 1, 0)); - - 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; - int buffer_size = 16 * 1024; - - 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_send_buffer_size((uv_handle_t*) &client, &buffer_size)); - - 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/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c b/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c deleted file mode 100644 index 2fa2ae72..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 -#include -#include - -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/3rd/libuv-1.19.2/test/test-tcp-writealot.c b/3rd/libuv-1.19.2/test/test-tcp-writealot.c deleted file mode 100644 index 7206fdc2..00000000 --- a/3rd/libuv-1.19.2/test/test-tcp-writealot.c +++ /dev/null @@ -1,180 +0,0 @@ -/* 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 -#include - - -#define WRITES 3 -#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ -#define CHUNKS_PER_WRITE 2048 -#else -#define CHUNKS_PER_WRITE 4096 -#endif -#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/3rd/libuv-1.19.2/test/test-thread-equal.c b/3rd/libuv-1.19.2/test/test-thread-equal.c deleted file mode 100644 index 27c07ee2..00000000 --- a/3rd/libuv-1.19.2/test/test-thread-equal.c +++ /dev/null @@ -1,45 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-thread.c b/3rd/libuv-1.19.2/test/test-thread.c deleted file mode 100644 index 955c9f2f..00000000 --- a/3rd/libuv-1.19.2/test/test-thread.c +++ /dev/null @@ -1,232 +0,0 @@ -/* 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 -#include -#include /* 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; - 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 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[4]; - struct fs_req fs_reqs[4]; - uv_loop_t loop; - size_t i; - struct test_thread* thread = arg; - - ASSERT(0 == uv_loop_init(&loop)); - - for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { - struct getaddrinfo_req* req = getaddrinfo_reqs + i; - req->counter = 4; - req->loop = &loop; - getaddrinfo_do(req); - } - - for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { - struct fs_req* req = fs_reqs + i; - req->counter = 4; - req->loop = &loop; - fs_do(req); - } - - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&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 == 1); - } - - 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; -} - - -static void thread_check_stack(void* arg) { -#if defined(__APPLE__) - /* 512 kB is the default stack size of threads other than the main thread - * on MacOS. */ - ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); -#elif defined(__linux__) && defined(__GLIBC__) - struct rlimit lim; - size_t stack_size; - pthread_attr_t attr; - ASSERT(0 == getrlimit(RLIMIT_STACK, &lim)); - if (lim.rlim_cur == RLIM_INFINITY) - lim.rlim_cur = 2 << 20; /* glibc default. */ - ASSERT(0 == pthread_getattr_np(pthread_self(), &attr)); - ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size)); - ASSERT(stack_size >= lim.rlim_cur); -#endif -} - - -TEST_IMPL(thread_stack_size) { - uv_thread_t thread; - ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); - ASSERT(0 == uv_thread_join(&thread)); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-threadpool-cancel.c b/3rd/libuv-1.19.2/test/test-threadpool-cancel.c deleted file mode 100644 index dd13d8ae..00000000 --- a/3rd/libuv-1.19.2/test/test-threadpool-cancel.c +++ /dev/null @@ -1,308 +0,0 @@ -/* 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 unsigned fs_cb_called; -static unsigned done_cb_called; -static unsigned done2_cb_called; -static unsigned timer_cb_called; -static uv_work_t pause_reqs[4]; -static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)]; - - -static void work_cb(uv_work_t* req) { - uv_sem_wait(pause_sems + (req - pause_reqs)); -} - - -static void done_cb(uv_work_t* req, int status) { - uv_sem_destroy(pause_sems + (req - pause_reqs)); -} - - -static void saturate_threadpool(void) { - uv_loop_t* loop; - char buf[64]; - size_t i; - - snprintf(buf, - sizeof(buf), - "UV_THREADPOOL_SIZE=%lu", - (unsigned long)ARRAY_SIZE(pause_reqs)); - putenv(buf); - - loop = uv_default_loop(); - for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) { - ASSERT(0 == uv_sem_init(pause_sems + i, 0)); - ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); - } -} - - -static void unblock_threadpool(void) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) - uv_sem_post(pause_sems + i); -} - - -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_done_cb(uv_work_t* req, int status) { - ASSERT(status == UV_ECANCELED); - done_cb_called++; -} - - -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); - - 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); - - 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); - - 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); - - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - -TEST_IMPL(threadpool_cancel_single) { - uv_loop_t* loop; - uv_work_t req; - - saturate_threadpool(); - loop = uv_default_loop(); - ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); - ASSERT(0 == uv_cancel((uv_req_t*) &req)); - ASSERT(0 == done_cb_called); - unblock_threadpool(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == done_cb_called); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-threadpool.c b/3rd/libuv-1.19.2/test/test-threadpool.c deleted file mode 100644 index e3d17d75..00000000 --- a/3rd/libuv-1.19.2/test/test-threadpool.c +++ /dev/null @@ -1,76 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-timer-again.c b/3rd/libuv-1.19.2/test/test-timer-again.c deleted file mode 100644 index f93c509b..00000000 --- a/3rd/libuv-1.19.2/test/test-timer-again.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-timer-from-check.c b/3rd/libuv-1.19.2/test/test-timer-from-check.c deleted file mode 100644 index a18c7e1f..00000000 --- a/3rd/libuv-1.19.2/test/test-timer-from-check.c +++ /dev/null @@ -1,80 +0,0 @@ -/* 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/3rd/libuv-1.19.2/test/test-timer.c b/3rd/libuv-1.19.2/test/test-timer.c deleted file mode 100644 index 080a7300..00000000 --- a/3rd/libuv-1.19.2/test/test-timer.c +++ /dev/null @@ -1,330 +0,0 @@ -/* 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; -} - - -static uint64_t timer_early_check_expected_time; - - -static void timer_early_check_cb(uv_timer_t* handle) { - uint64_t hrtime = uv_hrtime() / 1000000; - ASSERT(hrtime >= timer_early_check_expected_time); -} - - -TEST_IMPL(timer_early_check) { - uv_timer_t timer_handle; - const uint64_t timeout_ms = 10; - - timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; - - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - - uv_close((uv_handle_t*) &timer_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-tmpdir.c b/3rd/libuv-1.19.2/test/test-tmpdir.c deleted file mode 100644 index 29e8055f..00000000 --- a/3rd/libuv-1.19.2/test/test-tmpdir.c +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright 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. - */ - -#include "uv.h" -#include "task.h" -#include - -#define PATHMAX 1024 -#define SMALLPATH 1 - -TEST_IMPL(tmpdir) { - char tmpdir[PATHMAX]; - size_t len; - char last; - int r; - - /* Test the normal case */ - len = sizeof tmpdir; - tmpdir[0] = '\0'; - - ASSERT(strlen(tmpdir) == 0); - r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == 0); - ASSERT(strlen(tmpdir) == len); - ASSERT(len > 0); - ASSERT(tmpdir[len] == '\0'); - - if (len > 1) { - last = tmpdir[len - 1]; -#ifdef _WIN32 - ASSERT(last != '\\'); -#else - ASSERT(last != '/'); -#endif - } - - /* Test the case where the buffer is too small */ - len = SMALLPATH; - r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == UV_ENOBUFS); - ASSERT(len > SMALLPATH); - - /* Test invalid inputs */ - r = uv_os_tmpdir(NULL, &len); - ASSERT(r == UV_EINVAL); - r = uv_os_tmpdir(tmpdir, NULL); - ASSERT(r == UV_EINVAL); - len = 0; - r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == UV_EINVAL); - - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-tty.c b/3rd/libuv-1.19.2/test/test-tty.c deleted file mode 100644 index e761822f..00000000 --- a/3rd/libuv-1.19.2/test/test-tty.c +++ /dev/null @@ -1,390 +0,0 @@ -/* 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 -# include -#else /* Unix */ -# include -# include -# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) -# include -# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) -# include -# elif defined(__FreeBSD__) || defined(__DragonFly__) -# include -# endif -#endif - -#include -#include - - -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; -} - - -#ifdef _WIN32 -static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { - buf->base = malloc(size); - buf->len = size; -} - -static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { - if (nread > 0) { - ASSERT(nread == 1); - ASSERT(buf->base[0] == ' '); - uv_close((uv_handle_t*) tty_in, NULL); - } else { - ASSERT(nread == 0); - } -} - -TEST_IMPL(tty_raw) { - int r; - int ttyin_fd; - uv_tty_t tty_in; - uv_loop_t* loop = uv_default_loop(); - HANDLE handle; - INPUT_RECORD record; - DWORD written; - - /* Make sure we have an FD that refers to a tty */ - 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); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); - - r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); - - r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); - ASSERT(r == 0); - - /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ - Sleep(100); - - /* Turn on raw mode. */ - r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); - - /* Write ' ' that should be read in raw mode */ - record.EventType = KEY_EVENT; - record.Event.KeyEvent.bKeyDown = TRUE; - record.Event.KeyEvent.wRepeatCount = 1; - record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; - record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); - record.Event.KeyEvent.uChar.UnicodeChar = L' '; - record.Event.KeyEvent.dwControlKeyState = 0; - WriteConsoleInputW(handle, &record, 1, &written); - - uv_run(loop, UV_RUN_DEFAULT); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(tty_empty_write) { - int r; - int ttyout_fd; - uv_tty_t tty_out; - char dummy[1]; - uv_buf_t bufs[1]; - uv_loop_t* loop; - - /* Make sure we have an FD that refers to a tty */ - HANDLE handle; - - loop = uv_default_loop(); - - 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); - - ASSERT(ttyout_fd >= 0); - - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); - - bufs[0].len = 0; - bufs[0].base = &dummy[0]; - - r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); - ASSERT(r == 0); - - uv_close((uv_handle_t*) &tty_out, NULL); - - uv_run(loop, UV_RUN_DEFAULT); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -TEST_IMPL(tty_large_write) { - int r; - int ttyout_fd; - uv_tty_t tty_out; - char dummy[10000]; - uv_buf_t bufs[1]; - uv_loop_t* loop; - - /* Make sure we have an FD that refers to a tty */ - HANDLE handle; - - loop = uv_default_loop(); - - 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); - - ASSERT(ttyout_fd >= 0); - - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); - - memset(dummy, '.', sizeof(dummy) - 1); - dummy[sizeof(dummy) - 1] = '\n'; - - bufs[0] = uv_buf_init(dummy, sizeof(dummy)); - - r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); - ASSERT(r == 10000); - - uv_close((uv_handle_t*) &tty_out, NULL); - - uv_run(loop, UV_RUN_DEFAULT); - - MAKE_VALGRIND_HAPPY(); - return 0; -} -#endif - - -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; -} - -TEST_IMPL(tty_pty) { -#if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - (defined(__linux__) && !defined(__ANDROID__)) || \ - defined(__NetBSD__) || \ - defined(__OpenBSD__) - int master_fd, slave_fd, r; - struct winsize w; - uv_loop_t loop; - uv_tty_t master_tty, slave_tty; - - ASSERT(0 == uv_loop_init(&loop)); - - r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); - if (r != 0) - RETURN_SKIP("No pty available, skipping."); - - ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); - ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); - /* Check if the file descriptor was reopened. If it is, - * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. - */ - ASSERT(0 == (slave_tty.flags & 0x80)); - /* The master_fd of a pty should never be reopened. - */ - ASSERT(master_tty.flags & 0x80); - ASSERT(0 == close(slave_fd)); - uv_close((uv_handle_t*) &slave_tty, NULL); - ASSERT(0 == close(master_fd)); - uv_close((uv_handle_t*) &master_tty, NULL); - - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - - MAKE_VALGRIND_HAPPY(); -#endif - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c deleted file mode 100644 index 05b871e9..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright libuv project 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 -#include -#include - -#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 sv_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 cl_alloc_cb(uv_handle_t* handle, - size_t suggested_size, - uv_buf_t* buf) { - /* Do nothing, recv_cb should be called with UV_ENOBUFS. */ -} - - -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); - ASSERT(nread == UV_ENOBUFS); - - 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, cl_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)); - - 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_alloc_cb_fail) { - 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, sv_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("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); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-udp-bind.c b/3rd/libuv-1.19.2/test/test-udp-bind.c deleted file mode 100644 index a1e080ee..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-bind.c +++ /dev/null @@ -1,93 +0,0 @@ -/* 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 -#include -#include - - -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/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c deleted file mode 100644 index f7e46abc..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright (c) 2015 Saúl Ibarra Corretgé . - * 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 - -#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; - - if (!can_ipv6()) - RETURN_SKIP("IPv6 not supported"); - - 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); -#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) - 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/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c b/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c deleted file mode 100644 index bd44c425..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c +++ /dev/null @@ -1,91 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/test-udp-ipv6.c b/3rd/libuv-1.19.2/test/test-udp-ipv6.c deleted file mode 100644 index 00007918..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-ipv6.c +++ /dev/null @@ -1,198 +0,0 @@ -/* 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 -#include -#include - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) -#include -#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; - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) -static int can_ipv6_ipv4_dual(void) { - 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 defined(__CYGWIN__) || defined(__MSYS__) - /* FIXME: Does Cygwin support this? */ - RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); -#endif - - if (!can_ipv6()) - RETURN_SKIP("IPv6 not supported"); - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) - 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c deleted file mode 100644 index 0b3c0e62..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c +++ /dev/null @@ -1,99 +0,0 @@ -/* 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 -#include -#include - -#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 || status == UV_EPERM); - 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c deleted file mode 100644 index 40b05536..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c +++ /dev/null @@ -1,103 +0,0 @@ -/* 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 -#include -#include - -#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__) || defined(__FreeBSD_kernel__) - 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/3rd/libuv-1.19.2/test/test-udp-multicast-join.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join.c deleted file mode 100644 index 6110a8d9..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-multicast-join.c +++ /dev/null @@ -1,150 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c deleted file mode 100644 index 8814b5ad..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c +++ /dev/null @@ -1,165 +0,0 @@ -/* 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 -#include -#include - - -#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) || \ - defined(__MVS__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) - 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/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c b/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c deleted file mode 100644 index e92608be..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 -#include -#include - -#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 || status == UV_EPERM); - 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/3rd/libuv-1.19.2/test/test-udp-open.c b/3rd/libuv-1.19.2/test/test-udp-open.c deleted file mode 100644 index 4d77f45d..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-open.c +++ /dev/null @@ -1,204 +0,0 @@ -/* 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 -#include -#include - -#ifndef _WIN32 -# include -#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/3rd/libuv-1.19.2/test/test-udp-options.c b/3rd/libuv-1.19.2/test/test-udp-options.c deleted file mode 100644 index 8f913675..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-options.c +++ /dev/null @@ -1,137 +0,0 @@ -/* 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 -#include -#include - - -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); -#if defined(__MVS__) - if (addr->sa_family == AF_INET6) - ASSERT(r == 0); - else - ASSERT(r == UV_ENOTSUP); -#else - ASSERT(r == 0); -#endif - } - - 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)); -#if defined(__MVS__) - ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); -#else - ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); -#endif - 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/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c b/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c deleted file mode 100644 index 633a1672..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c +++ /dev/null @@ -1,214 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c b/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c deleted file mode 100644 index bf4dfebf..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c +++ /dev/null @@ -1,99 +0,0 @@ -/* 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 -#include -#include - -#define CHECK_OBJECT(handle, type, parent) \ - ASSERT((type*)(handle) == &(parent)) - -static uv_udp_t client; -static uv_idle_t idle_handle; -static uv_udp_send_t send_req; -static uv_buf_t buf; -static struct sockaddr_in addr; -static char send_data[1024]; - -static int loop_hang_called; - -static void send_cb(uv_udp_send_t* req, int status); - - -static void idle_cb(uv_idle_t* handle) { - int r; - - ASSERT(send_req.handle == NULL); - CHECK_OBJECT(handle, uv_idle_t, idle_handle); - ASSERT(0 == uv_idle_stop(handle)); - - /* It probably would have stalled by now if it's going to stall at all. */ - if (++loop_hang_called > 1000) { - uv_close((uv_handle_t*) &client, NULL); - uv_close((uv_handle_t*) &idle_handle, NULL); - return; - } - - r = uv_udp_send(&send_req, - &client, - &buf, - 1, - (const struct sockaddr*) &addr, - send_cb); - ASSERT(r == 0); -} - - -static void send_cb(uv_udp_send_t* req, int status) { - ASSERT(req != NULL); - ASSERT(status == 0 || status == UV_ENETUNREACH); - CHECK_OBJECT(req->handle, uv_udp_t, client); - CHECK_OBJECT(req, uv_udp_send_t, send_req); - req->handle = NULL; - - ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); -} - - -TEST_IMPL(udp_send_hang_loop) { - ASSERT(0 == uv_idle_init(uv_default_loop(), &idle_handle)); - - /* 192.0.2.0/8 is "TEST-NET" and reserved for documentation. - * Good for us, though. Since we want to have something unreachable. - */ - ASSERT(0 == uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); - - ASSERT(0 == uv_udp_init(uv_default_loop(), &client)); - - buf = uv_buf_init(send_data, sizeof(send_data)); - - ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); - - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - ASSERT(loop_hang_called > 1000); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/3rd/libuv-1.19.2/test/test-udp-send-immediate.c b/3rd/libuv-1.19.2/test/test-udp-send-immediate.c deleted file mode 100644 index 215f7225..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-send-immediate.c +++ /dev/null @@ -1,149 +0,0 @@ -/* 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 -#include -#include - -#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); - ASSERT(r == 0); - - 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/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c b/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c deleted file mode 100644 index c6500320..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c +++ /dev/null @@ -1,150 +0,0 @@ -/* 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 -#include -#include - -#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/3rd/libuv-1.19.2/test/test-udp-try-send.c b/3rd/libuv-1.19.2/test/test-udp-try-send.c deleted file mode 100644 index a31d3822..00000000 --- a/3rd/libuv-1.19.2/test/test-udp-try-send.c +++ /dev/null @@ -1,121 +0,0 @@ -/* 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 -#include -#include - -#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; -} diff --git a/3rd/libuv-1.19.2/test/test-walk-handles.c b/3rd/libuv-1.19.2/test/test-walk-handles.c deleted file mode 100644 index 4b0ca6eb..00000000 --- a/3rd/libuv-1.19.2/test/test-walk-handles.c +++ /dev/null @@ -1,77 +0,0 @@ -/* 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 -#include - -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/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c b/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c deleted file mode 100644 index 29a82a5c..00000000 --- a/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c +++ /dev/null @@ -1,111 +0,0 @@ -/* 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 -#include - -/* NOTE: Number should be big enough to trigger this problem */ -#if defined(__CYGWIN__) || defined(__MSYS__) -/* Cygwin crashes or hangs in socket() with too many AF_INET sockets. */ -static uv_udp_t sockets[1250]; -#else -static uv_udp_t sockets[2500]; -#endif -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) { -#if defined(__MVS__) - RETURN_SKIP("zOS does not allow address or port reuse when using UDP sockets"); -#endif - 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/3rd/libuv-1.19.2/test/test.gyp b/3rd/libuv-1.19.2/test/test.gyp deleted file mode 100644 index 480e5a26..00000000 --- a/3rd/libuv-1.19.2/test/test.gyp +++ /dev/null @@ -1,279 +0,0 @@ -{ - 'targets': [ - { - 'target_name': 'run-tests', - 'type': 'executable', - 'dependencies': [ '../uv.gyp:libuv' ], - 'sources': [ - 'blackhole-server.c', - 'echo-server.c', - 'run-tests.c', - 'runner.c', - 'runner.h', - 'test-get-loadavg.c', - 'task.h', - 'test-active.c', - 'test-async.c', - 'test-async-null-cb.c', - 'test-callback-stack.c', - 'test-callback-order.c', - 'test-close-fd.c', - 'test-close-order.c', - 'test-connect-unspecified.c', - 'test-connection-fail.c', - 'test-cwd-and-chdir.c', - 'test-default-loop-close.c', - 'test-delayed-accept.c', - 'test-eintr-handling.c', - 'test-error.c', - 'test-embed.c', - 'test-emfile.c', - 'test-env-vars.c', - 'test-fail-always.c', - 'test-fork.c', - 'test-fs.c', - 'test-fs-copyfile.c', - 'test-fs-event.c', - 'test-getters-setters.c', - 'test-get-currentexe.c', - 'test-get-memory.c', - 'test-get-passwd.c', - 'test-getaddrinfo.c', - 'test-gethostname.c', - 'test-getnameinfo.c', - 'test-getsockname.c', - 'test-handle-fileno.c', - 'test-homedir.c', - 'test-hrtime.c', - 'test-idle.c', - 'test-ip6-addr.c', - 'test-ipc.c', - 'test-ipc-send-recv.c', - 'test-list.h', - 'test-loop-handles.c', - 'test-loop-alive.c', - 'test-loop-close.c', - 'test-loop-stop.c', - 'test-loop-time.c', - 'test-loop-configure.c', - 'test-walk-handles.c', - 'test-watcher-cross-stop.c', - 'test-multiple-listen.c', - 'test-osx-select.c', - 'test-pass-always.c', - 'test-ping-pong.c', - 'test-pipe-bind-error.c', - 'test-pipe-connect-error.c', - 'test-pipe-connect-multiple.c', - 'test-pipe-connect-prepare.c', - 'test-pipe-getsockname.c', - 'test-pipe-pending-instances.c', - 'test-pipe-sendmsg.c', - 'test-pipe-server-close.c', - 'test-pipe-close-stdout-read-stdin.c', - 'test-pipe-set-non-blocking.c', - 'test-pipe-set-fchmod.c', - 'test-platform-output.c', - 'test-poll.c', - 'test-poll-close.c', - 'test-poll-close-doesnt-corrupt-stack.c', - 'test-poll-closesocket.c', - 'test-poll-oob.c', - 'test-process-title.c', - 'test-process-title-threadsafe.c', - 'test-queue-foreach-delete.c', - 'test-ref.c', - 'test-run-nowait.c', - 'test-run-once.c', - 'test-semaphore.c', - 'test-shutdown-close.c', - 'test-shutdown-eof.c', - 'test-shutdown-twice.c', - 'test-signal.c', - 'test-signal-multiple-loops.c', - 'test-socket-buffer-size.c', - 'test-spawn.c', - 'test-fs-poll.c', - 'test-stdio-over-pipes.c', - 'test-tcp-alloc-cb-fail.c', - 'test-tcp-bind-error.c', - 'test-tcp-bind6-error.c', - 'test-tcp-close.c', - 'test-tcp-close-accept.c', - 'test-tcp-close-while-connecting.c', - 'test-tcp-create-socket-early.c', - 'test-tcp-connect-error-after-write.c', - 'test-tcp-shutdown-after-write.c', - 'test-tcp-flags.c', - 'test-tcp-connect-error.c', - 'test-tcp-connect-timeout.c', - 'test-tcp-connect6-error.c', - 'test-tcp-open.c', - 'test-tcp-write-to-half-open-connection.c', - 'test-tcp-write-after-connect.c', - 'test-tcp-writealot.c', - 'test-tcp-write-fail.c', - 'test-tcp-try-write.c', - 'test-tcp-unexpected-read.c', - 'test-tcp-oob.c', - 'test-tcp-read-stop.c', - 'test-tcp-write-queue-order.c', - 'test-threadpool.c', - 'test-threadpool-cancel.c', - 'test-thread-equal.c', - 'test-tmpdir.c', - 'test-mutexes.c', - 'test-thread.c', - 'test-barrier.c', - 'test-condvar.c', - 'test-timer-again.c', - 'test-timer-from-check.c', - 'test-timer.c', - 'test-tty.c', - 'test-udp-alloc-cb-fail.c', - 'test-udp-bind.c', - 'test-udp-create-socket-early.c', - 'test-udp-dgram-too-big.c', - 'test-udp-ipv6.c', - 'test-udp-open.c', - 'test-udp-options.c', - 'test-udp-send-and-recv.c', - 'test-udp-send-hang-loop.c', - 'test-udp-send-immediate.c', - 'test-udp-send-unreachable.c', - 'test-udp-multicast-join.c', - 'test-udp-multicast-join6.c', - 'test-dlerror.c', - 'test-udp-multicast-ttl.c', - 'test-ip4-addr.c', - 'test-ip6-addr.c', - 'test-udp-multicast-interface.c', - 'test-udp-multicast-interface6.c', - 'test-udp-try-send.c', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'runner-win.c', - 'runner-win.h', - '../src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'sources': [ - 'runner-unix.c', - 'runner-unix.h', - ], - 'conditions': [ - [ 'OS != "zos"', { - 'defines': [ '_GNU_SOURCE' ], - 'cflags': [ '-Wno-long-long' ], - 'xcode_settings': { - 'WARNING_CFLAGS': [ '-Wno-long-long' ] - } - }], - ]}, - ], - [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { - 'link_settings': { - 'libraries': [ '-lutil' ], - }, - }], - [ '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', - ], - }], - [ 'OS == "zos"', { - 'cflags': [ '-qxplink' ], - 'ldflags': [ '-qxplink' ], - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, - - { - 'target_name': 'run-benchmarks', - 'type': 'executable', - 'dependencies': [ '../uv.gyp:libuv' ], - 'sources': [ - 'benchmark-async.c', - 'benchmark-async-pummel.c', - 'benchmark-fs-stat.c', - 'benchmark-getaddrinfo.c', - 'benchmark-list.h', - 'benchmark-loop-count.c', - 'benchmark-million-async.c', - 'benchmark-million-timers.c', - 'benchmark-multi-accept.c', - 'benchmark-ping-pongs.c', - 'benchmark-pound.c', - 'benchmark-pump.c', - 'benchmark-sizes.c', - 'benchmark-spawn.c', - 'benchmark-thread.c', - 'benchmark-tcp-write-batch.c', - 'benchmark-udp-pummel.c', - 'dns-server.c', - 'echo-server.c', - 'blackhole-server.c', - 'run-benchmarks.c', - 'runner.c', - 'runner.h', - 'task.h', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'runner-win.c', - 'runner-win.h', - '../src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], - 'sources': [ - 'runner-unix.c', - 'runner-unix.h', - ] - }], - [ 'OS == "zos"', { - 'cflags': [ '-qxplink' ], - 'ldflags': [ '-qxplink' ], - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, - ], -} diff --git a/3rd/libuv-1.19.2/tools/make_dist_html.py b/3rd/libuv-1.19.2/tools/make_dist_html.py deleted file mode 100644 index 7a19d3e1..00000000 --- a/3rd/libuv-1.19.2/tools/make_dist_html.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/python - -from __future__ import print_function - -import itertools -import os -import re -import subprocess - -HTML = r''' - - - - - - - - - {groups}
- - -''' - -GROUPS = r''' - - {groups[0]} - {groups[1]} - {groups[2]} - {groups[3]} - -''' - -GROUP = r''' - - - - - - - - {rows} -
versiontarballgpgwindows
-''' - -ROW = r''' - - -
{tag} - - - tarball - - {maybe_gpg} - {maybe_exe} - -''' - -GPG = r''' -gpg -''' - -# The binaries don't have a predictable name, link to the directory instead. -EXE = r''' -exe -''' - -def version(tag): - return map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups()) - -def major_minor(tag): - return version(tag)[:2] - -def row_for(tag): - maybe_gpg = '' - maybe_exe = '' - # We didn't start signing releases and producing Windows installers - # until v1.7.0. - if version(tag) >= version('v1.7.0'): - maybe_gpg = GPG.format(**locals()) - maybe_exe = EXE.format(**locals()) - return ROW.format(**locals()) - -def group_for(tags): - rows = ''.join(row_for(tag) for tag in tags) - return GROUP.format(rows=rows) - -# Partition in groups of |n|. -def groups_for(groups, n=4): - html = '' - groups = groups[:] + [''] * (n - 1) - while len(groups) >= n: - html += GROUPS.format(groups=groups) - groups = groups[n:] - return html - -if __name__ == '__main__': - os.chdir(os.path.dirname(__file__)) - tags = subprocess.check_output(['git', 'tag']) - tags = [tag for tag in tags.split('\n') if tag.startswith('v')] - tags.sort(key=version, reverse=True) - groups = [group_for(list(g)) for _, g in itertools.groupby(tags, major_minor)] - groups = groups_for(groups) - html = HTML.format(groups=groups).strip() - html = re.sub('>\\s+<', '><', html) - print(html) diff --git a/3rd/libuv-1.19.2/uv.gyp b/3rd/libuv-1.19.2/uv.gyp deleted file mode 100644 index a5046b87..00000000 --- a/3rd/libuv-1.19.2/uv.gyp +++ /dev/null @@ -1,355 +0,0 @@ -{ - 'variables': { - 'conditions': [ - ['OS=="win"', { - 'shared_unix_defines': [ - '_LARGEFILE_SOURCE', - '_FILE_OFFSET_BITS=64', - ], - }, { - 'shared_unix_defines': [ ], - }], - ['OS in "mac ios"', { - 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], - }, { - 'shared_mac_defines': [ ], - }], - ['OS=="zos"', { - 'shared_zos_defines': [ - '_UNIX03_THREADS', - '_UNIX03_SOURCE', - '_UNIX03_WITHDRAWN', - '_OPEN_SYS_IF_EXT', - '_OPEN_SYS_SOCK_IPV6', - '_OPEN_MSGQ_EXT', - '_XOPEN_SOURCE_EXTENDED', - '_ALL_SOURCE', - '_LARGE_TIME_API', - '_OPEN_SYS_FILE_EXT', - '_AE_BIMODAL', - 'PATH_MAX=255' - ], - }, { - 'shared_zos_defines': [ ], - }], - ], - }, - - 'targets': [ - { - 'target_name': 'libuv', - 'type': '<(uv_library)', - 'include_dirs': [ - 'include', - 'src/', - ], - 'defines': [ - '<@(shared_mac_defines)', - '<@(shared_unix_defines)', - '<@(shared_zos_defines)', - ], - 'direct_dependent_settings': { - 'defines': [ - '<@(shared_mac_defines)', - '<@(shared_unix_defines)', - '<@(shared_zos_defines)', - ], - 'include_dirs': [ 'include' ], - 'conditions': [ - ['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-data-getter-setters.c', - 'src/uv-common.c', - 'src/uv-common.h', - 'src/version.c' - ], - 'xcode_settings': { - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'WARNING_CFLAGS': [ - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], - }, - '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/detect-wakeup.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/snprintf.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', - ], - 'link_settings': { - 'libraries': [ - '-ladvapi32', - '-liphlpapi', - '-lpsapi', - '-lshell32', - '-luser32', - '-luserenv', - '-lws2_32' - ], - }, - }, { # Not Windows i.e. POSIX - '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=="zos" and uv_library=="shared_library"', { - 'ldflags': [ '-Wl,DLL' ], - }], - ['OS != "solaris" and OS != "android" and OS != "zos"', { - 'ldflags': [ '-pthread' ], - }], - ], - }, - 'conditions': [ - ['uv_library=="shared_library"', { - 'conditions': [ - ['OS=="zos"', { - 'cflags': [ '-qexportall' ], - }, { - 'cflags': [ '-fPIC' ], - }], - ], - }], - ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { - # 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 zos"', { - 'sources': [ 'src/unix/proctitle.c' ], - }], - [ 'OS != "zos"', { - 'cflags': [ - '-fvisibility=hidden', - '-g', - '--std=gnu89', - '-pedantic', - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - '-Wstrict-prototypes', - ], - }], - [ '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=="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', - 'src/unix/procfs-exepath.c', - 'src/unix/sysinfo-loadavg.c', - 'src/unix/sysinfo-memory.c', - ], - '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', - 'src/unix/procfs-exepath.c', - 'src/unix/sysinfo-loadavg.c', - 'src/unix/sysinfo-memory.c', - ], - 'link_settings': { - 'libraries': [ '-ldl' ], - }, - }], - [ 'OS=="solaris"', { - 'sources': [ - 'src/unix/no-proctitle.c', - 'src/unix/sunos.c', - ], - 'defines': [ - '__EXTENSIONS__', - '_XOPEN_SOURCE=500', - ], - 'link_settings': { - 'libraries': [ - '-lkstat', - '-lnsl', - '-lsendfile', - '-lsocket', - ], - }, - }], - [ 'OS=="aix"', { - 'variables': { - 'os_name': ' Date: Sat, 17 Mar 2018 04:41:16 +0800 Subject: [PATCH 04/11] add --- 3rd/make3rdcompile.sh | 50 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/3rd/make3rdcompile.sh b/3rd/make3rdcompile.sh index 43e029ae..87335c88 100644 --- a/3rd/make3rdcompile.sh +++ b/3rd/make3rdcompile.sh @@ -1,26 +1,24 @@ -######################################################################### -# File Name: make3rdcompile.sh -# Author: Thinking -# mail: program_code@sohu.com -# Created Time: Sun 07 Jan 2018 02:54:11 AM DST -######################################################################### - -buildtype="debug" - -function getlibuv() { - cd libuv - ./configure --enable-static --disable-shared --prefix=/opt/local/ - make -j - make install -} - -function 3rdcompile() { - getlibuv -} - - -echo "start " -3rdcompile -echo "end" - - +######################################################################### +# File Name: make3rdcompile.sh +# Author: Thinking +# mail: program_code@sohu.com +# Created Time: Sun 07 Jan 2018 02:54:11 AM DST +######################################################################### +function getlibuv(){ + + cd libuv + ./configure --enable-static --disable-shared --prefix=/opt/local/ + make -j + make install +} + +function 3rdcompile() { + getlibuv +} + + +echo "start " +3rdcompile +echo "end" + + -- Gitee From 2e044df3056173a95a449f87bbe36d56a9a1a32e Mon Sep 17 00:00:00 2001 From: thinking Date: Sat, 17 Mar 2018 04:43:06 +0800 Subject: [PATCH 05/11] add libuv --- 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md | 10 + 3rd/libuv-1.19.2/.gitignore | 79 + 3rd/libuv-1.19.2/.mailmap | 46 + 3rd/libuv-1.19.2/AUTHORS | 332 ++ 3rd/libuv-1.19.2/CONTRIBUTING.md | 169 + 3rd/libuv-1.19.2/ChangeLog | 3531 ++++++++++++ 3rd/libuv-1.19.2/LICENSE | 70 + 3rd/libuv-1.19.2/LICENSE-docs | 396 ++ 3rd/libuv-1.19.2/MAINTAINERS.md | 43 + 3rd/libuv-1.19.2/Makefile.am | 468 ++ 3rd/libuv-1.19.2/Makefile.mingw | 86 + 3rd/libuv-1.19.2/README.md | 332 ++ 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md | 73 + 3rd/libuv-1.19.2/android-configure | 23 + 3rd/libuv-1.19.2/appveyor.yml | 32 + 3rd/libuv-1.19.2/autogen.sh | 46 + 3rd/libuv-1.19.2/checksparse.sh | 253 + 3rd/libuv-1.19.2/common.gypi | 208 + 3rd/libuv-1.19.2/configure.ac | 72 + 3rd/libuv-1.19.2/docs/code/cgi/main.c | 81 + 3rd/libuv-1.19.2/docs/code/cgi/tick.c | 13 + 3rd/libuv-1.19.2/docs/code/detach/main.c | 31 + 3rd/libuv-1.19.2/docs/code/dns/main.c | 80 + 3rd/libuv-1.19.2/docs/code/helloworld/main.c | 15 + 3rd/libuv-1.19.2/docs/code/idle-basic/main.c | 24 + .../docs/code/idle-compute/main.c | 43 + 3rd/libuv-1.19.2/docs/code/interfaces/main.c | 33 + 3rd/libuv-1.19.2/docs/code/locks/main.c | 57 + .../docs/code/multi-echo-server/hammer.js | 20 + .../docs/code/multi-echo-server/main.c | 114 + .../docs/code/multi-echo-server/worker.c | 88 + 3rd/libuv-1.19.2/docs/code/onchange/main.c | 44 + .../docs/code/pipe-echo-server/main.c | 94 + 3rd/libuv-1.19.2/docs/code/plugin/hello.c | 5 + 3rd/libuv-1.19.2/docs/code/plugin/main.c | 39 + 3rd/libuv-1.19.2/docs/code/plugin/plugin.h | 7 + .../docs/code/proc-streams/main.c | 49 + .../docs/code/proc-streams/test.c | 8 + 3rd/libuv-1.19.2/docs/code/progress/main.c | 47 + .../docs/code/queue-cancel/main.c | 59 + 3rd/libuv-1.19.2/docs/code/queue-work/main.c | 44 + 3rd/libuv-1.19.2/docs/code/ref-timer/main.c | 29 + 3rd/libuv-1.19.2/docs/code/signal/main.c | 66 + 3rd/libuv-1.19.2/docs/code/spawn/main.c | 36 + .../docs/code/tcp-echo-server/main.c | 87 + .../docs/code/thread-create/main.c | 36 + 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c | 48 + 3rd/libuv-1.19.2/docs/code/tty/main.c | 29 + 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c | 127 + 3rd/libuv-1.19.2/docs/code/uvcat/main.c | 63 + 3rd/libuv-1.19.2/docs/code/uvstop/main.c | 33 + 3rd/libuv-1.19.2/docs/code/uvtee/main.c | 80 + 3rd/libuv-1.19.2/docs/code/uvwget/main.c | 166 + 3rd/libuv-1.19.2/docs/make.bat | 243 + 3rd/libuv-1.19.2/docs/src/api.rst | 35 + 3rd/libuv-1.19.2/docs/src/async.rst | 61 + 3rd/libuv-1.19.2/docs/src/check.rst | 46 + 3rd/libuv-1.19.2/docs/src/conf.py | 348 ++ 3rd/libuv-1.19.2/docs/src/design.rst | 138 + 3rd/libuv-1.19.2/docs/src/dll.rst | 44 + 3rd/libuv-1.19.2/docs/src/dns.rst | 108 + 3rd/libuv-1.19.2/docs/src/errors.rst | 344 ++ 3rd/libuv-1.19.2/docs/src/fs.rst | 538 ++ 3rd/libuv-1.19.2/docs/src/fs_event.rst | 132 + 3rd/libuv-1.19.2/docs/src/fs_poll.rst | 77 + 3rd/libuv-1.19.2/docs/src/guide.rst | 22 + 3rd/libuv-1.19.2/docs/src/guide/about.rst | 22 + 3rd/libuv-1.19.2/docs/src/guide/basics.rst | 188 + .../docs/src/guide/eventloops.rst | 48 + .../docs/src/guide/filesystem.rst | 287 + .../docs/src/guide/introduction.rst | 75 + .../docs/src/guide/networking.rst | 249 + 3rd/libuv-1.19.2/docs/src/guide/processes.rst | 389 ++ 3rd/libuv-1.19.2/docs/src/guide/threads.rst | 381 ++ 3rd/libuv-1.19.2/docs/src/guide/utilities.rst | 433 ++ 3rd/libuv-1.19.2/docs/src/handle.rst | 264 + 3rd/libuv-1.19.2/docs/src/idle.rst | 54 + 3rd/libuv-1.19.2/docs/src/index.rst | 62 + 3rd/libuv-1.19.2/docs/src/loop.rst | 236 + .../docs/src/migration_010_100.rst | 244 + 3rd/libuv-1.19.2/docs/src/misc.rst | 519 ++ 3rd/libuv-1.19.2/docs/src/pipe.rst | 113 + 3rd/libuv-1.19.2/docs/src/poll.rst | 121 + 3rd/libuv-1.19.2/docs/src/prepare.rst | 46 + 3rd/libuv-1.19.2/docs/src/process.rst | 231 + 3rd/libuv-1.19.2/docs/src/request.rst | 109 + 3rd/libuv-1.19.2/docs/src/signal.rst | 78 + .../docs/src/sphinx-plugins/manpage.py | 46 + .../docs/src/static/architecture.png | Bin 0 -> 206767 bytes .../src/static/diagrams.key/Data/st0-311.jpg | Bin 0 -> 19328 bytes .../src/static/diagrams.key/Data/st1-475.jpg | Bin 0 -> 12655 bytes .../docs/src/static/diagrams.key/Index.zip | Bin 0 -> 71160 bytes .../Metadata/BuildVersionHistory.plist | 8 + .../diagrams.key/Metadata/DocumentIdentifier | 1 + .../diagrams.key/Metadata/Properties.plist | Bin 0 -> 340 bytes .../src/static/diagrams.key/preview-micro.jpg | Bin 0 -> 1425 bytes .../src/static/diagrams.key/preview-web.jpg | Bin 0 -> 8106 bytes .../docs/src/static/diagrams.key/preview.jpg | Bin 0 -> 107456 bytes 3rd/libuv-1.19.2/docs/src/static/favicon.ico | Bin 0 -> 15086 bytes 3rd/libuv-1.19.2/docs/src/static/logo.png | Bin 0 -> 33545 bytes .../docs/src/static/loop_iteration.png | Bin 0 -> 80528 bytes 3rd/libuv-1.19.2/docs/src/stream.rst | 237 + 3rd/libuv-1.19.2/docs/src/tcp.rst | 115 + 3rd/libuv-1.19.2/docs/src/threading.rst | 168 + 3rd/libuv-1.19.2/docs/src/threadpool.rst | 67 + 3rd/libuv-1.19.2/docs/src/timer.rst | 81 + 3rd/libuv-1.19.2/docs/src/tty.rst | 101 + 3rd/libuv-1.19.2/docs/src/udp.rst | 314 ++ 3rd/libuv-1.19.2/docs/src/upgrading.rst | 11 + 3rd/libuv-1.19.2/docs/src/version.rst | 60 + 3rd/libuv-1.19.2/gyp_uv.py | 73 + 3rd/libuv-1.19.2/img/banner.png | Bin 0 -> 44102 bytes 3rd/libuv-1.19.2/img/logos.svg | 152 + 3rd/libuv-1.19.2/include/android-ifaddrs.h | 54 + 3rd/libuv-1.19.2/include/pthread-barrier.h | 69 + 3rd/libuv-1.19.2/include/stdint-msvc2008.h | 247 + 3rd/libuv-1.19.2/include/tree.h | 768 +++ 3rd/libuv-1.19.2/include/uv-aix.h | 32 + 3rd/libuv-1.19.2/include/uv-bsd.h | 34 + 3rd/libuv-1.19.2/include/uv-darwin.h | 61 + 3rd/libuv-1.19.2/include/uv-errno.h | 437 ++ 3rd/libuv-1.19.2/include/uv-linux.h | 34 + 3rd/libuv-1.19.2/include/uv-os390.h | 33 + 3rd/libuv-1.19.2/include/uv-posix.h | 31 + 3rd/libuv-1.19.2/include/uv-sunos.h | 44 + 3rd/libuv-1.19.2/include/uv-threadpool.h | 37 + 3rd/libuv-1.19.2/include/uv-unix.h | 464 ++ 3rd/libuv-1.19.2/include/uv-version.h | 43 + 3rd/libuv-1.19.2/include/uv-win.h | 676 +++ 3rd/libuv-1.19.2/include/uv.h | 1567 ++++++ 3rd/libuv-1.19.2/libuv.pc.in | 12 + 3rd/libuv-1.19.2/m4/.gitignore | 4 + 3rd/libuv-1.19.2/m4/as_case.m4 | 21 + 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 | 319 ++ 3rd/libuv-1.19.2/samples/.gitignore | 22 + .../samples/socks5-proxy/.gitignore | 21 + 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE | 53 + .../samples/socks5-proxy/build.gyp | 46 + .../samples/socks5-proxy/client.c | 736 +++ 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h | 139 + .../samples/socks5-proxy/getopt.c | 131 + 3rd/libuv-1.19.2/samples/socks5-proxy/main.c | 99 + 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c | 271 + 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h | 94 + .../samples/socks5-proxy/server.c | 241 + 3rd/libuv-1.19.2/samples/socks5-proxy/util.c | 72 + 3rd/libuv-1.19.2/src/fs-poll.c | 256 + 3rd/libuv-1.19.2/src/heap-inl.h | 245 + 3rd/libuv-1.19.2/src/inet.c | 309 ++ 3rd/libuv-1.19.2/src/queue.h | 108 + 3rd/libuv-1.19.2/src/threadpool.c | 318 ++ 3rd/libuv-1.19.2/src/unix/aix-common.c | 292 + 3rd/libuv-1.19.2/src/unix/aix.c | 1041 ++++ 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c | 710 +++ 3rd/libuv-1.19.2/src/unix/async.c | 269 + 3rd/libuv-1.19.2/src/unix/atomic-ops.h | 100 + 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c | 152 + 3rd/libuv-1.19.2/src/unix/core.c | 1355 +++++ 3rd/libuv-1.19.2/src/unix/cygwin.c | 54 + 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c | 209 + 3rd/libuv-1.19.2/src/unix/darwin.c | 231 + 3rd/libuv-1.19.2/src/unix/dl.c | 80 + 3rd/libuv-1.19.2/src/unix/freebsd.c | 375 ++ 3rd/libuv-1.19.2/src/unix/fs.c | 1513 ++++++ 3rd/libuv-1.19.2/src/unix/fsevents.c | 919 ++++ 3rd/libuv-1.19.2/src/unix/getaddrinfo.c | 232 + 3rd/libuv-1.19.2/src/unix/getnameinfo.c | 120 + 3rd/libuv-1.19.2/src/unix/ibmi.c | 112 + 3rd/libuv-1.19.2/src/unix/internal.h | 340 ++ 3rd/libuv-1.19.2/src/unix/kqueue.c | 533 ++ 3rd/libuv-1.19.2/src/unix/linux-core.c | 951 ++++ 3rd/libuv-1.19.2/src/unix/linux-inotify.c | 352 ++ 3rd/libuv-1.19.2/src/unix/linux-syscalls.c | 471 ++ 3rd/libuv-1.19.2/src/unix/linux-syscalls.h | 151 + 3rd/libuv-1.19.2/src/unix/loop-watcher.c | 68 + 3rd/libuv-1.19.2/src/unix/loop.c | 193 + 3rd/libuv-1.19.2/src/unix/netbsd.c | 309 ++ 3rd/libuv-1.19.2/src/unix/no-fsevents.c | 42 + 3rd/libuv-1.19.2/src/unix/no-proctitle.c | 42 + 3rd/libuv-1.19.2/src/unix/openbsd.c | 313 ++ 3rd/libuv-1.19.2/src/unix/os390-syscalls.c | 499 ++ 3rd/libuv-1.19.2/src/unix/os390-syscalls.h | 72 + 3rd/libuv-1.19.2/src/unix/os390.c | 998 ++++ 3rd/libuv-1.19.2/src/unix/pipe.c | 357 ++ 3rd/libuv-1.19.2/src/unix/poll.c | 147 + 3rd/libuv-1.19.2/src/unix/posix-hrtime.c | 35 + 3rd/libuv-1.19.2/src/unix/posix-poll.c | 324 ++ 3rd/libuv-1.19.2/src/unix/process.c | 599 +++ 3rd/libuv-1.19.2/src/unix/procfs-exepath.c | 45 + 3rd/libuv-1.19.2/src/unix/proctitle.c | 132 + 3rd/libuv-1.19.2/src/unix/pthread-fixes.c | 56 + 3rd/libuv-1.19.2/src/unix/signal.c | 564 ++ 3rd/libuv-1.19.2/src/unix/spinlock.h | 53 + 3rd/libuv-1.19.2/src/unix/stream.c | 1696 ++++++ 3rd/libuv-1.19.2/src/unix/sunos.c | 821 +++ 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c | 36 + 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c | 42 + 3rd/libuv-1.19.2/src/unix/tcp.c | 444 ++ 3rd/libuv-1.19.2/src/unix/thread.c | 729 +++ 3rd/libuv-1.19.2/src/unix/timer.c | 172 + 3rd/libuv-1.19.2/src/unix/tty.c | 372 ++ 3rd/libuv-1.19.2/src/unix/udp.c | 902 ++++ 3rd/libuv-1.19.2/src/uv-common.c | 664 +++ 3rd/libuv-1.19.2/src/uv-common.h | 260 + 3rd/libuv-1.19.2/src/uv-data-getter-setters.c | 96 + 3rd/libuv-1.19.2/src/version.c | 45 + 3rd/libuv-1.19.2/src/win/async.c | 98 + 3rd/libuv-1.19.2/src/win/atomicops-inl.h | 57 + 3rd/libuv-1.19.2/src/win/core.c | 605 +++ 3rd/libuv-1.19.2/src/win/detect-wakeup.c | 35 + 3rd/libuv-1.19.2/src/win/dl.c | 133 + 3rd/libuv-1.19.2/src/win/error.c | 171 + 3rd/libuv-1.19.2/src/win/fs-event.c | 561 ++ 3rd/libuv-1.19.2/src/win/fs.c | 2426 +++++++++ 3rd/libuv-1.19.2/src/win/getaddrinfo.c | 453 ++ 3rd/libuv-1.19.2/src/win/getnameinfo.c | 149 + 3rd/libuv-1.19.2/src/win/handle-inl.h | 179 + 3rd/libuv-1.19.2/src/win/handle.c | 159 + 3rd/libuv-1.19.2/src/win/internal.h | 394 ++ 3rd/libuv-1.19.2/src/win/loop-watcher.c | 122 + 3rd/libuv-1.19.2/src/win/pipe.c | 2214 ++++++++ 3rd/libuv-1.19.2/src/win/poll.c | 644 +++ 3rd/libuv-1.19.2/src/win/process-stdio.c | 511 ++ 3rd/libuv-1.19.2/src/win/process.c | 1272 +++++ 3rd/libuv-1.19.2/src/win/req-inl.h | 221 + 3rd/libuv-1.19.2/src/win/req.c | 25 + 3rd/libuv-1.19.2/src/win/signal.c | 277 + 3rd/libuv-1.19.2/src/win/snprintf.c | 42 + 3rd/libuv-1.19.2/src/win/stream-inl.h | 54 + 3rd/libuv-1.19.2/src/win/stream.c | 248 + 3rd/libuv-1.19.2/src/win/tcp.c | 1525 ++++++ 3rd/libuv-1.19.2/src/win/thread.c | 703 +++ 3rd/libuv-1.19.2/src/win/timer.c | 195 + 3rd/libuv-1.19.2/src/win/tty.c | 2328 ++++++++ 3rd/libuv-1.19.2/src/win/udp.c | 965 ++++ 3rd/libuv-1.19.2/src/win/util.c | 1581 ++++++ 3rd/libuv-1.19.2/src/win/winapi.c | 169 + 3rd/libuv-1.19.2/src/win/winapi.h | 4778 +++++++++++++++++ 3rd/libuv-1.19.2/src/win/winsock.c | 591 ++ 3rd/libuv-1.19.2/src/win/winsock.h | 193 + .../test/benchmark-async-pummel.c | 119 + 3rd/libuv-1.19.2/test/benchmark-async.c | 141 + 3rd/libuv-1.19.2/test/benchmark-fs-stat.c | 136 + 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c | 92 + 3rd/libuv-1.19.2/test/benchmark-list.h | 163 + 3rd/libuv-1.19.2/test/benchmark-loop-count.c | 92 + .../test/benchmark-million-async.c | 112 + .../test/benchmark-million-timers.c | 86 + .../test/benchmark-multi-accept.c | 447 ++ 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c | 221 + 3rd/libuv-1.19.2/test/benchmark-pound.c | 351 ++ 3rd/libuv-1.19.2/test/benchmark-pump.c | 476 ++ 3rd/libuv-1.19.2/test/benchmark-sizes.c | 46 + 3rd/libuv-1.19.2/test/benchmark-spawn.c | 164 + .../test/benchmark-tcp-write-batch.c | 144 + 3rd/libuv-1.19.2/test/benchmark-thread.c | 64 + 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c | 243 + 3rd/libuv-1.19.2/test/blackhole-server.c | 121 + 3rd/libuv-1.19.2/test/dns-server.c | 340 ++ 3rd/libuv-1.19.2/test/echo-server.c | 378 ++ 3rd/libuv-1.19.2/test/fixtures/empty_file | 0 .../test/fixtures/load_error.node | 1 + 3rd/libuv-1.19.2/test/run-benchmarks.c | 65 + 3rd/libuv-1.19.2/test/run-tests.c | 204 + 3rd/libuv-1.19.2/test/runner-unix.c | 400 ++ 3rd/libuv-1.19.2/test/runner-unix.h | 36 + 3rd/libuv-1.19.2/test/runner-win.c | 351 ++ 3rd/libuv-1.19.2/test/runner-win.h | 39 + 3rd/libuv-1.19.2/test/runner.c | 434 ++ 3rd/libuv-1.19.2/test/runner.h | 177 + 3rd/libuv-1.19.2/test/task.h | 232 + 3rd/libuv-1.19.2/test/test-active.c | 84 + 3rd/libuv-1.19.2/test/test-async-null-cb.c | 64 + 3rd/libuv-1.19.2/test/test-async.c | 134 + 3rd/libuv-1.19.2/test/test-barrier.c | 106 + 3rd/libuv-1.19.2/test/test-callback-order.c | 77 + 3rd/libuv-1.19.2/test/test-callback-stack.c | 205 + 3rd/libuv-1.19.2/test/test-close-fd.c | 76 + 3rd/libuv-1.19.2/test/test-close-order.c | 80 + 3rd/libuv-1.19.2/test/test-condvar.c | 245 + .../test/test-connect-unspecified.c | 61 + 3rd/libuv-1.19.2/test/test-connection-fail.c | 151 + 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c | 51 + .../test/test-default-loop-close.c | 59 + 3rd/libuv-1.19.2/test/test-delayed-accept.c | 189 + 3rd/libuv-1.19.2/test/test-dlerror.c | 57 + 3rd/libuv-1.19.2/test/test-eintr-handling.c | 94 + 3rd/libuv-1.19.2/test/test-embed.c | 139 + 3rd/libuv-1.19.2/test/test-emfile.c | 117 + 3rd/libuv-1.19.2/test/test-env-vars.c | 90 + 3rd/libuv-1.19.2/test/test-error.c | 73 + 3rd/libuv-1.19.2/test/test-fail-always.c | 29 + 3rd/libuv-1.19.2/test/test-fork.c | 681 +++ 3rd/libuv-1.19.2/test/test-fs-copyfile.c | 173 + 3rd/libuv-1.19.2/test/test-fs-event.c | 1051 ++++ 3rd/libuv-1.19.2/test/test-fs-poll.c | 187 + 3rd/libuv-1.19.2/test/test-fs.c | 3174 +++++++++++ 3rd/libuv-1.19.2/test/test-get-currentexe.c | 86 + 3rd/libuv-1.19.2/test/test-get-loadavg.c | 35 + 3rd/libuv-1.19.2/test/test-get-memory.c | 38 + 3rd/libuv-1.19.2/test/test-get-passwd.c | 86 + 3rd/libuv-1.19.2/test/test-getaddrinfo.c | 191 + 3rd/libuv-1.19.2/test/test-gethostname.c | 62 + 3rd/libuv-1.19.2/test/test-getnameinfo.c | 101 + 3rd/libuv-1.19.2/test/test-getsockname.c | 361 ++ 3rd/libuv-1.19.2/test/test-getters-setters.c | 88 + 3rd/libuv-1.19.2/test/test-handle-fileno.c | 121 + 3rd/libuv-1.19.2/test/test-homedir.c | 72 + 3rd/libuv-1.19.2/test/test-hrtime.c | 54 + 3rd/libuv-1.19.2/test/test-idle.c | 99 + 3rd/libuv-1.19.2/test/test-ip4-addr.c | 46 + 3rd/libuv-1.19.2/test/test-ip6-addr.c | 162 + 3rd/libuv-1.19.2/test/test-ipc-send-recv.c | 428 ++ 3rd/libuv-1.19.2/test/test-ipc.c | 887 +++ 3rd/libuv-1.19.2/test/test-list.h | 905 ++++ 3rd/libuv-1.19.2/test/test-loop-alive.c | 67 + 3rd/libuv-1.19.2/test/test-loop-close.c | 75 + 3rd/libuv-1.19.2/test/test-loop-configure.c | 38 + 3rd/libuv-1.19.2/test/test-loop-handles.c | 337 ++ 3rd/libuv-1.19.2/test/test-loop-stop.c | 71 + 3rd/libuv-1.19.2/test/test-loop-time.c | 63 + 3rd/libuv-1.19.2/test/test-multiple-listen.c | 109 + 3rd/libuv-1.19.2/test/test-mutexes.c | 182 + 3rd/libuv-1.19.2/test/test-osx-select.c | 140 + 3rd/libuv-1.19.2/test/test-pass-always.c | 28 + 3rd/libuv-1.19.2/test/test-ping-pong.c | 274 + 3rd/libuv-1.19.2/test/test-pipe-bind-error.c | 139 + .../test/test-pipe-close-stdout-read-stdin.c | 107 + .../test/test-pipe-connect-error.c | 95 + .../test/test-pipe-connect-multiple.c | 107 + .../test/test-pipe-connect-prepare.c | 83 + 3rd/libuv-1.19.2/test/test-pipe-getsockname.c | 266 + .../test/test-pipe-pending-instances.c | 59 + 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c | 172 + .../test/test-pipe-server-close.c | 94 + 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c | 66 + .../test/test-pipe-set-non-blocking.c | 99 + 3rd/libuv-1.19.2/test/test-platform-output.c | 157 + .../test-poll-close-doesnt-corrupt-stack.c | 116 + 3rd/libuv-1.19.2/test/test-poll-close.c | 73 + 3rd/libuv-1.19.2/test/test-poll-closesocket.c | 93 + 3rd/libuv-1.19.2/test/test-poll-oob.c | 205 + 3rd/libuv-1.19.2/test/test-poll.c | 665 +++ .../test/test-process-title-threadsafe.c | 90 + 3rd/libuv-1.19.2/test/test-process-title.c | 75 + .../test/test-queue-foreach-delete.c | 200 + 3rd/libuv-1.19.2/test/test-ref.c | 445 ++ 3rd/libuv-1.19.2/test/test-run-nowait.c | 45 + 3rd/libuv-1.19.2/test/test-run-once.c | 48 + 3rd/libuv-1.19.2/test/test-semaphore.c | 111 + 3rd/libuv-1.19.2/test/test-shutdown-close.c | 108 + 3rd/libuv-1.19.2/test/test-shutdown-eof.c | 182 + 3rd/libuv-1.19.2/test/test-shutdown-twice.c | 85 + .../test/test-signal-multiple-loops.c | 298 + 3rd/libuv-1.19.2/test/test-signal.c | 325 ++ .../test/test-socket-buffer-size.c | 77 + 3rd/libuv-1.19.2/test/test-spawn.c | 1875 +++++++ 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c | 255 + .../test/test-tcp-alloc-cb-fail.c | 123 + 3rd/libuv-1.19.2/test/test-tcp-bind-error.c | 216 + 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c | 176 + 3rd/libuv-1.19.2/test/test-tcp-close-accept.c | 194 + .../test/test-tcp-close-while-connecting.c | 97 + 3rd/libuv-1.19.2/test/test-tcp-close.c | 136 + .../test/test-tcp-connect-error-after-write.c | 98 + .../test/test-tcp-connect-error.c | 73 + .../test/test-tcp-connect-timeout.c | 91 + .../test/test-tcp-connect6-error.c | 71 + .../test/test-tcp-create-socket-early.c | 209 + 3rd/libuv-1.19.2/test/test-tcp-flags.c | 52 + 3rd/libuv-1.19.2/test/test-tcp-oob.c | 141 + 3rd/libuv-1.19.2/test/test-tcp-open.c | 277 + 3rd/libuv-1.19.2/test/test-tcp-read-stop.c | 76 + .../test/test-tcp-shutdown-after-write.c | 138 + 3rd/libuv-1.19.2/test/test-tcp-try-write.c | 135 + .../test/test-tcp-unexpected-read.c | 117 + .../test/test-tcp-write-after-connect.c | 68 + 3rd/libuv-1.19.2/test/test-tcp-write-fail.c | 115 + .../test/test-tcp-write-queue-order.c | 139 + .../test-tcp-write-to-half-open-connection.c | 141 + 3rd/libuv-1.19.2/test/test-tcp-writealot.c | 180 + 3rd/libuv-1.19.2/test/test-thread-equal.c | 45 + 3rd/libuv-1.19.2/test/test-thread.c | 232 + .../test/test-threadpool-cancel.c | 308 ++ 3rd/libuv-1.19.2/test/test-threadpool.c | 76 + 3rd/libuv-1.19.2/test/test-timer-again.c | 141 + 3rd/libuv-1.19.2/test/test-timer-from-check.c | 80 + 3rd/libuv-1.19.2/test/test-timer.c | 330 ++ 3rd/libuv-1.19.2/test/test-tmpdir.c | 71 + 3rd/libuv-1.19.2/test/test-tty.c | 390 ++ .../test/test-udp-alloc-cb-fail.c | 197 + 3rd/libuv-1.19.2/test/test-udp-bind.c | 93 + .../test/test-udp-create-socket-early.c | 135 + .../test/test-udp-dgram-too-big.c | 91 + 3rd/libuv-1.19.2/test/test-udp-ipv6.c | 198 + .../test/test-udp-multicast-interface.c | 99 + .../test/test-udp-multicast-interface6.c | 103 + .../test/test-udp-multicast-join.c | 150 + .../test/test-udp-multicast-join6.c | 165 + .../test/test-udp-multicast-ttl.c | 94 + 3rd/libuv-1.19.2/test/test-udp-open.c | 204 + 3rd/libuv-1.19.2/test/test-udp-options.c | 137 + .../test/test-udp-send-and-recv.c | 214 + .../test/test-udp-send-hang-loop.c | 99 + .../test/test-udp-send-immediate.c | 149 + .../test/test-udp-send-unreachable.c | 150 + 3rd/libuv-1.19.2/test/test-udp-try-send.c | 121 + 3rd/libuv-1.19.2/test/test-walk-handles.c | 77 + .../test/test-watcher-cross-stop.c | 111 + 3rd/libuv-1.19.2/test/test.gyp | 279 + 3rd/libuv-1.19.2/tools/make_dist_html.py | 124 + 3rd/libuv-1.19.2/uv.gyp | 355 ++ 3rd/libuv-1.19.2/vcbuild.bat | 184 + 413 files changed, 103306 insertions(+) create mode 100644 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md create mode 100644 3rd/libuv-1.19.2/.gitignore create mode 100644 3rd/libuv-1.19.2/.mailmap create mode 100644 3rd/libuv-1.19.2/AUTHORS create mode 100644 3rd/libuv-1.19.2/CONTRIBUTING.md create mode 100644 3rd/libuv-1.19.2/ChangeLog create mode 100644 3rd/libuv-1.19.2/LICENSE create mode 100644 3rd/libuv-1.19.2/LICENSE-docs create mode 100644 3rd/libuv-1.19.2/MAINTAINERS.md create mode 100644 3rd/libuv-1.19.2/Makefile.am create mode 100644 3rd/libuv-1.19.2/Makefile.mingw create mode 100644 3rd/libuv-1.19.2/README.md create mode 100644 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md create mode 100644 3rd/libuv-1.19.2/android-configure create mode 100644 3rd/libuv-1.19.2/appveyor.yml create mode 100644 3rd/libuv-1.19.2/autogen.sh create mode 100644 3rd/libuv-1.19.2/checksparse.sh create mode 100644 3rd/libuv-1.19.2/common.gypi create mode 100644 3rd/libuv-1.19.2/configure.ac create mode 100644 3rd/libuv-1.19.2/docs/code/cgi/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/cgi/tick.c create mode 100644 3rd/libuv-1.19.2/docs/code/detach/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/dns/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/helloworld/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/idle-basic/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/idle-compute/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/interfaces/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/locks/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c create mode 100644 3rd/libuv-1.19.2/docs/code/onchange/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/hello.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/plugin/plugin.h create mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/proc-streams/test.c create mode 100644 3rd/libuv-1.19.2/docs/code/progress/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/queue-cancel/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/queue-work/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/ref-timer/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/signal/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/spawn/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/thread-create/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/tty/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvcat/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvstop/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvtee/main.c create mode 100644 3rd/libuv-1.19.2/docs/code/uvwget/main.c create mode 100644 3rd/libuv-1.19.2/docs/make.bat create mode 100644 3rd/libuv-1.19.2/docs/src/api.rst create mode 100644 3rd/libuv-1.19.2/docs/src/async.rst create mode 100644 3rd/libuv-1.19.2/docs/src/check.rst create mode 100644 3rd/libuv-1.19.2/docs/src/conf.py create mode 100644 3rd/libuv-1.19.2/docs/src/design.rst create mode 100644 3rd/libuv-1.19.2/docs/src/dll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/dns.rst create mode 100644 3rd/libuv-1.19.2/docs/src/errors.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs_event.rst create mode 100644 3rd/libuv-1.19.2/docs/src/fs_poll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/about.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/basics.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/eventloops.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/filesystem.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/introduction.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/networking.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/processes.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/threads.rst create mode 100644 3rd/libuv-1.19.2/docs/src/guide/utilities.rst create mode 100644 3rd/libuv-1.19.2/docs/src/handle.rst create mode 100644 3rd/libuv-1.19.2/docs/src/idle.rst create mode 100644 3rd/libuv-1.19.2/docs/src/index.rst create mode 100644 3rd/libuv-1.19.2/docs/src/loop.rst create mode 100644 3rd/libuv-1.19.2/docs/src/migration_010_100.rst create mode 100644 3rd/libuv-1.19.2/docs/src/misc.rst create mode 100644 3rd/libuv-1.19.2/docs/src/pipe.rst create mode 100644 3rd/libuv-1.19.2/docs/src/poll.rst create mode 100644 3rd/libuv-1.19.2/docs/src/prepare.rst create mode 100644 3rd/libuv-1.19.2/docs/src/process.rst create mode 100644 3rd/libuv-1.19.2/docs/src/request.rst create mode 100644 3rd/libuv-1.19.2/docs/src/signal.rst create mode 100644 3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py create mode 100644 3rd/libuv-1.19.2/docs/src/static/architecture.png create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-micro.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-web.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview.jpg create mode 100644 3rd/libuv-1.19.2/docs/src/static/favicon.ico create mode 100644 3rd/libuv-1.19.2/docs/src/static/logo.png create mode 100644 3rd/libuv-1.19.2/docs/src/static/loop_iteration.png create mode 100644 3rd/libuv-1.19.2/docs/src/stream.rst create mode 100644 3rd/libuv-1.19.2/docs/src/tcp.rst create mode 100644 3rd/libuv-1.19.2/docs/src/threading.rst create mode 100644 3rd/libuv-1.19.2/docs/src/threadpool.rst create mode 100644 3rd/libuv-1.19.2/docs/src/timer.rst create mode 100644 3rd/libuv-1.19.2/docs/src/tty.rst create mode 100644 3rd/libuv-1.19.2/docs/src/udp.rst create mode 100644 3rd/libuv-1.19.2/docs/src/upgrading.rst create mode 100644 3rd/libuv-1.19.2/docs/src/version.rst create mode 100644 3rd/libuv-1.19.2/gyp_uv.py create mode 100644 3rd/libuv-1.19.2/img/banner.png create mode 100644 3rd/libuv-1.19.2/img/logos.svg create mode 100644 3rd/libuv-1.19.2/include/android-ifaddrs.h create mode 100644 3rd/libuv-1.19.2/include/pthread-barrier.h create mode 100644 3rd/libuv-1.19.2/include/stdint-msvc2008.h create mode 100644 3rd/libuv-1.19.2/include/tree.h create mode 100644 3rd/libuv-1.19.2/include/uv-aix.h create mode 100644 3rd/libuv-1.19.2/include/uv-bsd.h create mode 100644 3rd/libuv-1.19.2/include/uv-darwin.h create mode 100644 3rd/libuv-1.19.2/include/uv-errno.h create mode 100644 3rd/libuv-1.19.2/include/uv-linux.h create mode 100644 3rd/libuv-1.19.2/include/uv-os390.h create mode 100644 3rd/libuv-1.19.2/include/uv-posix.h create mode 100644 3rd/libuv-1.19.2/include/uv-sunos.h create mode 100644 3rd/libuv-1.19.2/include/uv-threadpool.h create mode 100644 3rd/libuv-1.19.2/include/uv-unix.h create mode 100644 3rd/libuv-1.19.2/include/uv-version.h create mode 100644 3rd/libuv-1.19.2/include/uv-win.h create mode 100644 3rd/libuv-1.19.2/include/uv.h create mode 100644 3rd/libuv-1.19.2/libuv.pc.in create mode 100644 3rd/libuv-1.19.2/m4/.gitignore create mode 100644 3rd/libuv-1.19.2/m4/as_case.m4 create mode 100644 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 create mode 100644 3rd/libuv-1.19.2/samples/.gitignore create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/client.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/main.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/server.c create mode 100644 3rd/libuv-1.19.2/samples/socks5-proxy/util.c create mode 100644 3rd/libuv-1.19.2/src/fs-poll.c create mode 100644 3rd/libuv-1.19.2/src/heap-inl.h create mode 100644 3rd/libuv-1.19.2/src/inet.c create mode 100644 3rd/libuv-1.19.2/src/queue.h create mode 100644 3rd/libuv-1.19.2/src/threadpool.c create mode 100644 3rd/libuv-1.19.2/src/unix/aix-common.c create mode 100644 3rd/libuv-1.19.2/src/unix/aix.c create mode 100644 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c create mode 100644 3rd/libuv-1.19.2/src/unix/async.c create mode 100644 3rd/libuv-1.19.2/src/unix/atomic-ops.h create mode 100644 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c create mode 100644 3rd/libuv-1.19.2/src/unix/core.c create mode 100644 3rd/libuv-1.19.2/src/unix/cygwin.c create mode 100644 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/darwin.c create mode 100644 3rd/libuv-1.19.2/src/unix/dl.c create mode 100644 3rd/libuv-1.19.2/src/unix/freebsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/fs.c create mode 100644 3rd/libuv-1.19.2/src/unix/fsevents.c create mode 100644 3rd/libuv-1.19.2/src/unix/getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/src/unix/getnameinfo.c create mode 100644 3rd/libuv-1.19.2/src/unix/ibmi.c create mode 100644 3rd/libuv-1.19.2/src/unix/internal.h create mode 100644 3rd/libuv-1.19.2/src/unix/kqueue.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-core.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-inotify.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.c create mode 100644 3rd/libuv-1.19.2/src/unix/linux-syscalls.h create mode 100644 3rd/libuv-1.19.2/src/unix/loop-watcher.c create mode 100644 3rd/libuv-1.19.2/src/unix/loop.c create mode 100644 3rd/libuv-1.19.2/src/unix/netbsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/no-fsevents.c create mode 100644 3rd/libuv-1.19.2/src/unix/no-proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/openbsd.c create mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.c create mode 100644 3rd/libuv-1.19.2/src/unix/os390-syscalls.h create mode 100644 3rd/libuv-1.19.2/src/unix/os390.c create mode 100644 3rd/libuv-1.19.2/src/unix/pipe.c create mode 100644 3rd/libuv-1.19.2/src/unix/poll.c create mode 100644 3rd/libuv-1.19.2/src/unix/posix-hrtime.c create mode 100644 3rd/libuv-1.19.2/src/unix/posix-poll.c create mode 100644 3rd/libuv-1.19.2/src/unix/process.c create mode 100644 3rd/libuv-1.19.2/src/unix/procfs-exepath.c create mode 100644 3rd/libuv-1.19.2/src/unix/proctitle.c create mode 100644 3rd/libuv-1.19.2/src/unix/pthread-fixes.c create mode 100644 3rd/libuv-1.19.2/src/unix/signal.c create mode 100644 3rd/libuv-1.19.2/src/unix/spinlock.h create mode 100644 3rd/libuv-1.19.2/src/unix/stream.c create mode 100644 3rd/libuv-1.19.2/src/unix/sunos.c create mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c create mode 100644 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c create mode 100644 3rd/libuv-1.19.2/src/unix/tcp.c create mode 100644 3rd/libuv-1.19.2/src/unix/thread.c create mode 100644 3rd/libuv-1.19.2/src/unix/timer.c create mode 100644 3rd/libuv-1.19.2/src/unix/tty.c create mode 100644 3rd/libuv-1.19.2/src/unix/udp.c create mode 100644 3rd/libuv-1.19.2/src/uv-common.c create mode 100644 3rd/libuv-1.19.2/src/uv-common.h create mode 100644 3rd/libuv-1.19.2/src/uv-data-getter-setters.c create mode 100644 3rd/libuv-1.19.2/src/version.c create mode 100644 3rd/libuv-1.19.2/src/win/async.c create mode 100644 3rd/libuv-1.19.2/src/win/atomicops-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/core.c create mode 100644 3rd/libuv-1.19.2/src/win/detect-wakeup.c create mode 100644 3rd/libuv-1.19.2/src/win/dl.c create mode 100644 3rd/libuv-1.19.2/src/win/error.c create mode 100644 3rd/libuv-1.19.2/src/win/fs-event.c create mode 100644 3rd/libuv-1.19.2/src/win/fs.c create mode 100644 3rd/libuv-1.19.2/src/win/getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/src/win/getnameinfo.c create mode 100644 3rd/libuv-1.19.2/src/win/handle-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/handle.c create mode 100644 3rd/libuv-1.19.2/src/win/internal.h create mode 100644 3rd/libuv-1.19.2/src/win/loop-watcher.c create mode 100644 3rd/libuv-1.19.2/src/win/pipe.c create mode 100644 3rd/libuv-1.19.2/src/win/poll.c create mode 100644 3rd/libuv-1.19.2/src/win/process-stdio.c create mode 100644 3rd/libuv-1.19.2/src/win/process.c create mode 100644 3rd/libuv-1.19.2/src/win/req-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/req.c create mode 100644 3rd/libuv-1.19.2/src/win/signal.c create mode 100644 3rd/libuv-1.19.2/src/win/snprintf.c create mode 100644 3rd/libuv-1.19.2/src/win/stream-inl.h create mode 100644 3rd/libuv-1.19.2/src/win/stream.c create mode 100644 3rd/libuv-1.19.2/src/win/tcp.c create mode 100644 3rd/libuv-1.19.2/src/win/thread.c create mode 100644 3rd/libuv-1.19.2/src/win/timer.c create mode 100644 3rd/libuv-1.19.2/src/win/tty.c create mode 100644 3rd/libuv-1.19.2/src/win/udp.c create mode 100644 3rd/libuv-1.19.2/src/win/util.c create mode 100644 3rd/libuv-1.19.2/src/win/winapi.c create mode 100644 3rd/libuv-1.19.2/src/win/winapi.h create mode 100644 3rd/libuv-1.19.2/src/win/winsock.c create mode 100644 3rd/libuv-1.19.2/src/win/winsock.h create mode 100644 3rd/libuv-1.19.2/test/benchmark-async-pummel.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-async.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-fs-stat.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-list.h create mode 100644 3rd/libuv-1.19.2/test/benchmark-loop-count.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-million-async.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-million-timers.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-multi-accept.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-pound.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-pump.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-sizes.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-spawn.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-thread.c create mode 100644 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c create mode 100644 3rd/libuv-1.19.2/test/blackhole-server.c create mode 100644 3rd/libuv-1.19.2/test/dns-server.c create mode 100644 3rd/libuv-1.19.2/test/echo-server.c create mode 100644 3rd/libuv-1.19.2/test/fixtures/empty_file create mode 100644 3rd/libuv-1.19.2/test/fixtures/load_error.node create mode 100644 3rd/libuv-1.19.2/test/run-benchmarks.c create mode 100644 3rd/libuv-1.19.2/test/run-tests.c create mode 100644 3rd/libuv-1.19.2/test/runner-unix.c create mode 100644 3rd/libuv-1.19.2/test/runner-unix.h create mode 100644 3rd/libuv-1.19.2/test/runner-win.c create mode 100644 3rd/libuv-1.19.2/test/runner-win.h create mode 100644 3rd/libuv-1.19.2/test/runner.c create mode 100644 3rd/libuv-1.19.2/test/runner.h create mode 100644 3rd/libuv-1.19.2/test/task.h create mode 100644 3rd/libuv-1.19.2/test/test-active.c create mode 100644 3rd/libuv-1.19.2/test/test-async-null-cb.c create mode 100644 3rd/libuv-1.19.2/test/test-async.c create mode 100644 3rd/libuv-1.19.2/test/test-barrier.c create mode 100644 3rd/libuv-1.19.2/test/test-callback-order.c create mode 100644 3rd/libuv-1.19.2/test/test-callback-stack.c create mode 100644 3rd/libuv-1.19.2/test/test-close-fd.c create mode 100644 3rd/libuv-1.19.2/test/test-close-order.c create mode 100644 3rd/libuv-1.19.2/test/test-condvar.c create mode 100644 3rd/libuv-1.19.2/test/test-connect-unspecified.c create mode 100644 3rd/libuv-1.19.2/test/test-connection-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c create mode 100644 3rd/libuv-1.19.2/test/test-default-loop-close.c create mode 100644 3rd/libuv-1.19.2/test/test-delayed-accept.c create mode 100644 3rd/libuv-1.19.2/test/test-dlerror.c create mode 100644 3rd/libuv-1.19.2/test/test-eintr-handling.c create mode 100644 3rd/libuv-1.19.2/test/test-embed.c create mode 100644 3rd/libuv-1.19.2/test/test-emfile.c create mode 100644 3rd/libuv-1.19.2/test/test-env-vars.c create mode 100644 3rd/libuv-1.19.2/test/test-error.c create mode 100644 3rd/libuv-1.19.2/test/test-fail-always.c create mode 100644 3rd/libuv-1.19.2/test/test-fork.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-copyfile.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-event.c create mode 100644 3rd/libuv-1.19.2/test/test-fs-poll.c create mode 100644 3rd/libuv-1.19.2/test/test-fs.c create mode 100644 3rd/libuv-1.19.2/test/test-get-currentexe.c create mode 100644 3rd/libuv-1.19.2/test/test-get-loadavg.c create mode 100644 3rd/libuv-1.19.2/test/test-get-memory.c create mode 100644 3rd/libuv-1.19.2/test/test-get-passwd.c create mode 100644 3rd/libuv-1.19.2/test/test-getaddrinfo.c create mode 100644 3rd/libuv-1.19.2/test/test-gethostname.c create mode 100644 3rd/libuv-1.19.2/test/test-getnameinfo.c create mode 100644 3rd/libuv-1.19.2/test/test-getsockname.c create mode 100644 3rd/libuv-1.19.2/test/test-getters-setters.c create mode 100644 3rd/libuv-1.19.2/test/test-handle-fileno.c create mode 100644 3rd/libuv-1.19.2/test/test-homedir.c create mode 100644 3rd/libuv-1.19.2/test/test-hrtime.c create mode 100644 3rd/libuv-1.19.2/test/test-idle.c create mode 100644 3rd/libuv-1.19.2/test/test-ip4-addr.c create mode 100644 3rd/libuv-1.19.2/test/test-ip6-addr.c create mode 100644 3rd/libuv-1.19.2/test/test-ipc-send-recv.c create mode 100644 3rd/libuv-1.19.2/test/test-ipc.c create mode 100644 3rd/libuv-1.19.2/test/test-list.h create mode 100644 3rd/libuv-1.19.2/test/test-loop-alive.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-close.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-configure.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-handles.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-stop.c create mode 100644 3rd/libuv-1.19.2/test/test-loop-time.c create mode 100644 3rd/libuv-1.19.2/test/test-multiple-listen.c create mode 100644 3rd/libuv-1.19.2/test/test-mutexes.c create mode 100644 3rd/libuv-1.19.2/test/test-osx-select.c create mode 100644 3rd/libuv-1.19.2/test/test-pass-always.c create mode 100644 3rd/libuv-1.19.2/test/test-ping-pong.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-bind-error.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-error.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-getsockname.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-pending-instances.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-server-close.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c create mode 100644 3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c create mode 100644 3rd/libuv-1.19.2/test/test-platform-output.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-close.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-closesocket.c create mode 100644 3rd/libuv-1.19.2/test/test-poll-oob.c create mode 100644 3rd/libuv-1.19.2/test/test-poll.c create mode 100644 3rd/libuv-1.19.2/test/test-process-title-threadsafe.c create mode 100644 3rd/libuv-1.19.2/test/test-process-title.c create mode 100644 3rd/libuv-1.19.2/test/test-queue-foreach-delete.c create mode 100644 3rd/libuv-1.19.2/test/test-ref.c create mode 100644 3rd/libuv-1.19.2/test/test-run-nowait.c create mode 100644 3rd/libuv-1.19.2/test/test-run-once.c create mode 100644 3rd/libuv-1.19.2/test/test-semaphore.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-close.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-eof.c create mode 100644 3rd/libuv-1.19.2/test/test-shutdown-twice.c create mode 100644 3rd/libuv-1.19.2/test/test-signal-multiple-loops.c create mode 100644 3rd/libuv-1.19.2/test/test-signal.c create mode 100644 3rd/libuv-1.19.2/test/test-socket-buffer-size.c create mode 100644 3rd/libuv-1.19.2/test/test-spawn.c create mode 100644 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-accept.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-close.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-connect6-error.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-flags.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-oob.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-open.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-read-stop.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-try-write.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c create mode 100644 3rd/libuv-1.19.2/test/test-tcp-writealot.c create mode 100644 3rd/libuv-1.19.2/test/test-thread-equal.c create mode 100644 3rd/libuv-1.19.2/test/test-thread.c create mode 100644 3rd/libuv-1.19.2/test/test-threadpool-cancel.c create mode 100644 3rd/libuv-1.19.2/test/test-threadpool.c create mode 100644 3rd/libuv-1.19.2/test/test-timer-again.c create mode 100644 3rd/libuv-1.19.2/test/test-timer-from-check.c create mode 100644 3rd/libuv-1.19.2/test/test-timer.c create mode 100644 3rd/libuv-1.19.2/test/test-tmpdir.c create mode 100644 3rd/libuv-1.19.2/test/test-tty.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-bind.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-create-socket-early.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-ipv6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-join6.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-open.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-options.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-and-recv.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-immediate.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-send-unreachable.c create mode 100644 3rd/libuv-1.19.2/test/test-udp-try-send.c create mode 100644 3rd/libuv-1.19.2/test/test-walk-handles.c create mode 100644 3rd/libuv-1.19.2/test/test-watcher-cross-stop.c create mode 100644 3rd/libuv-1.19.2/test/test.gyp create mode 100644 3rd/libuv-1.19.2/tools/make_dist_html.py create mode 100644 3rd/libuv-1.19.2/uv.gyp create mode 100644 3rd/libuv-1.19.2/vcbuild.bat diff --git a/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md b/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..543dc9fd --- /dev/null +++ b/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,10 @@ + +* **Version**: +* **Platform**: diff --git a/3rd/libuv-1.19.2/.gitignore b/3rd/libuv-1.19.2/.gitignore new file mode 100644 index 00000000..7536abd5 --- /dev/null +++ b/3rd/libuv-1.19.2/.gitignore @@ -0,0 +1,79 @@ +*.swp +*.[oa] +*.l[oa] +*.opensdf +*.orig +*.pyc +*.sdf +*.suo +.vs/ +*.VC.db +*.VC.opendb +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 +/android-toolchain + +/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/3rd/libuv-1.19.2/.mailmap b/3rd/libuv-1.19.2/.mailmap new file mode 100644 index 00000000..da421436 --- /dev/null +++ b/3rd/libuv-1.19.2/.mailmap @@ -0,0 +1,46 @@ +A. Hauptmann +Aaron Bieber +Alan Gutierrez +Andrius Bentkus +Bert Belder +Bert Belder +Bert Belder +Brandon Philips +Brian White +Brian White +Caleb James DeLisle +Christoph Iserlohn +Devchandra Meetei Leishangthem +Fedor Indutny +Frank Denis +Imran Iqbal +Isaac Z. Schlueter +Jason Williams +Justin Venus +Keno Fischer +Keno Fischer +Leith Bade +Leonard Hecker +Maciej Małecki +Marc Schlaich +Michael +Michael Neumann +Nicholas Vavilov +Nick Logan +Rasmus Christian Pedersen +Rasmus Christian Pedersen +Robert Mustacchi +Ryan Dahl +Ryan Emery +Sakthipriyan Vairamani +Sam Roberts +San-Tai Hsu +Santiago Gimeno +Saúl Ibarra Corretgé +Shigeki Ohtsu +Timothy J. Fontaine +Yasuhiro Matsumoto +Yazhong Liu +Yuki Okumura +jBarz +jBarz diff --git a/3rd/libuv-1.19.2/AUTHORS b/3rd/libuv-1.19.2/AUTHORS new file mode 100644 index 00000000..fcb0aac3 --- /dev/null +++ b/3rd/libuv-1.19.2/AUTHORS @@ -0,0 +1,332 @@ +# Authors ordered by first contribution. +Ryan Dahl +Bert Belder +Josh Roesslein +Alan Gutierrez +Joshua Peek +Igor Zinkovsky +San-Tai Hsu +Ben Noordhuis +Henry Rawas +Robert Mustacchi +Matt Stevens +Paul Querna +Shigeki Ohtsu +Tom Hughes +Peter Bright +Jeroen Janssen +Andrea Lattuada +Augusto Henrique Hentz +Clifford Heath +Jorge Chamorro Bieling +Luis Lavena +Matthew Sporleder +Erick Tryzelaar +Isaac Z. Schlueter +Pieter Noordhuis +Marek Jelen +Fedor Indutny +Saúl Ibarra Corretgé +Felix Geisendörfer +Yuki Okumura +Roman Shtylman +Frank Denis +Carter Allen +Tj Holowaychuk +Shimon Doodkin +Ryan Emery +Bruce Mitchener +Maciej Małecki +Yasuhiro Matsumoto +Daisuke Murase +Paddy Byers +Dan VerWeire +Brandon Benvie +Brandon Philips +Nathan Rajlich +Charlie McConnell +Vladimir Dronnikov +Aaron Bieber +Bulat Shakirzyanov +Brian White +Erik Dubbelboer +Keno Fischer +Ira Cooper +Andrius Bentkus +Iñaki Baz Castillo +Mark Cavage +George Yohng +Xidorn Quan +Roman Neuhauser +Shuhei Tanuma +Bryan Cantrill +Trond Norbye +Tim Holy +Prancesco Pertugio +Leonard Hecker +Andrew Paprocki +Luigi Grilli +Shannen Saez +Artur Adib +Hiroaki Nakamura +Ting-Yu Lin +Stephen Gallagher +Shane Holloway +Andrew Shaffer +Vlad Tudose +Ben Leslie +Tim Bradshaw +Timothy J. Fontaine +Marc Schlaich +Brian Mazza +Elliot Saba +Ben Kelly +Nils Maier +Nicholas Vavilov +Miroslav Bajtoš +Sean Silva +Wynn Wilkes +Andrei Sedoi +Alex Crichton +Brent Cook +Brian Kaisner +Luca Bruno +Reini Urban +Maks Naumov +Sean Farrell +Chris Bank +Geert Jansen +Christoph Iserlohn +Steven Kabbes +Alex Gaynor +huxingyi +Tenor Biel +Andrej Manduch +Joshua Neuheisel +Alexis Campailla +Yazhong Liu +Sam Roberts +River Tarnell +Nathan Sweet +Trevor Norris +Oguz Bastemur +Dylan Cali +Austin Foxley +Benjamin Saunders +Geoffry Song +Rasmus Christian Pedersen +William Light +Oleg Efimov +Lars Gierth +Rasmus Christian Pedersen +Justin Venus +Kristian Evensen +Linus Mårtensson +Navaneeth Kedaram Nambiathan +Yorkie +StarWing +thierry-FreeBSD +Isaiah Norton +Raul Martins +David Capello +Paul Tan +Javier Hernández +Tonis Tiigi +Norio Kobota +李港平 +Chernyshev Viacheslav +Stephen von Takach +JD Ballard +Luka Perkov +Ryan Cole +HungMingWu +Jay Satiro +Leith Bade +Peter Atashian +Tim Cooper +Caleb James DeLisle +Jameson Nash +Graham Lee +Andrew Low +Pavel Platto +Tony Kelman +John Firebaugh +lilohuang +Paul Goldsmith +Julien Gilli +Michael Hudson-Doyle +Recep ASLANTAS +Rob Adams +Zachary Newman +Robin Hahling +Jeff Widman +cjihrig +Tomasz Kołodziejski +Unknown W. Brackets +Emmanuel Odeke +Mikhail Mukovnikov +Thorsten Lorenz +Yuri D'Elia +Manos Nikolaidis +Elijah Andrews +Michael Ira Krufky +Helge Deller +Joey Geralnik +Tim Caswell +Logan Rosen +Kenneth Perry +John Marino +Alexey Melnichuk +Johan Bergström +Alex Mo +Luis Martinez de Bartolome +Michael Penick +Michael +Massimiliano Torromeo +TomCrypto +Brett Vickers +Ole André Vadla Ravnås +Kazuho Oku +Ryan Phillips +Brian Green +Devchandra Meetei Leishangthem +Corey Farrell +Per Nilsson +Alan Rogers +Daryl Haresign +Rui Abreu Ferreira +João Reis +farblue68 +Jason Williams +Igor Soarez +Miodrag Milanovic +Cheng Zhao +Michael Neumann +Stefano Cristiano +heshamsafi +A. Hauptmann +John McNamee +Yosuke Furukawa +Santiago Gimeno +guworks +RossBencina +Roger A. Light +chenttuuvv +Richard Lau +ronkorving +Corbin Simpson +Zachary Hamm +Karl Skomski +Jeremy Whitlock +Willem Thiart +Ben Trask +Jianghua Yang +Colin Snover +Sakthipriyan Vairamani +Eli Skeggs +nmushell +Gireesh Punathil +Ryan Johnston +Adam Stylinski +Nathan Corvino +Wink Saville +Angel Leon +Louis DeJardin +Imran Iqbal +Petka Antonov +Ian Kronquist +kkdaemon +Yuval Brik +Joran Dirk Greef +Andrey Mazo +sztomi +Martin Bark +Dave +Alexis Murzeau +Didiet +Nan Xiang <514580344@qq.com> +Samuel Lorétan +Nándor István Krácser +Katsutoshi Horie +Lukasz Jagiello +Robert Chiras +Kári Tristan Helgason +Krishnaraj Bhat +Enno Boland +Michael Fero +Robert Jefe Lindstaedt +Myles Borins +Tony Theodore +Jason Ginchereau +Nicolas Cavallari +Pierre-Marie de Rodat +Brian Maher +neevek +John Barboza +liuxiaobo +Michele Caini +Bartosz Sosnowski +Matej Knopp +sunjin.lee +Matt Clarkson +Jeffrey Clark +Bart Robinson +Vit Gottwald +Vladimír Čunát +Alex Hultman +Brad King +Philippe Laferriere +Will Speak +Hitesh Kanwathirtha +Eric Sciple +jBarz +muflub +Daniel Bevenius +Howard Hellyer +Chris Araman +Vladimir Matveev +Jason Madden +Jamie Davis +Daniel Kahn Gillmor +Keane +James McCoy +Bernardo Ramos +Juan Cruz Viotti +Gemini Wen +Sebastian Wiedenroth +Sai Ke WANG +Barnabas Gema +Romain Caire +Robert Ayrapetyan +Refael Ackermann +André Klitzing +Matthew Taylor +CurlyMoo +XadillaX +Anticrisis +Jacob Segal +Maciej Szeptuch (Neverous) +Joel Winarske +Gergely Nagy +Kamil Rytarowski +tux.uudiin <77389867@qq.com> +Nick Logan +darobs +Zheng, Lei +Carlo Marcelo Arenas Belón +Scott Parker +Wade Brainerd +rayrase +Pekka Nikander +Ed Schouten +Xu Meng +Matt Harrison +Anna Henningsen +Jérémy Lal +Ben Wijen +elephantp +Felix Yan +Mason X +Jesse Gorzinski +Ryuichi KAWAMATA +Joyee Cheung diff --git a/3rd/libuv-1.19.2/CONTRIBUTING.md b/3rd/libuv-1.19.2/CONTRIBUTING.md new file mode 100644 index 00000000..d9bf0472 --- /dev/null +++ b/3rd/libuv-1.19.2/CONTRIBUTING.md @@ -0,0 +1,169 @@ +# 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][] 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. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. +- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. + +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.freenode.net/?channels=libuv +[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html +[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/3rd/libuv-1.19.2/ChangeLog b/3rd/libuv-1.19.2/ChangeLog new file mode 100644 index 00000000..53ebd01d --- /dev/null +++ b/3rd/libuv-1.19.2/ChangeLog @@ -0,0 +1,3531 @@ +2018.02.22, Version 1.19.2 (Stable) + +Changes since version 1.19.1: + +* test: fix incorrect asserts (cjihrig) + +* test: fix a typo in test-fork.c (Felix Yan) + +* build: remove long-obsolete gyp workarounds (Ben Noordhuis) + +* build: split off tests into separate gyp file (Ben Noordhuis) + +* test: check uv_cond_timedwait more carefully (Jamie Davis) + +* include,src: introduce UV__ERR() macro (Mason X) + +* build: add url field to libuv.pc (Ben Noordhuis) + +* doc: mark IBM i as Tier 3 support (Jesse Gorzinski) + +* win,build: correct C2059 errors (Michael Fero) + +* zos: fix timeout for condition variable (jBarz) + +* win: CREATE_NO_WINDOW when stdio is not inherited (Nick Logan) + +* build: fix commmon.gypi comment (Ryuichi KAWAMATA) + +* doc: document uv_timer_start() on an active timer (Vladimír Čunát) + +* doc: add note about handle movability (Bartosz Sosnowski) + +* doc: fix syntax error in loop documentation (Bartosz Sosnowski) + +* osx,stream: retry sending handle on EMSGSIZE error (Santiago Gimeno) + +* unix: delay fs req register until after validation (cjihrig) + +* test: add tests for bad inputs (Joyee Cheung) + +* unix,win: ensure req->bufs is freed (cjihrig) + +* test: add additional fs memory management checks (cjihrig) + + +2018.01.20, Version 1.19.1 (Stable), 8202d1751196c2374ad370f7f3779daef89befae + +Changes since version 1.19.0: + +* Revert "unix,tcp: avoid marking server sockets connected" (Ben Noordhuis) + +* Revert "unix,fs: fix for potential partial reads/writes" (Ben Noordhuis) + +* Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" (Ben Noordhuis) + +* cygwin: fix compilation of ifaddrs impl (Brad King) + + +2018.01.18, Version 1.19.0 (Stable), effbb7c9d29090b2e085a40867f8cdfa916a66df + +Changes since version 1.18.0: + +* core: add getter/setter functions for easier ABI compat (Anna Henningsen) + +* unix: make get(set)_process_title MT-safe (Matt Harrison) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* win, process: uv_kill improvements (Bartosz Sosnowski) + +* win: set _WIN32_WINNT to 0x0600 (cjihrig) + +* zos: implement uv_fs_event* functions (jBarz) + +* unix,tcp: avoid marking server sockets connected (Jameson Nash) + +* doc: mark Windows 7 as Tier 1 support (Bartosz Sosnowski) + +* win: map 0.0.0.0 and :: addresses to localhost (Bartosz Sosnowski) + +* build: install libuv.pc unconditionally (Ben Noordhuis) + +* test: remove custom timeout for thread test on ppc (Ben Noordhuis) + +* test: allow multicast not permitted status (Jérémy Lal) + +* test: allow net unreachable status in udp test (Ben Noordhuis) + +* unix: use SA_RESTART when setting our sighandler (Brad King) + +* unix,fs: fix for potential partial reads/writes (Ben Wijen) + +* win,build: do not build executable installer for dll (Bert Belder) + +* win: allow directory symlinks to be created in a non-elevated context (Bert + Belder) + +* zos,test: accept SIGKILL for flaky test (jBarz) + +* win: use RemoveDirectoryW() instead of _wmrmdir() (Ben Noordhuis) + +* unix: fix uv_cpu_info() error on FreeBSD (elephantp) + +* zos,test: decrease pings to avoid timeout (jBarz) + + +2017.12.02, Version 1.18.0 (Stable), 1489c98b7fc17f1702821a269eb0c5e730c5c813 + +Changes since version 1.17.0: + +* aix: fix -Wmaybe-uninitialized warning (cjihrig) + +* doc: remove note about SIGWINCH on Windows (Bartosz Sosnowski) + +* Revert "unix,win: wait for threads to start" (Ben Noordhuis) + +* unix,win: add uv_os_getpid() (Bartosz Sosnowski) + +* unix: remove incorrect assertion in uv_shutdown() (Jameson Nash) + +* doc: fix IRC URL in CONTRIBUTING.md (Matt Harrison) + + +2017.11.25, Version 1.17.0 (Stable), 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 + +Changes since version 1.16.1: + +* unix: avoid malloc() call in uv_spawn() (Ben Noordhuis) + +* doc: clarify the description of uv_loop_alive() (Ed Schouten) + +* win: map UV_FS_O_EXLOCK to a share mode of 0 (Joran Dirk Greef) + +* win: fix build on case-sensitive file systems (Ben Noordhuis) + +* win: fix test runner build with mingw64 (Ben Noordhuis) + +* win: remove unused variable in test/test-fs.c (Ben Noordhuis) + +* zos: add strnlen() implementation (jBarz) + +* unix: keep track of bound sockets sent via spawn (jBarz) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* test: avoid malloc() in threadpool test (Ben Noordhuis) + +* test: lower number of tasks in threadpool test (Ben Noordhuis) + +* win: issue memory barrier in uv_thread_join() (Ben Noordhuis) + +* ibmi: add support for new platform (Xu Meng) + +* test: fix test-spawn compilation (Bartosz Sosnowski) + + +2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 + +Changes since version 1.16.0: + +* unix: move net/if.h include (cjihrig) + +* win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) + + +2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb + +Changes since version 1.15.0: + +* win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) + +* unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) + +* win, fs: fix non-symlink reparse points (Wade Brainerd) + +* test: fix -Wstrict-prototypes warnings (Ben Noordhuis) + +* unix, windows: map ENOTTY errno (Ben Noordhuis) + +* unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) + +* unix: do not close invalid kqueue fd after fork (jBarz) + +* zos: reset epoll data after fork (jBarz) + +* zos: skip fork_threadpool_queue_work_simple (jBarz) + +* test: keep platform_output as first test (Bartosz Sosnowski) + +* win: fix non-English dlopen error message (Bartosz Sosnowski) + +* unix,win: add uv_os_getppid() (cjihrig) + +* test: fix const qualification compiler warning (Ben Noordhuis) + +* doc: mark uv_default_loop() as not thread safe (rayrase) + +* win, pipe: null-initialize stream->shutdown_req (Jameson Nash) + +* tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) + +* test: no extra new line in skipped test output (Bartosz Sosnowski) + +* pipe: allow access from other users (Bartosz Sosnowski) + +* unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) + + +2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 + +Changes since version 1.14.1: + +* unix: limit uv__has_forked_with_cfrunloop to macOS (Kamil Rytarowski) + +* win: fix buffer size in uv__getpwuid_r() (tux.uudiin) + +* win,tty: improve SIGWINCH support (Bartosz Sosnowski) + +* unix: use fchmod() in uv_fs_copyfile() (cjihrig) + +* unix: support copying empty files (cjihrig) + +* unix: truncate destination in uv_fs_copyfile() (Nick Logan) + +* win,build: keep cwd when setting build environment (darobs) + +* test: add NetBSD support to test-udp-ipv6.c (Kamil Rytarowski) + +* unix: add NetBSD support in core.c (Kamil Rytarowski) + +* linux: increase thread stack size with musl libc (Ben Noordhuis) + +* netbsd: correct uv_exepath() on NetBSD (Kamil Rytarowski) + +* test: clean up semaphore after use (jBarz) + +* win,build: bump vswhere_usability_wrapper to 2.0.0 (Refael Ackermann) + +* win: let UV_PROCESS_WINDOWS_HIDE hide consoles (cjihrig) + +* zos: lock protect global epoll list in epoll_ctl (jBarz) + +* zos: change platform name to match python (jBarz) + +* android: fix getifaddrs() (Zheng, Lei) + +* netbsd: implement uv__tty_is_slave() (Kamil Rytarowski) + +* zos: fix readlink for mounts with system variables (jBarz) + +* test: sort the tests alphabetically (Sakthipriyan Vairamani) + +* windows: fix compilation warnings (Carlo Marcelo Arenas Belón) + +* build: avoid -fstrict-aliasing compile option (jBarz) + +* win: remove unused variables (Carlo Marcelo Arenas Belón) + +* unix: remove unused variables (Sakthipriyan Vairamani) + +* netbsd: disable poll_bad_fdtype on NetBSD (Kamil Rytarowski) + +* netbsd: use uv__cloexec and uv__nonblock (Kamil Rytarowski) + +* test: fix udp_multicast_join6 on NetBSD (Kamil Rytarowski) + +* unix,win: add uv_mutex_init_recursive() (Scott Parker) + +* netbsd: do not exclude IPv6 functionality (Kamil Rytarowski) + +* fsevents: watch files with fsevents on macos 10.7+ (Ben Noordhuis) + +* unix: retry on ENOBUFS in sendmsg(2) (Kamil Rytarowski) + + +2017.09.07, Version 1.14.1 (Stable), b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 + +Changes since version 1.14.0: + +* fs, win: add support for user symlinks (Bartosz Sosnowski) + +* cygwin: include uv-posix.h header (Joel Winarske) + +* zos: fix semaphore initialization (jBarz) + +* zos: improve loop_count benchmark performance (jBarz) + +* zos, test: flush out the oob data in callback (jBarz) + +* unix,win: check for bad flags in uv_fs_copyfile() (cjihrig) + +* unix: modify argv[0] when process title is set (Matthew Taylor) + +* unix: don't use req->loop in uv__fs_copyfile() (cjihrig) + +* doc: fix a trivial typo (Vladimír Čunát) + +* android: fix uv_cond_timedwait on API level < 21 (Gergely Nagy) + +* win: add uv__once_init() calls (Bartosz Sosnowski) + +* unix,windows: init all requests in fs calls (cjihrig) + +* unix,windows: return UV_EINVAL on NULL fs reqs (cjihrig) + +* windows: add POST macro to fs functions (cjihrig) + +* unix: handle partial sends in uv_fs_copyfile() (A. Hauptmann) + +* Revert "win, test: fix double close in test runner" (Bartosz Sosnowski) + +* win, test: remove surplus CloseHandle (Bartosz Sosnowski) + + +2017.08.17, Version 1.14.0 (Stable), e0d31e9e21870f88277746b6d59cf07b977cdfea + +Changes since version 1.13.1: + +* unix: check for NULL in uv_os_unsetenv for parameter name (André Klitzing) + +* doc: add thread safety warning for process title (Matthew Taylor) + +* unix: always copy process title into local buffer (Matthew Taylor) + +* poll: add support for OOB TCP and GPIO interrupts (CurlyMoo) + +* win,build: fix appveyor properly (Refael Ackermann) + +* win: include filename in dlopen error message (Ben Noordhuis) + +* aix: add netmask, mac address into net interfaces (Gireesh Punathil) + +* unix, windows: map EREMOTEIO errno (Ben Noordhuis) + +* unix: fix wrong MAC of uv_interface_address (XadillaX) + +* win,build: fix building from Windows SDK or VS console (Saúl Ibarra Corretgé) + +* github: fix link to help repo in issue template (Ben Noordhuis) + +* zos: remove nonexistent include from autotools build (Saúl Ibarra Corretgé) + +* misc: remove reference to pthread-fixes.h from LICENSE (Saúl Ibarra Corretgé) + +* docs: fix guide source code example paths (Anticrisis) + +* android: fix compilation with new NDK versions (Saúl Ibarra Corretgé) + +* misc: add android-toolchain to .gitignore (Saúl Ibarra Corretgé) + +* win, fs: support unusual reparse points (Bartosz Sosnowski) + +* android: fix detection of pthread_condattr_setclock (Saúl Ibarra Corretgé) + +* android: remove no longer needed check (Saúl Ibarra Corretgé) + +* doc: update instructions for building on Android (Saúl Ibarra Corretgé) + +* win, process: support semicolons in PATH variable (Bartosz Sosnowski) + +* doc: document uv_async_(init|send) return values (Ben Noordhuis) + +* doc: add Android as a tier 3 supported platform (Saúl Ibarra Corretgé) + +* unix: add missing semicolon (jBarz) + +* win, test: fix double close in test runner (Bartosz Sosnowski) + +* doc: update supported windows version baseline (Ben Noordhuis) + +* test,zos: skip chown root test (jBarz) + +* test,zos: use gid=-1 to test spawn_setgid_fails (jBarz) + +* zos: fix hr timer resolution (jBarz) + +* android: fix blocking recvmsg due to netlink bug (Jacob Segal) + +* zos: read more accurate rss info from RSM (jBarz) + +* win: allow bound/connected socket in uv_tcp_open() (Maciej Szeptuch + (Neverous)) + +* doc: differentiate SmartOS and SunOS support (cjihrig) + +* unix: make uv_poll_stop() remove fd from pollset (Ben Noordhuis) + +* unix, windows: add basic uv_fs_copyfile() (cjihrig) + + +2017.07.07, Version 1.13.1 (Stable), 2bb4b68758f07cd8617838e68c44c125bc567ba6 + +Changes since version 1.13.0: + +* Now working on version 1.13.1 (cjihrig) + +* build: workaround AppVeyor quirk (Refael Ackermann) + + +2017.07.06, Version 1.13.0 (Stable), 8342fcaab815f33b988c1910ea988f28dfe27edb + +Changes since version 1.12.0: + +* Now working on version 1.12.1 (cjihrig) + +* unix: avoid segfault in uv_get_process_title (Michele Caini) + +* build: add a comma to uv.gyp (Gemini Wen) + +* win: restore file pos after positional read/write (Bartosz Sosnowski) + +* unix,stream: return error on closed handle passing (Santiago Gimeno) + +* unix,benchmark: use fd instead of FILE* after fork (jBarz) + +* zos: avoid compiler warnings (jBarz) + +* win,pipe: race condition canceling readfile thread (Jameson Nash) + +* sunos: filter out non-IPv4/IPv6 interfaces (Sebastian Wiedenroth) + +* sunos: fix cmpxchgi and cmpxchgl type error (Sai Ke WANG) + +* unix: reset signal disposition before execve() (Ben Noordhuis) + +* unix: reset signal mask before execve() (Ben Noordhuis) + +* unix: fix POLLIN assertion on server read (jBarz) + +* zos: use stckf builtin for high-res timer (jBarz) + +* win,udp: implements uv_udp_try_send (Barnabas Gema) + +* win,udp: return UV_EINVAL instead of aborting (Romain Caire) + +* freebsd: replace kvm with sysctl (Robert Ayrapetyan) + +* aix: fix un-initialized pointer field in fs handle (Gireesh Punathil) + +* win,build: support building with VS2017 (Refael Ackermann) + +* doc: add instructions for building on Windows (Refael Ackermann) + +* doc: format README (Refael Ackermann) + + +2017.05.31, Version 1.12.0 (Stable), d6ac141ac674657049598c36604f26e031fae917 + +Changes since version 1.11.0: + +* Now working on version 1.11.1 (cjihrig) + +* test: fix tests on OpenBSD (Santiago Gimeno) + +* test: fix -Wformat warning (Santiago Gimeno) + +* win,fs: avoid double freeing uv_fs_event_t.dirw (Vladimir Matveev) + +* unix: remove unused code in `uv__io_start` (Fedor Indutny) + +* signal: add uv_signal_start_oneshot method (Santiago Gimeno) + +* unix: factor out reusable POSIX hrtime impl (Brad King) + +* unix,win: add uv_os_{get,set,unset}env() (cjihrig) + +* win: add uv__convert_utf8_to_utf16() (cjihrig) + +* docs: improve UV_ENOBUFS scenario documentation (cjihrig) + +* unix: return UV_EINVAL for NULL env name (jBarz) + +* unix: filter getifaddrs results consistently (Brad King) + +* unix: factor out getifaddrs result filter (Brad King) + +* unix: factor out reusable BSD ifaddrs impl (Brad King) + +* unix: use union to follow strict aliasing rules (jBarz) + +* unix: simplify async watcher dispatch logic (Ben Noordhuis) + +* samples: update timer callback prototype (Ben Noordhuis) + +* unix: make loops and watchers usable after fork() (Jason Madden) + +* win: free uv__loops once empty (cjihrig) + +* tools: add make_dist_html.py script (Ben Noordhuis) + +* win,sunos: stop handle on uv_fs_event_start() err (cjihrig) + +* unix,windows: refactor request init logic (Ben Noordhuis) + +* win: fix memory leak inside uv__pipe_getname (A. Hauptmann) + +* fsevent: support for files without short name (Bartosz Sosnowski) + +* doc: fix multiple doc typos (Jamie Davis) + +* test,osx: fix flaky kill test (Santiago Gimeno) + +* unix: inline uv_pipe_bind() err_bind goto target (cjihrig) + +* unix,test: deadstore fixes (Rasmus Christian Pedersen) + +* win: fix memory leak inside uv_fs_access() (A. Hauptmann) + +* doc: fix docs/src/fs.rst build warning (Daniel Bevenius) + +* doc: minor grammar fix in Installation section (Daniel Bevenius) + +* doc: suggestions for design page (Daniel Bevenius) + +* doc: libuv does not touch uv_loop_t.data (Ben Noordhuis) + +* github: add ISSUE_TEMPLATE.md (Ben Noordhuis) + +* doc: add link to libuv/help to README (Ben Noordhuis) + +* udp: fix fast path in uv_udp_send() on unix (Fedor Indutny) + +* test: add test for uv_udp_send() fix (Trevor Norris) + +* doc: fix documentation for uv_handle_t.type (Daniel Kahn Gillmor) + +* zos: use proper prototype for epoll_init() (Ben Noordhuis) + +* doc: rename docs to "libuv documentation" (Saúl Ibarra Corretgé) + +* doc: update copyright years (Saúl Ibarra Corretgé) + +* doc: move TOC to a dedicated document (Saúl Ibarra Corretgé) + +* doc: move documentation section up (Saúl Ibarra Corretgé) + +* doc: move "upgrading" to a standalone document (Saúl Ibarra Corretgé) + +* doc: add initial version of the User Guide (Saúl Ibarra Corretgé) + +* doc: removed unused file (Saúl Ibarra Corretgé) + +* doc: update guide/about and mention new maintainership (Saúl Ibarra Corretgé) + +* doc: remove licensing note from guide/about (Saúl Ibarra Corretgé) + +* doc: add warning note to user guide (Saúl Ibarra Corretgé) + +* doc: change license to CC BY 4.0 (Saúl Ibarra Corretgé) + +* doc: remove ubvook reference from README (Saúl Ibarra Corretgé) + +* doc: add code samples from uvbook (unadapted) (Saúl Ibarra Corretgé) + +* doc: update supported linux/glibc baseline (Ben Noordhuis) + +* win: avoid leaking pipe handles to child processes (Jameson Nash) + +* win,test: support stdout output larger than 1kb (Bartosz Sosnowski) + +* win: remove __declspec(inline) from atomic op (Keane) + +* test: fix VC++ compilation warning (Rasmus Christian Pedersen) + +* build: add -Wstrict-prototypes (Jameson Nash) + +* zos: implement uv__io_fork, skip fs event tests (jBarz) + +* unix: do not close udp sockets on bind error (Marc Schlaich) + +* unix: remove FSEventStreamFlushSync() call (cjihrig) + +* build,openbsd: remove kvm-related code (James McCoy) + +* test: fix flaky tcp-write-queue-order (Santiago Gimeno) + +* unix,win: add uv_os_gethostname() (cjihrig) + +* zos: increase timeout for tcp_writealot (jBarz) + +* zos: do not inline OOB data by default (jBarz) + +* test: fix -Wstrict-prototypes compiler warnings (Ben Noordhuis) + +* unix: factor out reusable no-proctitle impl (Brad King) + +* test: factor out fsevents skip explanation (Brad King) + +* test: skip fork fsevent cases when lacking support (Brad King) + +* unix: factor out reusable no-fsevents impl (Brad King) + +* unix: factor out reusable sysinfo memory lookup (Brad King) + +* unix: factor out reusable sysinfo loadavg impl (Brad King) + +* unix: factor out reusable procfs exepath impl (Brad King) + +* unix: add a uv__io_poll impl using POSIX poll(2) (Brad King) + +* cygwin: implement support for cygwin and msys2 (Brad King) + +* cygwin: recognize EOF on named pipe closure (Brad King) + +* cygwin: fix uv_pipe_connect report of ENOTSOCK (Brad King) + +* cygwin: disable non-functional ipc handle send (Brad King) + +* test: skip self-connecting tests on cygwin (Brad King) + +* doc: mark uv_loop_fork() as experimental (cjihrig) + +* doc: add bzoz to maintainers (Bartosz Sosnowski) + +* doc: fix memory leak in tcp-echo-server example (Bernardo Ramos) + +* win: make uv__get_osfhandle() public (Juan Cruz Viotti) + +* doc: use valid pipe name in pipe-echo-server (Bernardo Ramos) + + +2017.02.02, Version 1.11.0 (Stable), 7452ef4e06a4f99ee26b694c65476401534f2725 + +Changes since version 1.10.2: + +* Now working on version 1.10.3 (cjihrig) + +* win: added fcntl.h to uv-win.h (Michele Caini) + +* unix: move function call out of assert (jBarz) + +* fs: cleanup uv__fs_scandir (Santiago Gimeno) + +* fs: fix crash in uv_fs_scandir_next (muflub) + +* win,signal: fix potential deadlock (Bartosz Sosnowski) + +* unix: use async-signal safe functions between fork and exec (jBarz) + +* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) + +* zos: make platform functional (John Barboza) + +* doc: add repitition qualifier to version regexs (Daniel Bevenius) + +* zos: use gyp OS label "os390" on z/OS (John Barboza) + +* aix: enable uv_get/set_process_title (Howard Hellyer) + +* zos: use built-in proctitle implementation (John Barboza) + +* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) + +* win,test: don't write uninitialized buffer to tty (Bert Belder) + +* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) + +* aix: re-enable fs watch facility (Gireesh Punathil) + + +2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 + +Changes since version 1.10.1: + +* Now working on version 1.10.2 (cjihrig) + +* darwin: fix fsync and fdatasync (Joran Dirk Greef) + +* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" + (Santiago Gimeno) + +* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) + +* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) + +* win: fix comment in quote_cmd_arg (Eric Sciple) + +* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) + +* win, tty: fix crash on restarting with pending data (Nicholas Vavilov) + +* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) + +* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) + +* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) + + +2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 + +Changes since version 1.10.0: + +* Now working on version 1.10.1 (cjihrig) + +* win: fix anonymous union syntax (Brad King) + +* unix: use uv__is_closing everywhere (Santiago Gimeno) + +* win: add missing break statement (cjihrig) + +* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) + +* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) + +* doc: add cjihrig alternative GPG ID (cjihrig) + +* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) + + +2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 + +Changes since version 1.9.1: + +* Now working on version 1.9.2 (Saúl Ibarra Corretgé) + +* doc: add cjihrig GPG ID (cjihrig) + +* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) + +* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra + Corretgé) + +* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) + +* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) + +* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) + +* license: libuv is no longer a Node project (Saúl Ibarra Corretgé) + +* license: add license text we've been using for a while (Saúl Ibarra Corretgé) + +* doc: add licensing information to README (Saúl Ibarra Corretgé) + +* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) + +* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) + +* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) + +* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) + +* doc: update docs with AIX related information (Imran Iqbal) + +* test: silence build warnings (Kári Tristan Helgason) + +* doc: add iWuzHere GPG ID (Imran Iqbal) + +* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) + +* build: fix build on DragonFly (Michael Neumann) + +* unix: correctly detect named pipes on DragonFly (Michael Neumann) + +* test: make tap output the default (Ben Noordhuis) + +* test: don't dump output for skipped tests (Ben Noordhuis) + +* test: improve formatting of diagnostic messages (Ben Noordhuis) + +* test: remove unused RETURN_TODO macro (Ben Noordhuis) + +* doc: fix stream typos (Pierre-Marie de Rodat) + +* doc: update coding style link (Imran Iqbal) + +* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) + +* build: check for warnings for -fvisibility=hidden (Imran Iqbal) + +* unix: remove unneeded TODO note (Saúl Ibarra Corretgé) + +* test: skip tty_pty test if pty is not available (Luca Bruno) + +* sunos: set phys_addr of interface_address using ARP (Brian Maher) + +* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) + +* unix: don't convert stat buffer when syscall fails (Ben Noordhuis) + +* win: compare entire filename in watch events (cjihrig) + +* doc: add a note on safe reuse of uv_write_t (neevek) + +* linux: fix potential event loop stall (Ben Noordhuis) + +* unix,win: make uv_get_process_title() stricter (cjihrig) + +* test: close server before initiating new connection (John Barboza) + +* test: account for multiple handles in one ipc read (John Barboza) + +* unix: fix errno and retval conflict (liuxiaobo) + +* doc: add missing entry in uv_fs_type enum (Michele Caini) + +* unix: preserve loop->data across loop init/done (Ben Noordhuis) + +* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) + +* win: simplify memory copy logic in fs.c (Ben Noordhuis) + +* win: fix compilation on mingw (Bartosz Sosnowski) + +* win: ensure 32-bit printf precision (Matej Knopp) + +* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) + +* test: fix OOB buffer access (Saúl Ibarra Corretgé) + +* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) + +* test: fix android build error. (sunjin.lee) + +* win: evaluate timers when system wakes up (Bartosz Sosnowski) + +* doc: add supported platforms description (Saúl Ibarra Corretgé) + +* win: fix lstat reparse point without link data (Jason Ginchereau) + +* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) + +* zos: add support for new platform (John Barboza) + +* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) + +* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) + +* build: GNU/kFreeBSD support (Jeffrey Clark) + +* zos: use PLO instruction for atomic operations (John Barboza) + +* zos: use pthread helper functions (John Barboza) + +* zos: implement uv__fs_futime (John Barboza) + +* unix: expand range of values for usleep (John Barboza) + +* zos: track unbound handles and bind before listen (John Barboza) + +* test: improve tap output on test failures (Santiago Gimeno) + +* test: refactor fs_event_close_in_callback (Julien Gilli) + +* zos: implement uv__io_check_fd (John Barboza) + +* unix: unneccessary use const qualifier in container_of (John Barboza) + +* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) + +* doc: add santigimeno to maintainers (Santiago Gimeno) + +* win: fix typo in type name (Saúl Ibarra Corretgé) + +* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) + +* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) + +* win: add disk read/write count to uv_getrusage (Imran Iqbal) + +* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) + +* test: improve spawn_setuid_setgid test (Santiago Gimeno) + +* test: fix building pty test on Android (Saúl Ibarra Corretgé) + +* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) + +* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) + +* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) + +* doc: update supported fields for uv_rusage_t (Imran Iqbal) + +* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) + +* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) + +* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) + +* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) + +* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) + +* doc: add ABI tracker link to README (Saúl Ibarra Corretgé) + +* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) + +* test: fix fs_fstat on Android (Vit Gottwald) + +* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) + +* doc: add description of uv_handle_type (Vit Gottwald) + +* build: use -pthreads for tests with autotools (Julien Gilli) + +* win: fix leaky fs request buffer (Jason Ginchereau) + +* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) + +* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) + +* win: fix winapi function pointer typedef syntax (Brad King) + +* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) + +* test: make threadpool_cancel_single deterministic (Ben Noordhuis) + +* test: make threadpool saturation reliable (Ben Noordhuis) + +* unix: don't malloc in uv_thread_create() (Ben Noordhuis) + +* unix: don't include CoreServices globally on macOS (Brad King) + +* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) + +* win: remove unused static variables (Ben Noordhuis) + +* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) + +* signal: replace pthread_once with uv_once (Santiago Gimeno) + +* test: fix sign-compare warning (Will Speak) + +* common: fix unused variable warning (Brad King) + + +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c + +Changes since version 1.9.0: + +* test: handle root home directories (cjihrig) + +* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) + +* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) + +* win: fix var declaration to be C89 compliant (Michael Fero) + +* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) + +* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) + +* Revert "win,build: remove unused build defines" (cjihrig) + +* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) + +* linux: don't abort on malformed /proc/stat (Ben Noordhuis) + +* linux: fix long lines in linux-core.c (Ben Noordhuis) + +* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) + +* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) + +* unix: delay signal handling until after normal i/o (Ben Noordhuis) + +* android: pthread_sigmask() does not set errno (Oguz Bastemur) + +* win: work around sharepoint scandir bug (Ben Noordhuis) + +* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) + +* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) + +* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) + +* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) + +* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) + +* unix: error on realpath if PATH_MAX is undefined (Myles Borins) + +* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) + +* build: bump android ndk version (Kári Tristan Helgason) + +* build: always compile with -fvisibility=hidden (Ben Noordhuis) + +* test: fix -Wformat warnings in platform test (Ben Noordhuis) + +* win: clarify fsevents handling code (Saúl Ibarra Corretgé) + +* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) + +* build, mingw: set LIBS in configure.ac (Tony Theodore) + +* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) + +* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* darwin: work around condition variable kernel bug (Ben Noordhuis) + +* darwin: make thread stack multiple of page size (Ben Noordhuis) + +* build,win: rename platform to msbuild_platform (João Reis) + +* gitignore: ignore VS temporary database files (João Reis) + +* test: skip emfile on AIX (Imran Iqbal) + +* unix: use system allocator for scandir() (cjihrig) + +* common: release uv_fs_scandir() array (cjihrig) + +* win: call uv__fs_scandir_cleanup() (cjihrig) + +* win,tty: fix read stop in line mode (João Reis) + +* win,tty: don't duplicate handle for line reads (João Reis) + +* win,tty: restore cursor after canceling line read (Alexis Campailla) + + +2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 + +Changes since version 1.8.0: + +* win: wait for full timeout duration (João Reis) + +* unix: fix support for uClibc-ng (Martin Bark) + +* doc: indicate where new test files need to be added (Dave) + +* test,unix: fix logic error in test runner (Ben Noordhuis) + +* fs: don't nullify req->bufs on EINTR (Dave) + +* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) + +* build: invoke libtoolize with --copy (Ben Noordhuis) + +* test: fixup eintr_handling (Saúl Ibarra Corretgé) + +* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) + +* test,win: fix compilation with shared lib (Alexis Murzeau) + +* test: fix race condition in pipe-close-stdout (Imran Iqbal) + +* unix,win: add uv_os_tmpdir() (cjihrig) + +* ios: fix undefined PTHREAD_STACK_MIN (Didiet) + +* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) + +* unix: report errors for unpollable fds (Ben Noordhuis) + +* win: fix watching root files (Nicholas Vavilov) + +* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) + +* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) + +* test,win: fix compilation warning (Saúl Ibarra Corretgé) + +* test: use uv_loop_close and assert its result (Nan Xiang) + +* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) + +* osx: protected use of potentially undefined macro (Samuel Lorétan) + +* linux: fix compilation with musl (Saúl Ibarra Corretgé) + +* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) + +* doc: add missing link in README (Saúl Ibarra Corretgé) + +* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) + +* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) + +* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) + +* doc: add missing write callback to example (Nándor István Krácser) + +* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) + +* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) + +* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) + +* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) + +* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) + +* linux: fix cpu count (Lukasz Jagiello) + +* unix: fix uv__handle_type for AIX (Imran Iqbal) + +* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* unix: fix compile error in Android using bionic (Robert Chiras) + +* linux: add braces to multi-statement if (Kári Tristan Helgason) + +* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) + +* unix: add fork-safe open file function (Kári Tristan Helgason) + +* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) + +* linux: remove redundant call to rewind() (Krishnaraj Bhat) + +* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) + +* test: fix poll_bad_fdtype for AIX (Imran Iqbal) + +* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) + +* poll: add UV_DISCONNECT event (Santiago Gimeno) + +* fs: realpath: fix string size before converting (Yuval Brik) + +* win: use native APIs for UTF conversions (cjihrig) + +* doc: clarify uv_loop_close() (Ben Noordhuis) + +* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) + +* win,build: remove unused build defines (Saúl Ibarra Corretgé) + +* win: fix buffer overflow in fs events (Joran Dirk Greef) + +* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) + +* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) + +* test: add missing copyright header (cjihrig) + +* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) + +* unix,win: add uv_get_passwd() (cjihrig) + +* process: fix uv_spawn edge-case (Santiago Gimeno) + +* test: use %ld for printing uid/gid (Ben Noordhuis) + +* aix: fix ahafs implementation (Imran Iqbal) + +* aix: do not store absolute path to ahafs (Imran Iqbal) + +* process: close process pipes safely (Santiago Gimeno) + +* unix: open ttyname instead of /dev/tty (Enno Boland) + +* unix: remove outdated comment (Kári Tristan Helgason) + + +2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 + +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/3rd/libuv-1.19.2/LICENSE b/3rd/libuv-1.19.2/LICENSE new file mode 100644 index 00000000..28f17339 --- /dev/null +++ b/3rd/libuv-1.19.2/LICENSE @@ -0,0 +1,70 @@ +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +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 parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +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.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/3rd/libuv-1.19.2/LICENSE-docs b/3rd/libuv-1.19.2/LICENSE-docs new file mode 100644 index 00000000..53883b1c --- /dev/null +++ b/3rd/libuv-1.19.2/LICENSE-docs @@ -0,0 +1,396 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/3rd/libuv-1.19.2/MAINTAINERS.md b/3rd/libuv-1.19.2/MAINTAINERS.md new file mode 100644 index 00000000..d85deb00 --- /dev/null +++ b/3rd/libuv-1.19.2/MAINTAINERS.md @@ -0,0 +1,43 @@ + +# Project Maintainers + +libuv is currently managed by the following individuals: + +* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) +* **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)) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) +* **Fedor Indutny** ([@indutny](https://github.com/indutny)) + - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) +* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) + - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) +* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) + - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) +* **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/3rd/libuv-1.19.2/Makefile.am b/3rd/libuv-1.19.2/Makefile.am new file mode 100644 index 00000000..ae9d96bc --- /dev/null +++ b/3rd/libuv-1.19.2/Makefile.am @@ -0,0 +1,468 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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-data-getter-setters.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 += -pthreads +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 +libuv_la_SOURCES += src/win/async.c \ + src/win/atomicops-inl.h \ + src/win/core.c \ + src/win/detect-wakeup.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 +if OS390 +test_run_tests_CFLAGS = +else +test_run_tests_CFLAGS = -Wno-long-long +endif + +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. +test_run_tests_CFLAGS += -pthreads +endif + +test_run_tests_LDFLAGS = +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-connect-unspecified.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-eintr-handling.c \ + test/test-embed.c \ + test/test-emfile.c \ + test/test-env-vars.c \ + test/test-error.c \ + test/test-fail-always.c \ + test/test-fs-copyfile.c \ + test/test-fs-event.c \ + test/test-fs-poll.c \ + test/test-fs.c \ + test/test-fork.c \ + test/test-getters-setters.c \ + test/test-get-currentexe.c \ + test/test-get-loadavg.c \ + test/test-get-memory.c \ + test/test-get-passwd.c \ + test/test-getaddrinfo.c \ + test/test-gethostname.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-pipe-set-fchmod.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-poll-oob.c \ + test/test-process-title.c \ + test/test-process-title-threadsafe.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-alloc-cb-fail.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-tmpdir.c \ + test/test-tty.c \ + test/test-udp-alloc-cb-fail.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-hang-loop.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 LINUX +test_run_tests_CFLAGS += -D_GNU_SOURCE +endif + +if SUNOS +test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +endif + +if OS390 +test_run_tests_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_FILE_EXT \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +endif + +if AIX +libuv_la_CFLAGS += -D_ALL_SOURCE \ + -D_XOPEN_SOURCE=500 \ + -D_LINUX_SOURCE_COMPAT \ + -D_THREAD_SAFE \ + -DHAVE_SYS_AHAFS_EVPRODS_H +include_HEADERS += include/uv-aix.h +libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c +endif + +if ANDROID +include_HEADERS += include/android-ifaddrs.h \ + include/pthread-barrier.h +libuv_la_SOURCES += src/unix/android-ifaddrs.c \ + src/unix/pthread-fixes.c +endif + +if CYGWIN +include_HEADERS += include/uv-posix.h +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_SOURCES += src/unix/cygwin.c \ + src/unix/bsd-ifaddrs.c \ + src/unix/no-fsevents.c \ + src/unix/no-proctitle.c \ + src/unix/posix-hrtime.c \ + src/unix/posix-poll.c \ + src/unix/procfs-exepath.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +endif + +if DARWIN +include_HEADERS += include/uv-darwin.h \ + include/pthread-barrier.h +libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 +libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/darwin.c \ + src/unix/darwin-proctitle.c \ + src/unix/fsevents.c \ + src/unix/kqueue.c \ + src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil +endif + +if DRAGONFLY +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if FREEBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +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/procfs-exepath.c \ + src/unix/proctitle.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +test_run_tests_LDFLAGS += -lutil +endif + +if MSYS +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_SOURCES += src/unix/cygwin.c \ + src/unix/bsd-ifaddrs.c \ + src/unix/no-fsevents.c \ + src/unix/no-proctitle.c \ + src/unix/posix-hrtime.c \ + src/unix/posix-poll.c \ + src/unix/procfs-exepath.c \ + src/unix/sysinfo-loadavg.c \ + src/unix/sysinfo-memory.c +endif + +if NETBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ + src/unix/netbsd.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if OPENBSD +include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ + src/unix/openbsd.c \ + src/unix/posix-hrtime.c +test_run_tests_LDFLAGS += -lutil +endif + +if SUNOS +include_HEADERS += include/uv-sunos.h +libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +libuv_la_SOURCES += src/unix/no-proctitle.c \ + src/unix/sunos.c +endif + +if OS390 +include_HEADERS += include/pthread-barrier.h +libuv_la_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_SYS_FILE_EXT \ + -DUV_PLATFORM_SEM_T=int \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +libuv_la_LDFLAGS += -qXPLINK +libuv_la_SOURCES += src/unix/pthread-fixes.c \ + src/unix/os390.c \ + src/unix/os390-syscalls.c \ + src/unix/proctitle.c +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/3rd/libuv-1.19.2/Makefile.mingw b/3rd/libuv-1.19.2/Makefile.mingw new file mode 100644 index 00000000..3acf9e14 --- /dev/null +++ b/3rd/libuv-1.19.2/Makefile.mingw @@ -0,0 +1,86 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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 \ + -Wstrict-prototypes \ + -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/detect-wakeup.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/3rd/libuv-1.19.2/README.md b/3rd/libuv-1.19.2/README.md new file mode 100644 index 00000000..733171be --- /dev/null +++ b/3rd/libuv-1.19.2/README.md @@ -0,0 +1,332 @@ +![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][], 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. + +The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/). + +## Licensing + +libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). +The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-docs file](LICENSE-docs). + +## Community + + * [Support](https://github.com/libuv/help) + * [Mailing list](http://groups.google.com/group/libuv) + * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) + +## Documentation + +### Official 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: + +```bash +$ make help +``` + +Build documentation as HTML: + +```bash +$ make html +``` + +Build documentation as HTML and live reload it when it changes (this requires +sphinx-autobuild to be installed and is only supported on Unix): + +```bash +$ make livehtml +``` + +Build documentation as man pages: + +```bash +$ make man +``` + +Build documentation as ePub: + +```bash +$ 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 + + * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) + — High-level introductory talk about libuv. + * [libuv-dox](https://github.com/thlorenz/libuv-dox) + — Documenting types and methods of libuv, mostly by reading uv.h. + * [learnuv](https://github.com/thlorenz/learnuv) + — 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: + +```bash +$ gpg --keyserver pool.sks-keyservers.net --recv-keys AE9BC059 +``` + +Importing a key from a git blob object: + +```bash +$ git show pubkey-saghul | gpg --import +``` + +### Verifying releases + +Git tags are signed with the developer's key, they can be verified as follows: + +```bash +$ 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: + +```bash +$ 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: + +```bash +$ sh autogen.sh +$ ./configure +$ make +$ make check +$ make install +``` + +### Windows + +Prerequisites: + +* [Python 2.6 or 2.7][] 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` +* One of: + * [Visual C++ Build Tools][] + * [Visual Studio 2015 Update 3][], all editions + including the Community edition (remember to select + "Common Tools for Visual C++ 2015" feature during installation). + * [Visual Studio 2017][], any edition (including the Build Tools SKU). + **Required Components:** "MSbuild", "VC++ 2017 v141 toolset" and one of the + Windows SDKs (10 or 8.1). +* Basic Unix tools required for some tests, + [Git for Windows][] includes Git Bash + and tools which can be included in the global `PATH`. + +To build, launch a git shell (e.g. Cmd or PowerShell), run `vcbuild.bat` +(to build with VS2017 you need to explicitly add a `vs2017` argument), +which will checkout the GYP code into `build/gyp`, generate `uv.sln` +as well as the necesery related project files, and start building. + +```console +> vcbuild +``` + +Or: + +```console +> vcbuild vs2017 +``` + +To run the tests: + +```console +> vcbuild test +``` + +To see all the options that could passed to `vcbuild`: + +```console +> vcbuild help +vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] +Examples: + vcbuild.bat : builds debug build + vcbuild.bat test : builds debug build and runs tests + vcbuild.bat release bench: builds release build and runs benchmarks +``` + + +### Unix + +For Debug builds (recommended) run: + +```bash +$ ./gyp_uv.py -f make +$ make -C out +``` + +For Release builds run: + +```bash +$ ./gyp_uv.py -f make +$ BUILDTYPE=Release make -C out +``` + +Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. + +### OS X + +Run: + +```bash +$ ./gyp_uv.py -f xcode +$ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ + -configuration Release -target All +``` + +Using Homebrew: + +```bash +$ 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: + +```bash +$ source ./android-configure NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +The default API level is 24, but a different one can be selected as follows: + +```bash +$ source ./android-configure ~/android-ndk-r15b gyp 21 +$ 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: + +```bash +$ ./gyp_uv.py -f ninja +$ ninja -C out/Debug #for debug build OR +$ ninja -C out/Release +``` + + +### Running tests + +Run: + +```bash +$ ./gyp_uv.py -f make +$ make -C out +$ ./out/Debug/run-tests +``` + +## Supported Platforms + +Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). + +### 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/ +[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md +[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png +[x32]: https://en.wikipedia.org/wiki/X32_ABI +[Python 2.6 or 2.7]: https://www.python.org/downloads/ +[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools +[Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ +[Visual Studio 2017]: https://www.visualstudio.com/downloads/ +[Git for Windows]: http://git-scm.com/download/win diff --git a/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md b/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md new file mode 100644 index 00000000..07719108 --- /dev/null +++ b/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md @@ -0,0 +1,73 @@ +# Supported platforms + +| System | Support type | Supported versions | Notes | +|---|---|---|---| +| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | +| macOS | Tier 1 | macOS >= 10.7 | | +| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported | +| FreeBSD | Tier 1 | >= 9 (see note) | | +| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | +| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | +| Linux with musl | Tier 2 | musl >= 1.0 | | +| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | +| Android | Tier 3 | NDK >= r15b | | +| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | +| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| SunOS | Tier 3 | Solaris 121 and later | | +| Other | Tier 3 | N/A | | + +#### Note on FreeBSD 9 + +While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until +it reaches end of life, in December 2016. + +## Support types + +* **Tier 1**: Officially supported and tested with CI. Any contributed patch + MUST NOT break such systems. These are supported by @libuv/collaborators. + +* **Tier 2**: Officially supported, but not necessarily tested with CI. These + systems are maintained to the best of @libuv/collaborators ability, + without being a top priority. + +* **Tier 3**: Community maintained. These systems may inadvertently break and the + community and interested parties are expected to help with the maintenance. + +## Adding support for a new platform + +**IMPORTANT**: Before attempting to add support for a new platform please open +an issue about it for discussion. + +### Unix + +I/O handling is abstracted by an internal `uv__io_t` handle. The new platform +will need to implement some of the functions, the prototypes are in +``src/unix/internal.h``. + +If the new platform requires extra fields for any handle structure, create a +new include file in ``include/`` with the name ``uv-theplatform.h`` and add +the appropriate defines there. + +All functionality related to the new platform must be implemented in its own +file inside ``src/unix/`` unless it's already done in a common file, in which +case adding an `ifdef` is fine. + +Two build systems are supported: autotools and GYP. Ideally both need to be +supported, but if GYP does not support the new platform it can be left out. + +### Windows + +Windows is treated as a single platform, so adding support for a new platform +would mean adding support for a new version. + +Compilation and runtime must succeed for the minimum supported version. If a +new API is to be used, it must be done optionally, only in supported versions. + +### Common + +Some common notes when adding support for new platforms: + +* Generally libuv tries to avoid compile time checks. Do not add any to the + autotools based build system or use version checking macros. + Dynamically load functions and symbols if they are not supported by the + minimum supported version. diff --git a/3rd/libuv-1.19.2/android-configure b/3rd/libuv-1.19.2/android-configure new file mode 100644 index 00000000..b5c11cd4 --- /dev/null +++ b/3rd/libuv-1.19.2/android-configure @@ -0,0 +1,23 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain +mkdir -p $TOOLCHAIN +API=${3:-24} +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=arm-linux-androideabi-4.9 \ + --arch=arm \ + --install-dir=$TOOLCHAIN \ + --platform=android-$API \ + --force +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 +export CFLAGS="-D__ANDROID_API__=$API" + +if [[ $2 == 'gyp' ]] + then + ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android +fi diff --git a/3rd/libuv-1.19.2/appveyor.yml b/3rd/libuv-1.19.2/appveyor.yml new file mode 100644 index 00000000..1b018a59 --- /dev/null +++ b/3rd/libuv-1.19.2/appveyor.yml @@ -0,0 +1,32 @@ +version: v1.18.0.build{build} + +init: + - git config --global core.autocrlf true + +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 + +cache: + - C:\projects\libuv\build\gyp diff --git a/3rd/libuv-1.19.2/autogen.sh b/3rd/libuv-1.19.2/autogen.sh new file mode 100644 index 00000000..271c2ee8 --- /dev/null +++ b/3rd/libuv-1.19.2/autogen.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# 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" --copy +"$ACLOCAL" -I m4 +"$AUTOCONF" +"$AUTOMAKE" --add-missing --copy diff --git a/3rd/libuv-1.19.2/checksparse.sh b/3rd/libuv-1.19.2/checksparse.sh new file mode 100644 index 00000000..27eb529b --- /dev/null +++ b/3rd/libuv-1.19.2/checksparse.sh @@ -0,0 +1,253 @@ +#!/bin/sh + +# Copyright (c) 2013, Ben Noordhuis +# +# 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 +src/uv-data-getter-setters.c +" + +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-env-vars.c +test/test-error.c +test/test-fail-always.c +test/test-fs-copyfile.c +test/test-fs-event.c +test/test-fs-poll.c +test/test-fs.c +test/test-getters-setters.c +test/test-get-currentexe.c +test/test-get-loadavg.c +test/test-get-memory.c +test/test-get-passwd.c +test/test-getaddrinfo.c +test/test-gethostname.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-process-title-threadsafe.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-tmpdir.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-udp-send-hang-loop.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-common.c + src/unix/aix.c" + ;; +OS400) + SPARSE_FLAGS="$SPARSE_FLAGS -D_PASE=1" + SOURCES="$SOURCES + src/unix/aix-common.c + src/unix/ibmi.c + src/unix/posix-poll.c + src/unix/no-fsevents.c + src/unix/no-proctitle.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/3rd/libuv-1.19.2/common.gypi b/3rd/libuv-1.19.2/common.gypi new file mode 100644 index 00000000..572a1633 --- /dev/null +++ b/3rd/libuv-1.19.2/common.gypi @@ -0,0 +1,208 @@ +{ + 'variables': { + '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' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['uv_library=="static_library"', { + 'RuntimeLibrary': 1, # /MTd static debug + }, { + 'RuntimeLibrary': 3, # /MDd 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', + }, + 'conditions': [ + ['OS != "zos"', { + 'cflags': [ '-O0', '-fwrapv' ] + }], + ['OS == "android"', { + 'cflags': [ '-fPIE' ], + 'ldflags': [ '-fPIE', '-pie' ] + }] + ] + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'cflags': [ + '-O3', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'target_conditions': [ + ['uv_library=="static_library"', { + 'RuntimeLibrary': 0, # /MT static release + }, { + 'RuntimeLibrary': 2, # /MD DLL 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 + }, + }, + 'conditions': [ + ['OS != "zos"', { + 'cflags': [ + '-fomit-frame-pointer', + '-fdata-sections', + '-ffunction-sections', + ], + }], + ] + } + }, + '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 zos"', { + 'cflags': [ '-pthread' ], + 'ldflags': [ '-pthread' ], + }], + ], + }], + ['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_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'PREBINDING': 'NO', # No -Wl,-prebind + 'USE_HEADERMAP': 'NO', + 'WARNING_CFLAGS': [ + '-Wall', + '-Wendif-labels', + '-W', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + }, + '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/3rd/libuv-1.19.2/configure.ac b/3rd/libuv-1.19.2/configure.ac new file mode 100644 index 00000000..4074e778 --- /dev/null +++ b/3rd/libuv-1.19.2/configure.ac @@ -0,0 +1,72 @@ +# Copyright (c) 2013, Ben Noordhuis +# +# 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.19.2], [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 +AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) +]) +CC_FLAG_VISIBILITY #[-fvisibility=hidden] +CC_CHECK_CFLAGS_APPEND([-g]) +CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-Wall]) +CC_CHECK_CFLAGS_APPEND([-Wextra]) +CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) +CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) +# 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([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([CYGWIN], [AS_CASE([$host_os],[cygwin*], [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([MSYS], [AS_CASE([$host_os],[msys*], [true], [false])]) +AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) +AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) +AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])]) +AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) +AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) +AS_CASE([$host_os],[mingw*], [ + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" +]) +AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) +AC_CHECK_HEADERS([sys/ahafs_evProds.h]) +AC_CONFIG_FILES([Makefile libuv.pc]) +AC_OUTPUT diff --git a/3rd/libuv-1.19.2/docs/code/cgi/main.c b/3rd/libuv-1.19.2/docs/code/cgi/main.c new file mode 100644 index 00000000..d2e34265 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/cgi/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req->data, NULL); + uv_close((uv_handle_t*) req, NULL); +} + +void invoke_cgi_script(uv_tcp_t *client) { + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("cgi")), "tick"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... finding the executable path and setting up arguments ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_INHERIT_STREAM; + child_stdio[1].data.stream = (uv_stream_t*) client; + child_stdio[2].flags = UV_IGNORE; + options.stdio = child_stdio; + + options.exit_cb = cleanup_handles; + options.file = args[0]; + options.args = args; + + // Set this so we can close the socket after the child process exits. + child_req.data = (void*) client; + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return; + } +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + invoke_cgi_script(client); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/cgi/tick.c b/3rd/libuv-1.19.2/docs/code/cgi/tick.c new file mode 100644 index 00000000..0b498edf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/cgi/tick.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + int i; + for (i = 0; i < 10; i++) { + printf("tick\n"); + fflush(stdout); + sleep(1); + } + printf("BOOM!\n"); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/detach/main.c b/3rd/libuv-1.19.2/docs/code/detach/main.c new file mode 100644 index 00000000..3c88fff4 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/detach/main.c @@ -0,0 +1,31 @@ +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "sleep"; + args[1] = "100"; + args[2] = NULL; + + options.exit_cb = NULL; + options.file = "sleep"; + options.args = args; + options.flags = UV_PROCESS_DETACHED; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid); + uv_unref((uv_handle_t*) &child_req); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/dns/main.c b/3rd/libuv-1.19.2/docs/code/dns/main.c new file mode 100644 index 00000000..77a7005f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/dns/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +uv_loop_t *loop; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + free(buf->base); + free(client); + return; + } + + char *data = (char*) malloc(sizeof(char) * (nread+1)); + data[nread] = '\0'; + strncpy(data, buf->base, nread); + + fprintf(stderr, "%s", data); + free(data); + free(buf->base); +} + +void on_connect(uv_connect_t *req, int status) { + if (status < 0) { + fprintf(stderr, "connect failed error %s\n", uv_err_name(status)); + free(req); + return; + } + + uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read); + free(req); +} + +void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { + if (status < 0) { + fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status)); + return; + } + + char addr[17] = {'\0'}; + uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16); + fprintf(stderr, "%s\n", addr); + + uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); + uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect); + + uv_freeaddrinfo(res); +} + +int main() { + loop = uv_default_loop(); + + struct addrinfo hints; + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = 0; + + uv_getaddrinfo_t resolver; + fprintf(stderr, "irc.freenode.net is... "); + int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints); + + if (r) { + fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/helloworld/main.c b/3rd/libuv-1.19.2/docs/code/helloworld/main.c new file mode 100644 index 00000000..a31bf88a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/helloworld/main.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int main() { + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + uv_loop_init(loop); + + printf("Now quitting.\n"); + uv_run(loop, UV_RUN_DEFAULT); + + uv_loop_close(loop); + free(loop); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/idle-basic/main.c b/3rd/libuv-1.19.2/docs/code/idle-basic/main.c new file mode 100644 index 00000000..77ba31cf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/idle-basic/main.c @@ -0,0 +1,24 @@ +#include +#include + +int64_t counter = 0; + +void wait_for_a_while(uv_idle_t* handle) { + counter++; + + if (counter >= 10e6) + uv_idle_stop(handle); +} + +int main() { + uv_idle_t idler; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, wait_for_a_while); + + printf("Idling...\n"); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_loop_close(uv_default_loop()); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/idle-compute/main.c b/3rd/libuv-1.19.2/docs/code/idle-compute/main.c new file mode 100644 index 00000000..ff44b694 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/idle-compute/main.c @@ -0,0 +1,43 @@ +#include + +#include + +uv_loop_t *loop; +uv_fs_t stdin_watcher; +uv_idle_t idler; +char buffer[1024]; + +void crunch_away(uv_idle_t* handle) { + // Compute extra-terrestrial life + // fold proteins + // computer another digit of PI + // or similar + fprintf(stderr, "Computing PI...\n"); + // just to avoid overwhelming your terminal emulator + uv_idle_stop(handle); +} + +void on_type(uv_fs_t *req) { + if (stdin_watcher.result > 0) { + buffer[stdin_watcher.result] = '\0'; + printf("Typed %s\n", buffer); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + } + else if (stdin_watcher.result < 0) { + fprintf(stderr, "error opening file: %s\n", uv_strerror(req->result)); + } +} + +int main() { + loop = uv_default_loop(); + + uv_idle_init(loop, &idler); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/interfaces/main.c b/3rd/libuv-1.19.2/docs/code/interfaces/main.c new file mode 100644 index 00000000..cac12c26 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/interfaces/main.c @@ -0,0 +1,33 @@ +#include +#include + +int main() { + char buf[512]; + uv_interface_address_t *info; + int count, i; + + uv_interface_addresses(&info, &count); + i = count; + + printf("Number of interfaces: %d\n", count); + while (i--) { + uv_interface_address_t interface = info[i]; + + printf("Name: %s\n", interface.name); + printf("Internal? %s\n", interface.is_internal ? "Yes" : "No"); + + if (interface.address.address4.sin_family == AF_INET) { + uv_ip4_name(&interface.address.address4, buf, sizeof(buf)); + printf("IPv4 address: %s\n", buf); + } + else if (interface.address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interface.address.address6, buf, sizeof(buf)); + printf("IPv6 address: %s\n", buf); + } + + printf("\n"); + } + + uv_free_interface_addresses(info, count); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/locks/main.c b/3rd/libuv-1.19.2/docs/code/locks/main.c new file mode 100644 index 00000000..2b1f8ca7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/locks/main.c @@ -0,0 +1,57 @@ +#include +#include + +uv_barrier_t blocker; +uv_rwlock_t numlock; +int shared_num; + +void reader(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_rdlock(&numlock); + printf("Reader %d: acquired lock\n", num); + printf("Reader %d: shared num = %d\n", num, shared_num); + uv_rwlock_rdunlock(&numlock); + printf("Reader %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +void writer(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_wrlock(&numlock); + printf("Writer %d: acquired lock\n", num); + shared_num++; + printf("Writer %d: incremented shared num = %d\n", num, shared_num); + uv_rwlock_wrunlock(&numlock); + printf("Writer %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +int main() +{ + uv_barrier_init(&blocker, 4); + + shared_num = 0; + uv_rwlock_init(&numlock); + + uv_thread_t threads[3]; + + int thread_nums[] = {1, 2, 1}; + uv_thread_create(&threads[0], reader, &thread_nums[0]); + uv_thread_create(&threads[1], reader, &thread_nums[1]); + + uv_thread_create(&threads[2], writer, &thread_nums[2]); + + uv_barrier_wait(&blocker); + uv_barrier_destroy(&blocker); + + uv_rwlock_destroy(&numlock); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js b/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js new file mode 100644 index 00000000..5df345b7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js @@ -0,0 +1,20 @@ +var net = require('net'); + +var PHRASE = "hello world"; +var write = function(socket) { + socket.write(PHRASE, 'utf8'); +} + +for (var i = 0; i < 1000; i++) { +(function() { + var socket = net.connect(7000, 'localhost', function() { + socket.on('data', function(reply) { + if (reply.toString().indexOf(PHRASE) != 0) + console.error("Problem! '" + reply + "'" + " '" + PHRASE + "'"); + else + write(socket); + }); + write(socket); + }); +})(); +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c new file mode 100644 index 00000000..25f49612 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; + +struct child_worker { + uv_process_t req; + uv_process_options_t options; + uv_pipe_t pipe; +} *workers; + +int round_robin_counter; +int child_worker_count; + +uv_buf_t dummy_buf; +char worker_path[500]; + +void close_process_handle(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_write_t *write_req = (uv_write_t*) malloc(sizeof(uv_write_t)); + dummy_buf = uv_buf_init("a", 1); + struct child_worker *worker = &workers[round_robin_counter]; + uv_write2(write_req, (uv_stream_t*) &worker->pipe, &dummy_buf, 1, (uv_stream_t*) client, NULL); + round_robin_counter = (round_robin_counter + 1) % child_worker_count; + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void setup_workers() { + size_t path_size = 500; + uv_exepath(worker_path, &path_size); + strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker"); + fprintf(stderr, "Worker path: %s\n", worker_path); + + char* args[2]; + args[0] = worker_path; + args[1] = NULL; + + round_robin_counter = 0; + + // ... + + // launch same number of workers as number of CPUs + uv_cpu_info_t *info; + int cpu_count; + uv_cpu_info(&info, &cpu_count); + uv_free_cpu_info(info, cpu_count); + + child_worker_count = cpu_count; + + workers = calloc(sizeof(struct child_worker), cpu_count); + while (cpu_count--) { + struct child_worker *worker = &workers[cpu_count]; + uv_pipe_init(loop, &worker->pipe, 1); + + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + + worker->options.stdio = child_stdio; + worker->options.stdio_count = 3; + + worker->options.exit_cb = close_process_handle; + worker->options.file = args[0]; + worker->options.args = args; + + uv_spawn(loop, &worker->req, &worker->options); + fprintf(stderr, "Started worker %d\n", worker->req.pid); + } +} + +int main() { + loop = uv_default_loop(); + + setup_workers(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r; + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c b/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c new file mode 100644 index 00000000..1c465759 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_pipe_t queue; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) q, NULL); + return; + } + + uv_pipe_t *pipe = (uv_pipe_t*) q; + if (!uv_pipe_pending_count(pipe)) { + fprintf(stderr, "No pending count\n"); + return; + } + + uv_handle_type pending = uv_pipe_pending_type(pipe); + assert(pending == UV_TCP); + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(q, (uv_stream_t*) client) == 0) { + uv_os_fd_t fd; + uv_fileno((const uv_handle_t*) client, &fd); + fprintf(stderr, "Worker %d: Accepted fd %d\n", getpid(), fd); + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_init(loop, &queue, 1 /* ipc */); + uv_pipe_open(&queue, 0); + uv_read_start((uv_stream_t*)&queue, alloc_buffer, on_new_connection); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/onchange/main.c b/3rd/libuv-1.19.2/docs/code/onchange/main.c new file mode 100644 index 00000000..40bdaa52 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/onchange/main.c @@ -0,0 +1,44 @@ +#include +#include + +#include + +uv_loop_t *loop; +const char *command; + +void run_command(uv_fs_event_t *handle, const char *filename, int events, int status) { + char path[1024]; + size_t size = 1023; + // Does not handle error if path is longer than 1023. + uv_fs_event_getpath(handle, path, &size); + path[size] = '\0'; + + fprintf(stderr, "Change detected in %s: ", path); + if (events & UV_RENAME) + fprintf(stderr, "renamed"); + if (events & UV_CHANGE) + fprintf(stderr, "changed"); + + fprintf(stderr, " %s\n", filename ? filename : ""); + system(command); +} + +int main(int argc, char **argv) { + if (argc <= 2) { + fprintf(stderr, "Usage: %s [file2 ...]\n", argv[0]); + return 1; + } + + loop = uv_default_loop(); + command = argv[1]; + + while (argc-- > 2) { + fprintf(stderr, "Adding watch on %s\n", argv[argc]); + uv_fs_event_t *fs_event_req = malloc(sizeof(uv_fs_event_t)); + uv_fs_event_init(loop, fs_event_req); + // The recursive flag watches subdirectories too. + uv_fs_event_start(fs_event_req, run_command, argv[argc], UV_FS_EVENT_RECURSIVE); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c new file mode 100644 index 00000000..4f28fd03 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#define PIPENAME "\\\\?\\pipe\\echo.sock" +#else +#define PIPENAME "/tmp/echo.sock" +#endif + +uv_loop_t *loop; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status < 0) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t)); + uv_pipe_init(loop, client, 0); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void remove_sock(int sig) { + uv_fs_t req; + uv_fs_unlink(loop, &req, PIPENAME, NULL); + exit(0); +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_t server; + uv_pipe_init(loop, &server, 0); + + signal(SIGINT, remove_sock); + + int r; + if ((r = uv_pipe_bind(&server, PIPENAME))) { + fprintf(stderr, "Bind error %s\n", uv_err_name(r)); + return 1; + } + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/hello.c b/3rd/libuv-1.19.2/docs/code/plugin/hello.c new file mode 100644 index 00000000..7b2861d7 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/hello.c @@ -0,0 +1,5 @@ +#include "plugin.h" + +void initialize() { + mfp_register("Hello World!"); +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/main.c b/3rd/libuv-1.19.2/docs/code/plugin/main.c new file mode 100644 index 00000000..06e581e6 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/main.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include + +#include "plugin.h" + +typedef void (*init_plugin_function)(); + +void mfp_register(const char *name) { + fprintf(stderr, "Registered plugin \"%s\"\n", name); +} + +int main(int argc, char **argv) { + if (argc == 1) { + fprintf(stderr, "Usage: %s [plugin1] [plugin2] ...\n", argv[0]); + return 0; + } + + uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t)); + while (--argc) { + fprintf(stderr, "Loading %s\n", argv[argc]); + if (uv_dlopen(argv[argc], lib)) { + fprintf(stderr, "Error: %s\n", uv_dlerror(lib)); + continue; + } + + init_plugin_function init_plugin; + if (uv_dlsym(lib, "initialize", (void **) &init_plugin)) { + fprintf(stderr, "dlsym error: %s\n", uv_dlerror(lib)); + continue; + } + + init_plugin(); + } + + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/plugin/plugin.h b/3rd/libuv-1.19.2/docs/code/plugin/plugin.h new file mode 100644 index 00000000..21f194e6 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/plugin/plugin.h @@ -0,0 +1,7 @@ +#ifndef UVBOOK_PLUGIN_SYSTEM +#define UVBOOK_PLUGIN_SYSTEM + +// Plugin authors should use this to register their plugins with mfp. +void mfp_register(const char *name); + +#endif diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/main.c b/3rd/libuv-1.19.2/docs/code/proc-streams/main.c new file mode 100644 index 00000000..b8a65212 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/proc-streams/main.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("proc-streams")), "test"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + options.stdio = child_stdio; + + options.exit_cb = on_exit; + options.file = args[0]; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/test.c b/3rd/libuv-1.19.2/docs/code/proc-streams/test.c new file mode 100644 index 00000000..7c45c1fd --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/proc-streams/test.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + fprintf(stderr, "This is stderr\n"); + printf("This is stdout\n"); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/progress/main.c b/3rd/libuv-1.19.2/docs/code/progress/main.c new file mode 100644 index 00000000..5af01f14 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/progress/main.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_async_t async; + +double percentage; + +void fake_download(uv_work_t *req) { + int size = *((int*) req->data); + int downloaded = 0; + while (downloaded < size) { + percentage = downloaded*100.0/size; + async.data = (void*) &percentage; + uv_async_send(&async); + + sleep(1); + downloaded += (200+random())%1000; // can only download max 1000bytes/sec, + // but at least a 200; + } +} + +void after(uv_work_t *req, int status) { + fprintf(stderr, "Download complete\n"); + uv_close((uv_handle_t*) &async, NULL); +} + +void print_progress(uv_async_t *handle) { + double percentage = *((double*) handle->data); + fprintf(stderr, "Downloaded %.2f%%\n", percentage); +} + +int main() { + loop = uv_default_loop(); + + uv_work_t req; + int size = 10240; + req.data = (void*) &size; + + uv_async_init(loop, &async, print_progress); + uv_queue_work(loop, &req, fake_download, after); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c b/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c new file mode 100644 index 00000000..3f7836cb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; +uv_work_t fib_reqs[FIB_UNTIL]; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + if (status == UV_ECANCELED) + fprintf(stderr, "Calculation of %d cancelled.\n", *(int *) req->data); +} + +void signal_handler(uv_signal_t *req, int signum) +{ + printf("Signal received!\n"); + int i; + for (i = 0; i < FIB_UNTIL; i++) { + uv_cancel((uv_req_t*) &fib_reqs[i]); + } + uv_signal_stop(req); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + fib_reqs[i].data = (void *) &data[i]; + uv_queue_work(loop, &fib_reqs[i], fib, after_fib); + } + + uv_signal_t sig; + uv_signal_init(loop, &sig); + uv_signal_start(&sig, signal_handler, SIGINT); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/queue-work/main.c b/3rd/libuv-1.19.2/docs/code/queue-work/main.c new file mode 100644 index 00000000..55675ea0 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/queue-work/main.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + fprintf(stderr, "Done calculating %dth fibonacci\n", *(int *) req->data); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + uv_work_t req[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + req[i].data = (void *) &data[i]; + uv_queue_work(loop, &req[i], fib, after_fib); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/ref-timer/main.c b/3rd/libuv-1.19.2/docs/code/ref-timer/main.c new file mode 100644 index 00000000..ad7c8295 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/ref-timer/main.c @@ -0,0 +1,29 @@ +#include + +#include + +uv_loop_t *loop; +uv_timer_t gc_req; +uv_timer_t fake_job_req; + +void gc(uv_timer_t *handle) { + fprintf(stderr, "Freeing unused objects\n"); +} + +void fake_job(uv_timer_t *handle) { + fprintf(stdout, "Fake job done\n"); +} + +int main() { + loop = uv_default_loop(); + + uv_timer_init(loop, &gc_req); + uv_unref((uv_handle_t*) &gc_req); + + uv_timer_start(&gc_req, gc, 0, 2000); + + // could actually be a TCP download or something + uv_timer_init(loop, &fake_job_req); + uv_timer_start(&fake_job_req, fake_job, 9000, 0); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/signal/main.c b/3rd/libuv-1.19.2/docs/code/signal/main.c new file mode 100644 index 00000000..1b982c5a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/signal/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +uv_loop_t* create_loop() +{ + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + if (loop) { + uv_loop_init(loop); + } + return loop; +} + +void signal_handler(uv_signal_t *handle, int signum) +{ + printf("Signal received: %d\n", signum); + uv_signal_stop(handle); +} + +// two signal handlers in one loop +void thread1_worker(void *userp) +{ + uv_loop_t *loop1 = create_loop(); + + uv_signal_t sig1a, sig1b; + uv_signal_init(loop1, &sig1a); + uv_signal_start(&sig1a, signal_handler, SIGUSR1); + + uv_signal_init(loop1, &sig1b); + uv_signal_start(&sig1b, signal_handler, SIGUSR1); + + uv_run(loop1, UV_RUN_DEFAULT); +} + +// two signal handlers, each in its own loop +void thread2_worker(void *userp) +{ + uv_loop_t *loop2 = create_loop(); + uv_loop_t *loop3 = create_loop(); + + uv_signal_t sig2; + uv_signal_init(loop2, &sig2); + uv_signal_start(&sig2, signal_handler, SIGUSR1); + + uv_signal_t sig3; + uv_signal_init(loop3, &sig3); + uv_signal_start(&sig3, signal_handler, SIGUSR1); + + while (uv_run(loop2, UV_RUN_NOWAIT) || uv_run(loop3, UV_RUN_NOWAIT)) { + } +} + +int main() +{ + printf("PID %d\n", getpid()); + + uv_thread_t thread1, thread2; + + uv_thread_create(&thread1, thread1_worker, 0); + uv_thread_create(&thread2, thread2_worker, 0); + + uv_thread_join(&thread1); + uv_thread_join(&thread2); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/spawn/main.c b/3rd/libuv-1.19.2/docs/code/spawn/main.c new file mode 100644 index 00000000..dedfe00c --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/spawn/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "mkdir"; + args[1] = "test-dir"; + args[2] = NULL; + + options.exit_cb = on_exit; + options.file = "mkdir"; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } else { + fprintf(stderr, "Launched process with ID %d\n", child_req.pid); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c b/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c new file mode 100644 index 00000000..5d7b4993 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#define DEFAULT_PORT 7000 +#define DEFAULT_BACKLOG 128 + +uv_loop_t *loop; +struct sockaddr_in addr; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = (char*) malloc(suggested_size); + buf->len = suggested_size; +} + +void on_close(uv_handle_t* handle) { + free(handle); +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_strerror(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, on_close); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status < 0) { + fprintf(stderr, "New connection error %s\n", uv_strerror(status)); + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, on_close); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr); + + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_strerror(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/thread-create/main.c b/3rd/libuv-1.19.2/docs/code/thread-create/main.c new file mode 100644 index 00000000..70224c1e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/thread-create/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +void hare(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + sleep(1); + fprintf(stderr, "Hare ran another step\n"); + } + fprintf(stderr, "Hare done running!\n"); +} + +void tortoise(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + fprintf(stderr, "Tortoise ran another step\n"); + sleep(3); + } + fprintf(stderr, "Tortoise done running!\n"); +} + +int main() { + int tracklen = 10; + uv_thread_t hare_id; + uv_thread_t tortoise_id; + uv_thread_create(&hare_id, hare, &tracklen); + uv_thread_create(&tortoise_id, tortoise, &tracklen); + + uv_thread_join(&hare_id); + uv_thread_join(&tortoise_id); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c b/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c new file mode 100644 index 00000000..053e7e59 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +uv_timer_t tick; +uv_write_t write_req; +int width, height; +int pos = 0; +char *message = " Hello TTY "; + +void update(uv_timer_t *req) { + char data[500]; + + uv_buf_t buf; + buf.base = data; + buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%luC\033[42;37m%s", + pos, + (unsigned long) (width-strlen(message))/2, + message); + uv_write(&write_req, (uv_stream_t*) &tty, &buf, 1, NULL); + + pos++; + if (pos > height) { + uv_tty_reset_mode(); + uv_timer_stop(&tick); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 0); + uv_tty_set_mode(&tty, 0); + + if (uv_tty_get_winsize(&tty, &width, &height)) { + fprintf(stderr, "Could not get TTY information\n"); + uv_tty_reset_mode(); + return 1; + } + + fprintf(stderr, "Width %d, height %d\n", width, height); + uv_timer_init(loop, &tick); + uv_timer_start(&tick, update, 200, 200); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/tty/main.c b/3rd/libuv-1.19.2/docs/code/tty/main.c new file mode 100644 index 00000000..03b26fbc --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/tty/main.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 0); + uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL); + + if (uv_guess_handle(1) == UV_TTY) { + uv_write_t req; + uv_buf_t buf; + buf.base = "\033[41;37m"; + buf.len = strlen(buf.base); + uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + } + + uv_write_t req; + uv_buf_t buf; + buf.base = "Hello TTY\n"; + buf.len = strlen(buf.base); + uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + uv_tty_reset_mode(); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c b/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c new file mode 100644 index 00000000..fc2ca0c8 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_udp_t send_socket; +uv_udp_t recv_socket; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { + if (nread < 0) { + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) req, NULL); + free(buf->base); + return; + } + + char sender[17] = { 0 }; + uv_ip4_name((const struct sockaddr_in*) addr, sender, 16); + fprintf(stderr, "Recv from %s\n", sender); + + // ... DHCP specific code + unsigned int *as_integer = (unsigned int*)buf->base; + unsigned int ipbin = ntohl(as_integer[4]); + unsigned char ip[4] = {0}; + int i; + for (i = 0; i < 4; i++) + ip[i] = (ipbin >> i*8) & 0xff; + fprintf(stderr, "Offered IP %d.%d.%d.%d\n", ip[3], ip[2], ip[1], ip[0]); + + free(buf->base); + uv_udp_recv_stop(req); +} + +uv_buf_t make_discover_msg() { + uv_buf_t buffer; + alloc_buffer(NULL, 256, &buffer); + memset(buffer.base, 0, buffer.len); + + // BOOTREQUEST + buffer.base[0] = 0x1; + // HTYPE ethernet + buffer.base[1] = 0x1; + // HLEN + buffer.base[2] = 0x6; + // HOPS + buffer.base[3] = 0x0; + // XID 4 bytes + buffer.base[4] = (unsigned int) random(); + // SECS + buffer.base[8] = 0x0; + // FLAGS + buffer.base[10] = 0x80; + // CIADDR 12-15 is all zeros + // YIADDR 16-19 is all zeros + // SIADDR 20-23 is all zeros + // GIADDR 24-27 is all zeros + // CHADDR 28-43 is the MAC address, use your own + buffer.base[28] = 0xe4; + buffer.base[29] = 0xce; + buffer.base[30] = 0x8f; + buffer.base[31] = 0x13; + buffer.base[32] = 0xf6; + buffer.base[33] = 0xd4; + // SNAME 64 bytes zero + // FILE 128 bytes zero + // OPTIONS + // - magic cookie + buffer.base[236] = 99; + buffer.base[237] = 130; + buffer.base[238] = 83; + buffer.base[239] = 99; + + // DHCP Message type + buffer.base[240] = 53; + buffer.base[241] = 1; + buffer.base[242] = 1; // DHCPDISCOVER + + // DHCP Parameter request list + buffer.base[243] = 55; + buffer.base[244] = 4; + buffer.base[245] = 1; + buffer.base[246] = 3; + buffer.base[247] = 15; + buffer.base[248] = 6; + + return buffer; +} + +void on_send(uv_udp_send_t *req, int status) { + if (status) { + fprintf(stderr, "Send error %s\n", uv_strerror(status)); + return; + } +} + +int main() { + loop = uv_default_loop(); + + uv_udp_init(loop, &recv_socket); + struct sockaddr_in recv_addr; + uv_ip4_addr("0.0.0.0", 68, &recv_addr); + uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); + uv_udp_recv_start(&recv_socket, alloc_buffer, on_read); + + uv_udp_init(loop, &send_socket); + struct sockaddr_in broadcast_addr; + uv_ip4_addr("0.0.0.0", 0, &broadcast_addr); + uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0); + uv_udp_set_broadcast(&send_socket, 1); + + uv_udp_send_t send_req; + uv_buf_t discover_msg = make_discover_msg(); + + struct sockaddr_in send_addr; + uv_ip4_addr("255.255.255.255", 67, &send_addr); + uv_udp_send(&send_req, &send_socket, &discover_msg, 1, (const struct sockaddr *)&send_addr, on_send); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/3rd/libuv-1.19.2/docs/code/uvcat/main.c b/3rd/libuv-1.19.2/docs/code/uvcat/main.c new file mode 100644 index 00000000..b03b0944 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvcat/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +void on_read(uv_fs_t *req); + +uv_fs_t open_req; +uv_fs_t read_req; +uv_fs_t write_req; + +static char buffer[1024]; + +static uv_buf_t iov; + +void on_write(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Write error: %s\n", uv_strerror((int)req->result)); + } + else { + uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1, on_read); + } +} + +void on_read(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Read error: %s\n", uv_strerror(req->result)); + } + else if (req->result == 0) { + uv_fs_t close_req; + // synchronous + uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); + } + else if (req->result > 0) { + iov.len = req->result; + uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write); + } +} + +void on_open(uv_fs_t *req) { + // The request passed to the callback is the same as the one the call setup + // function was passed. + assert(req == &open_req); + if (req->result >= 0) { + iov = uv_buf_init(buffer, sizeof(buffer)); + uv_fs_read(uv_default_loop(), &read_req, req->result, + &iov, 1, -1, on_read); + } + else { + fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result)); + } +} + +int main(int argc, char **argv) { + uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_fs_req_cleanup(&open_req); + uv_fs_req_cleanup(&read_req); + uv_fs_req_cleanup(&write_req); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvstop/main.c b/3rd/libuv-1.19.2/docs/code/uvstop/main.c new file mode 100644 index 00000000..7aa53b76 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvstop/main.c @@ -0,0 +1,33 @@ +#include +#include + +int64_t counter = 0; + +void idle_cb(uv_idle_t *handle) { + printf("Idle callback\n"); + counter++; + + if (counter >= 5) { + uv_stop(uv_default_loop()); + printf("uv_stop() called\n"); + } +} + +void prep_cb(uv_prepare_t *handle) { + printf("Prep callback\n"); +} + +int main() { + uv_idle_t idler; + uv_prepare_t prep; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, idle_cb); + + uv_prepare_init(uv_default_loop(), &prep); + uv_prepare_start(&prep, prep_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvtee/main.c b/3rd/libuv-1.19.2/docs/code/uvtee/main.c new file mode 100644 index 00000000..6216c2eb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvtee/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +#include + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +uv_loop_t *loop; +uv_pipe_t stdin_pipe; +uv_pipe_t stdout_pipe; +uv_pipe_t file_pipe; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + *buf = uv_buf_init((char*) malloc(suggested_size), suggested_size); +} + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void on_stdout_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void on_file_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void write_data(uv_stream_t *dest, size_t size, uv_buf_t buf, uv_write_cb cb) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init((char*) malloc(size), size); + memcpy(req->buf.base, buf.base, size); + uv_write((uv_write_t*) req, (uv_stream_t*)dest, &req->buf, 1, cb); +} + +void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0){ + if (nread == UV_EOF){ + // end of file + uv_close((uv_handle_t *)&stdin_pipe, NULL); + uv_close((uv_handle_t *)&stdout_pipe, NULL); + uv_close((uv_handle_t *)&file_pipe, NULL); + } + } else if (nread > 0) { + write_data((uv_stream_t *)&stdout_pipe, nread, *buf, on_stdout_write); + write_data((uv_stream_t *)&file_pipe, nread, *buf, on_file_write); + } + + // OK to free buffer as write_data copies it. + if (buf->base) + free(buf->base); +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + uv_pipe_init(loop, &stdin_pipe, 0); + uv_pipe_open(&stdin_pipe, 0); + + uv_pipe_init(loop, &stdout_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + uv_fs_t file_req; + int fd = uv_fs_open(loop, &file_req, argv[1], O_CREAT | O_RDWR, 0644, NULL); + uv_pipe_init(loop, &file_pipe, 0); + uv_pipe_open(&file_pipe, fd); + + uv_read_start((uv_stream_t*)&stdin_pipe, alloc_buffer, read_stdin); + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/code/uvwget/main.c b/3rd/libuv-1.19.2/docs/code/uvwget/main.c new file mode 100644 index 00000000..40186241 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/code/uvwget/main.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +CURLM *curl_handle; +uv_timer_t timeout; + +typedef struct curl_context_s { + uv_poll_t poll_handle; + curl_socket_t sockfd; +} curl_context_t; + +curl_context_t *create_curl_context(curl_socket_t sockfd) { + curl_context_t *context; + + context = (curl_context_t*) malloc(sizeof *context); + + context->sockfd = sockfd; + + int r = uv_poll_init_socket(loop, &context->poll_handle, sockfd); + assert(r == 0); + context->poll_handle.data = context; + + return context; +} + +void curl_close_cb(uv_handle_t *handle) { + curl_context_t *context = (curl_context_t*) handle->data; + free(context); +} + +void destroy_curl_context(curl_context_t *context) { + uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb); +} + + +void add_download(const char *url, int num) { + char filename[50]; + sprintf(filename, "%d.download", num); + FILE *file; + + file = fopen(filename, "w"); + if (file == NULL) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + CURL *handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +void check_multi_info(void) { + char *done_url; + CURLMsg *message; + int pending; + + while ((message = curl_multi_info_read(curl_handle, &pending))) { + switch (message->msg) { + case CURLMSG_DONE: + curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, + &done_url); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, message->easy_handle); + curl_easy_cleanup(message->easy_handle); + break; + + default: + fprintf(stderr, "CURLMSG default\n"); + abort(); + } + } +} + +void curl_perform(uv_poll_t *req, int status, int events) { + uv_timer_stop(&timeout); + int running_handles; + int flags = 0; + if (status < 0) flags = CURL_CSELECT_ERR; + if (!status && events & UV_READABLE) flags |= CURL_CSELECT_IN; + if (!status && events & UV_WRITABLE) flags |= CURL_CSELECT_OUT; + + curl_context_t *context; + + context = (curl_context_t*)req; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, &running_handles); + check_multi_info(); +} + +void on_timeout(uv_timer_t *req) { + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, &running_handles); + check_multi_info(); +} + +void start_timeout(CURLM *multi, long timeout_ms, void *userp) { + if (timeout_ms <= 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */ + uv_timer_start(&timeout, on_timeout, timeout_ms, 0); +} + +int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, void *socketp) { + curl_context_t *curl_context; + if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { + if (socketp) { + curl_context = (curl_context_t*) socketp; + } + else { + curl_context = create_curl_context(s); + curl_multi_assign(curl_handle, s, (void *) curl_context); + } + } + + switch (action) { + case CURL_POLL_IN: + uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform); + break; + case CURL_POLL_OUT: + uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform); + break; + case CURL_POLL_REMOVE: + if (socketp) { + uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + if (argc <= 1) + return 0; + + if (curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init cURL\n"); + return 1; + } + + uv_timer_init(loop, &timeout); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while (argc-- > 1) { + add_download(argv[argc], argc); + } + + uv_run(loop, UV_RUN_DEFAULT); + curl_multi_cleanup(curl_handle); + return 0; +} diff --git a/3rd/libuv-1.19.2/docs/make.bat b/3rd/libuv-1.19.2/docs/make.bat new file mode 100644 index 00000000..10eb94b0 --- /dev/null +++ b/3rd/libuv-1.19.2/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 ^` where ^ 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/3rd/libuv-1.19.2/docs/src/api.rst b/3rd/libuv-1.19.2/docs/src/api.rst new file mode 100644 index 00000000..22f0640f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/api.rst @@ -0,0 +1,35 @@ +.. _api: + +API documentation +================= + +.. toctree:: + :maxdepth: 1 + + 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/3rd/libuv-1.19.2/docs/src/async.rst b/3rd/libuv-1.19.2/docs/src/async.rst new file mode 100644 index 00000000..02e6a58e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/async.rst @@ -0,0 +1,61 @@ + +.. _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. + + :returns: 0 on success, or an error code < 0 on failure. + + .. note:: + Unlike other handle initialization functions, it immediately starts the handle. + +.. c:function:: int uv_async_send(uv_async_t* async) + + Wake up the event loop and call the async handle's callback. + + :returns: 0 on success, or an error code < 0 on failure. + + .. 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/3rd/libuv-1.19.2/docs/src/check.rst b/3rd/libuv-1.19.2/docs/src/check.rst new file mode 100644 index 00000000..36c93cf0 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/conf.py b/3rd/libuv-1.19.2/docs/src/conf.py new file mode 100644 index 00000000..c9b4ea38 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/conf.py @@ -0,0 +1,348 @@ +# -*- coding: utf-8 -*- +# +# libuv 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'2014-present, 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 +# " v documentation". +html_title = 'libuv documentation' + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = 'libuv %s 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 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 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 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 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 documentation' +epub_author = u'libuv contributors' +epub_publisher = u'libuv contributors' +epub_copyright = u'2014-present, 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/3rd/libuv-1.19.2/docs/src/design.rst b/3rd/libuv-1.19.2/docs/src/design.rst new file mode 100644 index 00000000..487d08ba --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/design.rst @@ -0,0 +1,138 @@ + +.. _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 a simple 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. +- A TCP server handle that gets 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 matches, 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 duration calculated + in 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 ends 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 `_. + +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: + + * File system 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/3rd/libuv-1.19.2/docs/src/dll.rst b/3rd/libuv-1.19.2/docs/src/dll.rst new file mode 100644 index 00000000..fb13f908 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/dns.rst b/3rd/libuv-1.19.2/docs/src/dns.rst new file mode 100644 index 00000000..1d881580 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/errors.rst b/3rd/libuv-1.19.2/docs/src/errors.rst new file mode 100644 index 00000000..4e30447b --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/errors.rst @@ -0,0 +1,344 @@ + +.. _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. + +When a function which takes a callback returns an error, the callback will never +be called. + +.. 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. + +.. c:function:: int uv_translate_sys_error(int sys_errno) + + Returns the libuv error code equivalent to the given platform dependent error + code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error + codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`). + + If `sys_errno` is already a libuv error, it is simply returned. + + .. versionchanged:: 1.10.0 function declared public. diff --git a/3rd/libuv-1.19.2/docs/src/fs.rst b/3rd/libuv-1.19.2/docs/src/fs.rst new file mode 100644 index 00000000..87af828a --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs.rst @@ -0,0 +1,538 @@ + +.. _fs: + +File system operations +====================== + +libuv provides a wide variety of cross-platform sync and async file system +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 + + File system 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 + + File system 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_REALPATH, + UV_FS_COPYFILE + } 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 file systems (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:`lstat(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_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) + + Copies a file from `path` to `new_path`. Supported `flags` are described below. + + - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with + `UV_EEXIST` if the destination path already exists. The default behavior + is to overwrite the destination if it exists. + + .. warning:: + If the destination path is created, but an error occurs while copying + the data, then the destination path is removed. There is a brief window + of time between closing and removing the file where another process + could access the file. + + .. versionadded:: 1.14.0 + +.. 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. + + .. note:: + AIX: This function only works for AIX 7.1 and newer. It can still be called on older + versions but will return ``UV_ENOSYS``. + + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows + +.. 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 `_. + + .. warning:: + This function has certain platform-specific caveats that were discovered when used in Node. + + * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are + found while resolving the given path. This limit is hardcoded and cannot be sidestepped. + * Windows: while this function works in the common case, there are a number of corner cases + where it doesn't: + + - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) + cannot be resolved. + - Inconsistent casing when using drive letters. + - Resolved path bypasses subst'd drives. + + While this function can still be used, it's not recommended if scenarios such as the + above need to be supported. + + The background story and some more details on these issues can be checked + `here `_. + + .. 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. + +.. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) + + Returns `req->fs_type`. + + .. versionadded:: 1.19.0 + +.. c:function:: ssize_t uv_fs_get_result(const uv_fs_t* req) + + Returns `req->result`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) + + Returns `req->ptr`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_fs_get_path(const uv_fs_t* req) + + Returns `req->path`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) + + Returns `&req->statbuf`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. + +Helper functions +---------------- + +.. c:function:: uv_os_fd_t uv_get_osfhandle(int fd) + + For a file descriptor in the C runtime, get the OS-dependent handle. + On UNIX, returns the ``fd`` intact. On Windows, this calls `_get_osfhandle `_. + Note that the return value is still owned by the C runtime, + any attempts to close it or to use it after closing the fd may lead to malfunction. + + .. versionadded:: 1.12.0 + +File open constants +------------------- + +.. c:macro:: UV_FS_O_APPEND + + The file is opened in append mode. Before each write, the file offset is + positioned at the end of the file. + +.. c:macro:: UV_FS_O_CREAT + + The file is created if it does not already exist. + +.. c:macro:: UV_FS_O_DIRECT + + File I/O is done directly to and from user-space buffers, which must be + aligned. Buffer size and address should be a multiple of the physical sector + size of the block device. + + .. note:: + `UV_FS_O_DIRECT` is supported on Linux, and on Windows via + `FILE_FLAG_NO_BUFFERING `_. + `UV_FS_O_DIRECT` is not supported on macOS. + +.. c:macro:: UV_FS_O_DIRECTORY + + If the path is not a directory, fail the open. + + .. note:: + `UV_FS_O_DIRECTORY` is not supported on Windows. + +.. c:macro:: UV_FS_O_DSYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and a minimum of metadata are flushed to disk. + + .. note:: + `UV_FS_O_DSYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_EXCL + + If the `O_CREAT` flag is set and the file already exists, fail the open. + + .. note:: + In general, the behavior of `O_EXCL` is undefined if it is used without + `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can + be used without `O_CREAT` if pathname refers to a block device. If the + block device is in use by the system (e.g., mounted), the open will fail + with the error `EBUSY`. + +.. c:macro:: UV_FS_O_EXLOCK + + Atomically obtain an exclusive lock. + + .. note:: + `UV_FS_O_EXLOCK` is only supported on macOS and Windows. + + .. versionchanged:: 1.17.0 support is added for Windows. + +.. c:macro:: UV_FS_O_NOATIME + + Do not update the file access time when the file is read. + + .. note:: + `UV_FS_O_NOATIME` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOCTTY + + If the path identifies a terminal device, opening the path will not cause + that terminal to become the controlling terminal for the process (if the + process does not already have one). + + .. note:: + `UV_FS_O_NOCTTY` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOFOLLOW + + If the path is a symbolic link, fail the open. + + .. note:: + `UV_FS_O_NOFOLLOW` is not supported on Windows. + +.. c:macro:: UV_FS_O_NONBLOCK + + Open the file in nonblocking mode if possible. + + .. note:: + `UV_FS_O_NONBLOCK` is not supported on Windows. + +.. c:macro:: UV_FS_O_RANDOM + + Access is intended to be random. The system can use this as a hint to + optimize file caching. + + .. note:: + `UV_FS_O_RANDOM` is only supported on Windows via + `FILE_FLAG_RANDOM_ACCESS `_. + +.. c:macro:: UV_FS_O_RDONLY + + Open the file for read-only access. + +.. c:macro:: UV_FS_O_RDWR + + Open the file for read-write access. + +.. c:macro:: UV_FS_O_SEQUENTIAL + + Access is intended to be sequential from beginning to end. The system can + use this as a hint to optimize file caching. + + .. note:: + `UV_FS_O_SEQUENTIAL` is only supported on Windows via + `FILE_FLAG_SEQUENTIAL_SCAN `_. + +.. c:macro:: UV_FS_O_SHORT_LIVED + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_SHORT_LIVED` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_SYMLINK + + Open the symbolic link itself rather than the resource it points to. + +.. c:macro:: UV_FS_O_SYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and all metadata are flushed to disk. + + .. note:: + `UV_FS_O_SYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_TEMPORARY + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_TEMPORARY` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_TRUNC + + If the file exists and is a regular file, and the file is opened + successfully for write access, its length shall be truncated to zero. + +.. c:macro:: UV_FS_O_WRONLY + + Open the file for write-only access. diff --git a/3rd/libuv-1.19.2/docs/src/fs_event.rst b/3rd/libuv-1.19.2/docs/src/fs_event.rst new file mode 100644 index 00000000..bd076aae --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs_event.rst @@ -0,0 +1,132 @@ + +.. _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. + +.. note:: + For AIX, the non default IBM bos.ahafs package has to be installed. + The AIX Event Infrastructure file system (ahafs) has some limitations: + + - ahafs tracks monitoring per process and is not thread safe. A separate process + must be spawned for each monitor for the same event. + - Events for file modification (writing to a file) are not received if only the + containing folder is watched. + + See documentation_ for more details. + + The z/OS file system events monitoring infrastructure does not notify of file + creation/deletion within a directory that is being monitored. + See the `IBM Knowledge centre`_ for more details. + + .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ + .. _`IBM Knowledge centre`: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.2.0/com.ibm.zos.v2r1.bpxb100/ioc.htm + + + + +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 file systems 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 its 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 `size` will be set to + the required size, including the null terminator. + + .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte, + and the buffer is not null terminated. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/fs_poll.rst b/3rd/libuv-1.19.2/docs/src/fs_poll.rst new file mode 100644 index 00000000..2912bad9 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/fs_poll.rst @@ -0,0 +1,77 @@ + +.. _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 `size` 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. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/guide.rst b/3rd/libuv-1.19.2/docs/src/guide.rst new file mode 100644 index 00000000..126e0808 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide.rst @@ -0,0 +1,22 @@ +.. _guide: + +User guide +========== + +.. warning:: + The contents of this guide have been recently incorporated into the libuv documentation + and it hasn't gone through thorough review yet. If you spot a mistake please file an + issue, or better yet, open a pull request! + +.. toctree:: + :maxdepth: 2 + + guide/introduction + guide/basics + guide/filesystem + guide/networking + guide/threads + guide/processes + guide/eventloops + guide/utilities + guide/about diff --git a/3rd/libuv-1.19.2/docs/src/guide/about.rst b/3rd/libuv-1.19.2/docs/src/guide/about.rst new file mode 100644 index 00000000..2de658d5 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/about.rst @@ -0,0 +1,22 @@ +About +===== + +`Nikhil Marathe `_ started writing this book one +afternoon (June 16, 2012) when he didn't feel like programming. He had recently +been stung by the lack of good documentation on libuv while working on +`node-taglib `_. Although reference +documentation was present, there were no comprehensive tutorials. This book is +the output of that need and tries to be accurate. That said, the book may have +mistakes. Pull requests are encouraged. + +Nikhil is indebted to Marc Lehmann's comprehensive `man page +`_ about libev which +describes much of the semantics of the two libraries. + +This book was made using `Sphinx `_ and `vim +`_. + +.. note:: + In 2017 the libuv project incorporated the Nikhil's work into the official + documentation and it's maintained there henceforth. + diff --git a/3rd/libuv-1.19.2/docs/src/guide/basics.rst b/3rd/libuv-1.19.2/docs/src/guide/basics.rst new file mode 100644 index 00000000..91fa6a6d --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/basics.rst @@ -0,0 +1,188 @@ +Basics of libuv +=============== + +libuv enforces an **asynchronous**, **event-driven** style of programming. Its +core job is to provide an event loop and callback based notifications of I/O +and other activities. libuv offers core utilities like timers, non-blocking +networking support, asynchronous file system access, child processes and more. + +Event loops +----------- + +In event-driven programming, an application expresses interest in certain events +and respond to them when they occur. The responsibility of gathering events +from the operating system or monitoring other sources of events is handled by +libuv, and the user can register callbacks to be invoked when an event occurs. +The event-loop usually keeps running *forever*. In pseudocode: + +.. code-block:: python + + while there are still events to process: + e = get the next event + if there is a callback associated with e: + call the callback + +Some examples of events are: + +* File is ready for writing +* A socket has data ready to be read +* A timer has timed out + +This event loop is encapsulated by ``uv_run()`` -- the end-all function when using +libuv. + +The most common activity of systems programs is to deal with input and output, +rather than a lot of number-crunching. The problem with using conventional +input/output functions (``read``, ``fprintf``, etc.) is that they are +**blocking**. The actual write to a hard disk or reading from a network, takes +a disproportionately long time compared to the speed of the processor. The +functions don't return until the task is done, so that your program is doing +nothing. For programs which require high performance this is a major roadblock +as other activities and other I/O operations are kept waiting. + +One of the standard solutions is to use threads. Each blocking I/O operation is +started in a separate thread (or in a thread pool). When the blocking function +gets invoked in the thread, the processor can schedule another thread to run, +which actually needs the CPU. + +The approach followed by libuv uses another style, which is the **asynchronous, +non-blocking** style. Most modern operating systems provide event notification +subsystems. For example, a normal ``read`` call on a socket would block until +the sender actually sent something. Instead, the application can request the +operating system to watch the socket and put an event notification in the +queue. The application can inspect the events at its convenience (perhaps doing +some number crunching before to use the processor to the maximum) and grab the +data. It is **asynchronous** because the application expressed interest at one +point, then used the data at another point (in time and space). It is +**non-blocking** because the application process was free to do other tasks. +This fits in well with libuv's event-loop approach, since the operating system +events can be treated as just another libuv event. The non-blocking ensures +that other events can continue to be handled as fast as they come in [#]_. + +.. NOTE:: + + How the I/O is run in the background is not of our concern, but due to the + way our computer hardware works, with the thread as the basic unit of the + processor, libuv and OSes will usually run background/worker threads and/or + polling to perform tasks in a non-blocking manner. + +Bert Belder, one of the libuv core developers has a small video explaining the +architecture of libuv and its background. If you have no prior experience with +either libuv or libev, it is a quick, useful watch. + +libuv's event loop is explained in more detail in the `documentation +`_. + +.. raw:: html + + + +Hello World +----------- + +With the basics out of the way, lets write our first libuv program. It does +nothing, except start a loop which will exit immediately. + +.. rubric:: helloworld/main.c +.. literalinclude:: ../../code/helloworld/main.c + :linenos: + +This program quits immediately because it has no events to process. A libuv +event loop has to be told to watch out for events using the various API +functions. + +Starting with libuv v1.0, users should allocate the memory for the loops before +initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in +custom memory management. Remember to de-initialize the loop using +``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never +close loops since the program quits after the loop ends and the system will +reclaim memory. Production grade projects, especially long running systems +programs, should take care to release correctly. + +Default loop +++++++++++++ + +A default loop is provided by libuv and can be accessed using +``uv_default_loop()``. You should use this loop if you only want a single +loop. + +.. note:: + + node.js uses the default loop as its main loop. If you are writing bindings + you should be aware of this. + +.. _libuv-error-handling: + +Error handling +-------------- + +Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. + +.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants + +You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions +to get a ``const char *`` describing the error or the error name respectively. + +I/O read callbacks (such as for files and sockets) are passed a parameter ``nread``. If ``nread`` is less than 0, there was an error (UV_EOF is the end of file error, which you may want to handle differently). + +Handles and Requests +-------------------- + +libuv works by the user expressing interest in particular events. This is +usually done by creating a **handle** to an I/O device, timer or process. +Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the +handle is used for. + +.. rubric:: libuv watchers +.. literalinclude:: ../../../include/uv.h + :lines: 197-230 + +Handles represent long-lived objects. Async operations on such handles are +identified using **requests**. A request is short-lived (usually used across +only one callback) and usually indicates one I/O operation on a handle. +Requests are used to preserve context between the initiation and the callback +of individual actions. For example, an UDP socket is represented by +a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t`` +structure that is passed to the callback after the write is done. + +Handles are setup by a corresponding:: + + uv_TYPE_init(uv_loop_t *, uv_TYPE_t *) + +function. + +Callbacks are functions which are called by libuv whenever an event the watcher +is interested in has taken place. Application specific logic will usually be +implemented in the callback. For example, an IO watcher's callback will receive +the data read from a file, a timer callback will be triggered on timeout and so +on. + +Idling +++++++ + +Here is an example of using an idle handle. The callback is called once on +every turn of the event loop. A use case for idle handles is discussed in +:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle +and see how ``uv_run()`` will now block because a watcher is present. The idle +watcher is stopped when the count is reached and ``uv_run()`` exits since no +event watchers are active. + +.. rubric:: idle-basic/main.c +.. literalinclude:: ../../code/idle-basic/main.c + :emphasize-lines: 6,10,14-17 + +Storing context ++++++++++++++++ + +In callback based programming style you'll often want to pass some 'context' -- +application specific information -- between the call site and the callback. All +handles and requests have a ``void* data`` member which you can set to the +context and cast back in the callback. This is a common pattern used throughout +the C library ecosystem. In addition ``uv_loop_t`` also has a similar data +member. + +---- + +.. [#] Depending on the capacity of the hardware of course. diff --git a/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst b/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst new file mode 100644 index 00000000..fd9df5fb --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst @@ -0,0 +1,48 @@ +Advanced event loops +==================== + +libuv provides considerable user control over event loops, and you can achieve +interesting results by juggling multiple loops. You can also embed libuv's +event loop into another event loop based library -- imagine a Qt based UI, and +Qt's event loop driving a libuv backend which does intensive system level +tasks. + +Stopping an event loop +~~~~~~~~~~~~~~~~~~~~~~ + +``uv_stop()`` can be used to stop an event loop. The earliest the loop will +stop running is *on the next iteration*, possibly later. This means that events +that are ready to be processed in this iteration of the loop will still be +processed, so ``uv_stop()`` can't be used as a kill switch. When ``uv_stop()`` +is called, the loop **won't** block for i/o on this iteration. The semantics of +these things can be a bit difficult to understand, so let's look at +``uv_run()`` where all the control flow occurs. + +.. rubric:: src/unix/core.c - uv_run +.. literalinclude:: ../../../src/unix/core.c + :linenos: + :lines: 304-324 + :emphasize-lines: 10,19,21 + +``stop_flag`` is set by ``uv_stop()``. Now all libuv callbacks are invoked +within the event loop, which is why invoking ``uv_stop()`` in them will still +lead to this iteration of the loop occurring. First libuv updates timers, then +runs pending timer, idle and prepare callbacks, and invokes any pending I/O +callbacks. If you were to call ``uv_stop()`` in any of them, ``stop_flag`` +would be set. This causes ``uv_backend_timeout()`` to return ``0``, which is +why the loop does not block on I/O. If on the other hand, you called +``uv_stop()`` in one of the check handlers, I/O has already finished and is not +affected. + +``uv_stop()`` is useful to shutdown a loop when a result has been computed or +there is an error, without having to ensure that all handlers are stopped one +by one. + +Here is a simple example that stops the loop and demonstrates how the current +iteration of the loop still takes places. + +.. rubric:: uvstop/main.c +.. literalinclude:: ../../code/uvstop/main.c + :linenos: + :emphasize-lines: 11 + diff --git a/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst b/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst new file mode 100644 index 00000000..6129303e --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst @@ -0,0 +1,287 @@ +Filesystem +========== + +Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the +``uv_fs_t`` struct. + +.. note:: + + The libuv filesystem operations are different from :doc:`socket operations + `. Socket operations use the non-blocking operations provided + by the operating system. Filesystem operations use blocking functions + internally, but invoke these functions in a `thread pool`_ and notify + watchers registered with the event loop when application interaction is + required. + +.. _thread pool: http://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling + +All filesystem functions have two forms - *synchronous* and *asynchronous*. + +The *synchronous* forms automatically get called (and **block**) if the +callback is null. The return value of functions is a :ref:`libuv error code +`. This is usually only useful for synchronous calls. +The *asynchronous* form is called when a callback is passed and the return +value is 0. + +Reading/Writing files +--------------------- + +A file descriptor is obtained using + +.. code-block:: c + + int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) + +``flags`` and ``mode`` are standard +`Unix flags `_. +libuv takes care of converting to the appropriate Windows flags. + +File descriptors are closed using + +.. code-block:: c + + int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + +Filesystem operation callbacks have the signature: + +.. code-block:: c + + void callback(uv_fs_t* req); + +Let's see a simple implementation of ``cat``. We start with registering +a callback for when the file is opened: + +.. rubric:: uvcat/main.c - opening a file +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 41-53 + :emphasize-lines: 4, 6-7 + +The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the +``uv_fs_open`` callback. If the file is successfully opened, we start reading it. + +.. rubric:: uvcat/main.c - read callback +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 26-40 + :emphasize-lines: 2,8,12 + +In the case of a read call, you should pass an *initialized* buffer which will +be filled with data before the read callback is triggered. The ``uv_fs_*`` +operations map almost directly to certain POSIX functions, so EOF is indicated +in this case by ``result`` being 0. In the case of streams or pipes, the +``UV_EOF`` constant would have been passed as a status instead. + +Here you see a common pattern when writing asynchronous programs. The +``uv_fs_close()`` call is performed synchronously. *Usually tasks which are +one-off, or are done as part of the startup or shutdown stage are performed +synchronously, since we are interested in fast I/O when the program is going +about its primary task and dealing with multiple I/O sources*. For solo tasks +the performance difference usually is negligible and may lead to simpler code. + +Filesystem writing is similarly simple using ``uv_fs_write()``. *Your callback +will be triggered after the write is complete*. In our case the callback +simply drives the next read. Thus read and write proceed in lockstep via +callbacks. + +.. rubric:: uvcat/main.c - write callback +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 16-24 + :emphasize-lines: 6 + +.. warning:: + + Due to the way filesystems and disk drives are configured for performance, + a write that 'succeeds' may not be committed to disk yet. + +We set the dominos rolling in ``main()``: + +.. rubric:: uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c + :linenos: + :lines: 55- + :emphasize-lines: 2 + +.. warning:: + + The ``uv_fs_req_cleanup()`` function must always be called on filesystem + requests to free internal memory allocations in libuv. + +Filesystem operations +--------------------- + +All the standard filesystem operations like ``unlink``, ``rmdir``, ``stat`` are +supported asynchronously and have intuitive argument order. They follow the +same patterns as the read/write/open calls, returning the result in the +``uv_fs_t.result`` field. The full list: + +.. rubric:: Filesystem operations +.. literalinclude:: ../../../include/uv.h + :lines: 1084-1195 + +.. _buffers-and-streams: + +Buffers and Streams +------------------- + +The basic I/O handle in libuv is the stream (``uv_stream_t``). TCP sockets, UDP +sockets, and pipes for file I/O and IPC are all treated as stream subclasses. + +Streams are initialized using custom functions for each subclass, then operated +upon using + +.. code-block:: c + + int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb); + int uv_read_stop(uv_stream_t*); + int uv_write(uv_write_t* req, uv_stream_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); + +The stream based functions are simpler to use than the filesystem ones and +libuv will automatically keep reading from a stream when ``uv_read_start()`` is +called once, until ``uv_read_stop()`` is called. + +The discrete unit of data is the buffer -- ``uv_buf_t``. This is simply +a collection of a pointer to bytes (``uv_buf_t.base``) and the length +(``uv_buf_t.len``). The ``uv_buf_t`` is lightweight and passed around by value. +What does require management is the actual bytes, which have to be allocated +and freed by the application. + +.. ERROR:: + + THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER** + +To demonstrate streams we will need to use ``uv_pipe_t``. This allows streaming +local files [#]_. Here is a simple tee utility using libuv. Doing all operations +asynchronously shows the power of evented I/O. The two writes won't block each +other, but we have to be careful to copy over the buffer data to ensure we don't +free a buffer until it has been written. + +The program is to be executed as:: + + ./uvtee + +We start off opening pipes on the files we require. libuv pipes to a file are +opened as bidirectional by default. + +.. rubric:: uvtee/main.c - read on pipes +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 61-80 + :emphasize-lines: 4,5,15 + +The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named +pipes. This is covered in :doc:`processes`. The ``uv_pipe_open()`` call +associates the pipe with the file descriptor, in this case ``0`` (standard +input). + +We start monitoring ``stdin``. The ``alloc_buffer`` callback is invoked as new +buffers are required to hold incoming data. ``read_stdin`` will be called with +these buffers. + +.. rubric:: uvtee/main.c - reading buffers +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 19-22,44-60 + +The standard ``malloc`` is sufficient here, but you can use any memory allocation +scheme. For example, node.js uses its own slab allocator which associates +buffers with V8 objects. + +The read callback ``nread`` parameter is less than 0 on any error. This error +might be EOF, in which case we close all the streams, using the generic close +function ``uv_close()`` which deals with the handle based on its internal type. +Otherwise ``nread`` is a non-negative number and we can attempt to write that +many bytes to the output streams. Finally remember that buffer allocation and +deallocation is application responsibility, so we free the data. + +The allocation callback may return a buffer with length zero if it fails to +allocate memory. In this case, the read callback is invoked with error +UV_ENOBUFS. libuv will continue to attempt to read the stream though, so you +must explicitly call ``uv_close()`` if you want to stop when allocation fails. + +The read callback may be called with ``nread = 0``, indicating that at this +point there is nothing to be read. Most applications will just ignore this. + +.. rubric:: uvtee/main.c - Write to pipe +.. literalinclude:: ../../code/uvtee/main.c + :linenos: + :lines: 9-13,23-42 + +``write_data()`` makes a copy of the buffer obtained from read. This buffer +does not get passed through to the write callback trigged on write completion. To +get around this we wrap a write request and a buffer in ``write_req_t`` and +unwrap it in the callbacks. We make a copy so we can free the two buffers from +the two calls to ``write_data`` independently of each other. While acceptable +for a demo program like this, you'll probably want smarter memory management, +like reference counted buffers or a pool of buffers in any major application. + +.. WARNING:: + + If your program is meant to be used with other programs it may knowingly or + unknowingly be writing to a pipe. This makes it susceptible to `aborting on + receiving a SIGPIPE`_. It is a good idea to insert:: + + signal(SIGPIPE, SIG_IGN) + + in the initialization stages of your application. + +.. _aborting on receiving a SIGPIPE: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_SIGPIPE + +File change events +------------------ + +All modern operating systems provide APIs to put watches on individual files or +directories and be informed when the files are modified. libuv wraps common +file change notification libraries [#fsnotify]_. This is one of the more +inconsistent parts of libuv. File change notification systems are themselves +extremely varied across platforms so getting everything working everywhere is +difficult. To demonstrate, I'm going to build a simple utility which runs +a command whenever any of the watched files change:: + + ./onchange [file2] ... + +The file change notification is started using ``uv_fs_event_init()``: + +.. rubric:: onchange/main.c - The setup +.. literalinclude:: ../../code/onchange/main.c + :linenos: + :lines: 26- + :emphasize-lines: 15 + +The third argument is the actual file or directory to monitor. The last +argument, ``flags``, can be: + +.. literalinclude:: ../../../include/uv.h + :lines: 1299, 1308, 1315 + +``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet). +``UV_FS_EVENT_RECURSIVE`` will start watching subdirectories as well on +supported platforms. + +The callback will receive the following arguments: + + #. ``uv_fs_event_t *handle`` - The handle. The ``path`` field of the handle + is the file on which the watch was set. + #. ``const char *filename`` - If a directory is being monitored, this is the + file which was changed. Only non-``null`` on Linux and Windows. May be ``null`` + even on those platforms. + #. ``int flags`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of + both. + #. ``int status`` - Currently 0. + +In our example we simply print the arguments and run the command using +``system()``. + +.. rubric:: onchange/main.c - file change notification callback +.. literalinclude:: ../../code/onchange/main.c + :linenos: + :lines: 9-24 + +---- + +.. [#fsnotify] inotify on Linux, FSEvents on Darwin, kqueue on BSDs, + ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin +.. [#] see :ref:`pipes` diff --git a/3rd/libuv-1.19.2/docs/src/guide/introduction.rst b/3rd/libuv-1.19.2/docs/src/guide/introduction.rst new file mode 100644 index 00000000..f57cdd9c --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/introduction.rst @@ -0,0 +1,75 @@ +Introduction +============ + +This 'book' is a small set of tutorials about using libuv_ as +a high performance evented I/O library which offers the same API on Windows and Unix. + +It is meant to cover the main areas of libuv, but is not a comprehensive +reference discussing every function and data structure. The `official libuv +documentation`_ may be consulted for full details. + +.. _official libuv documentation: http://docs.libuv.org/en/v1.x/ + +This book is still a work in progress, so sections may be incomplete, but +I hope you will enjoy it as it grows. + +Who this book is for +-------------------- + +If you are reading this book, you are either: + +1) a systems programmer, creating low-level programs such as daemons or network + services and clients. You have found that the event loop approach is well + suited for your application and decided to use libuv. + +2) a node.js module writer, who wants to wrap platform APIs + written in C or C++ with a set of (a)synchronous APIs that are exposed to + JavaScript. You will use libuv purely in the context of node.js. For + this you will require some other resources as the book does not cover parts + specific to v8/node.js. + +This book assumes that you are comfortable with the C programming language. + +Background +---------- + +The node.js_ project began in 2009 as a JavaScript environment decoupled +from the browser. Using Google's V8_ and Marc Lehmann's libev_, node.js +combined a model of I/O -- evented -- with a language that was well suited to +the style of programming; due to the way it had been shaped by browsers. As +node.js grew in popularity, it was important to make it work on Windows, but +libev ran only on Unix. The Windows equivalent of kernel event notification +mechanisms like kqueue or (e)poll is IOCP. libuv was an abstraction around libev +or IOCP depending on the platform, providing users an API based on libev. +In the node-v0.9.0 version of libuv `libev was removed`_. + +Since then libuv has continued to mature and become a high quality standalone +library for system programming. Users outside of node.js include Mozilla's +Rust_ programming language, and a variety_ of language bindings. + +This book and the code is based on libuv version `v1.3.0`_. + +Code +---- + +All the code from this book is included as part of the source of the book on +Github. `Clone`_/`Download`_ the book, then build libuv:: + + cd libuv + ./autogen.sh + ./configure + make + +There is no need to ``make install``. To build the examples run ``make`` in the +``code/`` directory. + +.. _Clone: https://github.com/nikhilm/uvbook +.. _Download: https://github.com/nikhilm/uvbook/downloads +.. _v1.3.0: https://github.com/libuv/libuv/tags +.. _V8: http://code.google.com/p/v8/ +.. _libev: http://software.schmorp.de/pkg/libev.html +.. _libuv: https://github.com/libuv/libuv +.. _node.js: http://www.nodejs.org +.. _libev was removed: https://github.com/joyent/libuv/issues/485 +.. _Rust: http://rust-lang.org +.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv diff --git a/3rd/libuv-1.19.2/docs/src/guide/networking.rst b/3rd/libuv-1.19.2/docs/src/guide/networking.rst new file mode 100644 index 00000000..8d3c87bf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/networking.rst @@ -0,0 +1,249 @@ +Networking +========== + +Networking in libuv is not much different from directly using the BSD socket +interface, some things are easier, all are non-blocking, but the concepts stay +the same. In addition libuv offers utility functions to abstract the annoying, +repetitive and low-level tasks like setting up sockets using the BSD socket +structures, DNS lookup, and tweaking various socket parameters. + +The ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O. + +.. NOTE:: + + The code samples in this chapter exist to show certain libuv APIs. They are + not examples of good quality code. They leak memory and don't always close + connections properly. + +TCP +--- + +TCP is a connection oriented, stream protocol and is therefore based on the +libuv streams infrastructure. + +Server +++++++ + +Server sockets proceed by: + +1. ``uv_tcp_init`` the TCP handle. +2. ``uv_tcp_bind`` it. +3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new + connection is established by a client. +4. Use ``uv_accept`` to accept the connection. +5. Use :ref:`stream operations ` to communicate with the + client. + +Here is a simple echo server + +.. rubric:: tcp-echo-server/main.c - The listen socket +.. literalinclude:: ../../code/tcp-echo-server/main.c + :linenos: + :lines: 68- + :emphasize-lines: 4-5,7-10 + +You can see the utility function ``uv_ip4_addr`` being used to convert from +a human readable IP address, port pair to the sockaddr_in structure required by +the BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``. + +.. NOTE:: + + There are ``uv_ip6_*`` analogues for the ip4 functions. + +Most of the setup functions are synchronous since they are CPU-bound. +``uv_listen`` is where we return to libuv's callback style. The second +arguments is the backlog queue -- the maximum length of queued connections. + +When a connection is initiated by clients, the callback is required to set up +a handle for the client socket and associate the handle using ``uv_accept``. +In this case we also establish interest in reading from this stream. + +.. rubric:: tcp-echo-server/main.c - Accepting the client +.. literalinclude:: ../../code/tcp-echo-server/main.c + :linenos: + :lines: 51-66 + :emphasize-lines: 9-10 + +The remaining set of functions is very similar to the streams example and can +be found in the code. Just remember to call ``uv_close`` when the socket isn't +required. This can be done even in the ``uv_listen`` callback if you are not +interested in accepting the connection. + +Client +++++++ + +Where you do bind/listen/accept on the server, on the client side it's simply +a matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style +callback of ``uv_listen`` is used by ``uv_tcp_connect``. Try:: + + uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); + + struct sockaddr_in dest; + uv_ip4_addr("127.0.0.1", 80, &dest); + + uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect); + +where ``on_connect`` will be called after the connection is established. The +callback receives the ``uv_connect_t`` struct, which has a member ``.handle`` +pointing to the socket. + +UDP +--- + +The `User Datagram Protocol`_ offers connectionless, unreliable network +communication. Hence libuv doesn't offer a stream. Instead libuv provides +non-blocking UDP support via the `uv_udp_t` handle (for receiving) and +`uv_udp_send_t` request (for sending) and related functions. That said, the +actual API for reading/writing is very similar to normal stream reads. To look +at how UDP can be used, the example shows the first stage of obtaining an IP +address from a `DHCP`_ server -- DHCP Discover. + +.. note:: + + You will have to run `udp-dhcp` as **root** since it uses well known port + numbers below 1024. + +.. rubric:: udp-dhcp/main.c - Setup and send UDP packets +.. literalinclude:: ../../code/udp-dhcp/main.c + :linenos: + :lines: 7-11,104- + :emphasize-lines: 8,10-11,17-18,21 + +.. note:: + + The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP + address ``255.255.255.255`` is a broadcast address meaning that packets + will be sent to all interfaces on the subnet. port ``0`` means that the OS + randomly assigns a port. + +First we setup the receiving socket to bind on all interfaces on port 68 (DHCP +client) and start a read on it. This will read back responses from any DHCP +server that replies. We use the UV_UDP_REUSEADDR flag to play nice with any +other system DHCP clients that are running on this computer on the same port. +Then we setup a similar send socket and use ``uv_udp_send`` to send +a *broadcast message* on port 67 (DHCP server). + +It is **necessary** to set the broadcast flag, otherwise you will get an +``EACCES`` error [#]_. The exact message being sent is not relevant to this +book and you can study the code if you are interested. As usual the read and +write callbacks will receive a status code of < 0 if something went wrong. + +Since UDP sockets are not connected to a particular peer, the read callback +receives an extra parameter about the sender of the packet. + +``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL, +it indicates there is nothing to read (the callback shouldn't do anything), if +not NULL, it indicates that an empty datagram was received from the host at +``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer +provided by your allocator was not large enough to hold the data. *In this case +the OS will discard the data that could not fit* (That's UDP for you!). + +.. rubric:: udp-dhcp/main.c - Reading packets +.. literalinclude:: ../../code/udp-dhcp/main.c + :linenos: + :lines: 17-40 + :emphasize-lines: 1,23 + +UDP Options ++++++++++++ + +Time-to-live +~~~~~~~~~~~~ + +The TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``. + +IPv6 stack only +~~~~~~~~~~~~~~~ + +IPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to +restrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to +``uv_udp_bind`` [#]_. + +Multicast +~~~~~~~~~ + +A socket can (un)subscribe to a multicast group using: + +.. literalinclude:: ../../../include/uv.h + :lines: 594-597 + +where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. + +The concepts of multicasting are nicely explained in `this guide`_. + +.. _this guide: http://www.tldp.org/HOWTO/Multicast-HOWTO-2.html + +Local loopback of multicast packets is enabled by default [#]_, use +``uv_udp_set_multicast_loop`` to switch it off. + +The packet time-to-live for multicast packets can be changed using +``uv_udp_set_multicast_ttl``. + +Querying DNS +------------ + +libuv provides asynchronous DNS resolution. For this it provides its own +``getaddrinfo`` replacement [#]_. In the callback you can +perform normal socket operations on the retrieved addresses. Let's connect to +Freenode to see an example of DNS resolution. + +.. rubric:: dns/main.c +.. literalinclude:: ../../code/dns/main.c + :linenos: + :lines: 61- + :emphasize-lines: 12 + +If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and +your callback won't be invoked at all. All arguments can be freed immediately +after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` +structures are documented in `the getaddrinfo man page `_. The +callback can be ``NULL`` in which case the function will run synchronously. + +In the resolver callback, you can pick any IP from the linked list of ``struct +addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to +call ``uv_freeaddrinfo`` in the callback. + +.. rubric:: dns/main.c +.. literalinclude:: ../../code/dns/main.c + :linenos: + :lines: 42-60 + :emphasize-lines: 8,16 + +libuv also provides the inverse `uv_getnameinfo`_. + +.. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo + +Network interfaces +------------------ + +Information about the system's network interfaces can be obtained through libuv +using ``uv_interface_addresses``. This simple program just prints out all the +interface details so you get an idea of the fields that are available. This is +useful to allow your service to bind to IP addresses when it starts. + +.. rubric:: interfaces/main.c +.. literalinclude:: ../../code/interfaces/main.c + :linenos: + :emphasize-lines: 9,17 + +``is_internal`` is true for loopback interfaces. Note that if a physical +interface has multiple IPv4/IPv6 addresses, the name will be reported multiple +times, with each address being reported once. + +.. _c-ares: http://c-ares.haxx.se +.. _getaddrinfo: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html + +.. _User Datagram Protocol: http://en.wikipedia.org/wiki/User_Datagram_Protocol +.. _DHCP: http://tools.ietf.org/html/rfc2131 + +---- + +.. [#] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#broadcast +.. [#] on Windows only supported on Windows Vista and later. +.. [#] http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1 +.. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv + v0.8.0 and earlier also included c-ares_ as an alternative, but this has been + removed in v0.9.0. diff --git a/3rd/libuv-1.19.2/docs/src/guide/processes.rst b/3rd/libuv-1.19.2/docs/src/guide/processes.rst new file mode 100644 index 00000000..49df4e93 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/processes.rst @@ -0,0 +1,389 @@ +Processes +========= + +libuv offers considerable child process management, abstracting the platform +differences and allowing communication with the child process using streams or +named pipes. + +A common idiom in Unix is for every process to do one thing and do it well. In +such a case, a process often uses multiple child processes to achieve tasks +(similar to using pipes in shells). A multi-process model with messages +may also be easier to reason about compared to one with threads and shared +memory. + +A common refrain against event-based programs is that they cannot take +advantage of multiple cores in modern computers. In a multi-threaded program +the kernel can perform scheduling and assign different threads to different +cores, improving performance. But an event loop has only one thread. The +workaround can be to launch multiple processes instead, with each process +running an event loop, and each process getting assigned to a separate CPU +core. + +Spawning child processes +------------------------ + +The simplest case is when you simply want to launch a process and know when it +exits. This is achieved using ``uv_spawn``. + +.. rubric:: spawn/main.c +.. literalinclude:: ../../code/spawn/main.c + :linenos: + :lines: 6-8,15- + :emphasize-lines: 11,13-17 + +.. NOTE:: + + ``options`` is implicitly initialized with zeros since it is a global + variable. If you change ``options`` to a local variable, remember to + initialize it to null out all unused fields:: + + uv_process_options_t options = {0}; + +The ``uv_process_t`` struct only acts as the handle, all options are set via +``uv_process_options_t``. To simply launch a process, you need to set only the +``file`` and ``args`` fields. ``file`` is the program to execute. Since +``uv_spawn`` uses execvp_ internally, there is no need to supply the full +path. Finally as per underlying conventions, **the arguments array has to be +one larger than the number of arguments, with the last element being NULL**. + +.. _execvp: http://www.kernel.org/doc/man-pages/online/pages/man3/exec.3.html + +After the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process +ID of the child process. + +The exit callback will be invoked with the *exit status* and the type of *signal* +which caused the exit. + +.. rubric:: spawn/main.c +.. literalinclude:: ../../code/spawn/main.c + :linenos: + :lines: 9-12 + :emphasize-lines: 3 + +It is **required** to close the process watcher after the process exits. + +Changing process parameters +--------------------------- + +Before the child process is launched you can control the execution environment +using fields in ``uv_process_options_t``. + +Change execution directory +++++++++++++++++++++++++++ + +Set ``uv_process_options_t.cwd`` to the corresponding directory. + +Set environment variables ++++++++++++++++++++++++++ + +``uv_process_options_t.env`` is a null-terminated array of strings, each of the +form ``VAR=VALUE`` used to set up the environment variables for the process. Set +this to ``NULL`` to inherit the environment from the parent (this) process. + +Option flags +++++++++++++ + +Setting ``uv_process_options_t.flags`` to a bitwise OR of the following flags, +modifies the child process behaviour: + +* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``. +* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``. + +Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on +Windows with ``UV_ENOTSUP``. + +* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of + ``uv_process_options_t.args`` is done on Windows. Ignored on Unix. +* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which + will keep running after the parent process exits. See example below. + +Detaching processes +------------------- + +Passing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or +child processes which are independent of the parent so that the parent exiting +does not affect it. + +.. rubric:: detach/main.c +.. literalinclude:: ../../code/detach/main.c + :linenos: + :lines: 9-30 + :emphasize-lines: 12,19 + +Just remember that the handle is still monitoring the child, so your program +won't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*. + +Sending signals to processes +---------------------------- + +libuv wraps the standard ``kill(2)`` system call on Unix and implements one +with similar semantics on Windows, with *one caveat*: all of ``SIGTERM``, +``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature +of ``uv_kill`` is:: + + uv_err_t uv_kill(int pid, int signum); + +For processes started using libuv, you may use ``uv_process_kill`` instead, +which accepts the ``uv_process_t`` watcher as the first argument, rather than +the pid. In this case, **remember to call** ``uv_close`` on the watcher. + +Signals +------- + +libuv provides wrappers around Unix signals with `some Windows support +`_ as well. + +Use ``uv_signal_init()`` to initialize +a handle and associate it with a loop. To listen for particular signals on +that handler, use ``uv_signal_start()`` with the handler function. Each handler +can only be associated with one signal number, with subsequent calls to +``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to +stop watching. Here is a small example demonstrating the various possibilities: + +.. rubric:: signal/main.c +.. literalinclude:: ../../code/signal/main.c + :linenos: + :emphasize-lines: 17-18,27-28 + +.. NOTE:: + + ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)`` + in that it will process only one event. UV_RUN_ONCE blocks if there are no + pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT + so that one of the loops isn't starved because the other one has no pending + activity. + +Send ``SIGUSR1`` to the process, and you'll find the handler being invoked +4 times, one for each ``uv_signal_t``. The handler just stops each handle, +so that the program exits. This sort of dispatch to all handlers is very +useful. A server using multiple event loops could ensure that all data was +safely saved before termination, simply by every loop adding a watcher for +``SIGINT``. + +Child Process I/O +----------------- + +A normal, newly spawned process has its own set of file descriptors, with 0, +1 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you +may want to share file descriptors with the child. For example, perhaps your +applications launches a sub-command and you want any errors to go in the log +file, but ignore ``stdout``. For this you'd like to have ``stderr`` of the +child be the same as the stderr of the parent. In this case, libuv supports +*inheriting* file descriptors. In this sample, we invoke the test program, +which is: + +.. rubric:: proc-streams/test.c +.. literalinclude:: ../../code/proc-streams/test.c + +The actual program ``proc-streams`` runs this while sharing only ``stderr``. +The file descriptors of the child process are set using the ``stdio`` field in +``uv_process_options_t``. First set the ``stdio_count`` field to the number of +file descriptors being set. ``uv_process_options_t.stdio`` is an array of +``uv_stdio_container_t``, which is: + +.. literalinclude:: ../../../include/uv.h + :lines: 826-834 + +where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be +used. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll +redirect to ``/dev/null``. + +Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``. +Then we set the ``fd`` to ``stderr``. + +.. rubric:: proc-streams/main.c +.. literalinclude:: ../../code/proc-streams/main.c + :linenos: + :lines: 15-17,27- + :emphasize-lines: 6,10,11,12 + +If you run ``proc-stream`` you'll see that only the line "This is stderr" will +be displayed. Try marking ``stdout`` as being inherited and see the output. + +It is dead simple to apply this redirection to streams. By setting ``flags`` +to ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the +parent process, the child process can treat that stream as standard I/O. This +can be used to implement something like CGI_. + +.. _CGI: http://en.wikipedia.org/wiki/Common_Gateway_Interface + +A sample CGI script/executable is: + +.. rubric:: cgi/tick.c +.. literalinclude:: ../../code/cgi/tick.c + +The CGI server combines the concepts from this chapter and :doc:`networking` so +that every client is sent ten ticks after which that connection is closed. + +.. rubric:: cgi/main.c +.. literalinclude:: ../../code/cgi/main.c + :linenos: + :lines: 49-63 + :emphasize-lines: 10 + +Here we simply accept the TCP connection and pass on the socket (*stream*) to +``invoke_cgi_script``. + +.. rubric:: cgi/main.c +.. literalinclude:: ../../code/cgi/main.c + :linenos: + :lines: 16, 25-45 + :emphasize-lines: 8-9,18,20 + +The ``stdout`` of the CGI script is set to the socket so that whatever our tick +script prints, gets sent to the client. By using processes, we can offload the +read/write buffering to the operating system, so in terms of convenience this +is great. Just be warned that creating processes is a costly task. + +.. _pipes: + +Pipes +----- + +libuv's ``uv_pipe_t`` structure is slightly confusing to Unix programmers, +because it immediately conjures up ``|`` and `pipe(7)`_. But ``uv_pipe_t`` is +not related to anonymous pipes, rather it is an IPC mechanism. ``uv_pipe_t`` +can be backed by a `Unix Domain Socket`_ or `Windows Named Pipe`_ to allow +multiple processes to communicate. This is discussed below. + +.. _pipe(7): http://www.kernel.org/doc/man-pages/online/pages/man7/pipe.7.html +.. _Unix Domain Socket: http://www.kernel.org/doc/man-pages/online/pages/man7/unix.7.html +.. _Windows Named Pipe: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx + +Parent-child IPC +++++++++++++++++ + +A parent and child can have one or two way communication over a pipe created by +settings ``uv_stdio_container_t.flags`` to a bit-wise combination of +``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The +read/write flag is from the perspective of the child process. + +Arbitrary process IPC ++++++++++++++++++++++ + +Since domain sockets [#]_ can have a well known name and a location in the +file-system they can be used for IPC between unrelated processes. The D-BUS_ +system used by open source desktop environments uses domain sockets for event +notification. Various applications can then react when a contact comes online +or new hardware is detected. The MySQL server also runs a domain socket on +which clients can interact with it. + +.. _D-BUS: http://www.freedesktop.org/wiki/Software/dbus + +When using domain sockets, a client-server pattern is usually followed with the +creator/owner of the socket acting as the server. After the initial setup, +messaging is no different from TCP, so we'll re-use the echo server example. + +.. rubric:: pipe-echo-server/main.c +.. literalinclude:: ../../code/pipe-echo-server/main.c + :linenos: + :lines: 70- + :emphasize-lines: 5,10,14 + +We name the socket ``echo.sock`` which means it will be created in the local +directory. This socket now behaves no different from TCP sockets as far as +the stream API is concerned. You can test this server using `socat`_:: + + $ socat - /path/to/socket + +A client which wants to connect to a domain socket will use:: + + void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb); + +where ``name`` will be ``echo.sock`` or similar. + +.. _socat: http://www.dest-unreach.org/socat/ + +Sending file descriptors over pipes ++++++++++++++++++++++++++++++++++++ + +The cool thing about domain sockets is that file descriptors can be exchanged +between processes by sending them over a domain socket. This allows processes +to hand off their I/O to other processes. Applications include load-balancing +servers, worker processes and other ways to make optimum use of CPU. libuv only +supports sending **TCP sockets or other pipes** over pipes for now. + +To demonstrate, we will look at a echo server implementation that hands of +clients to worker processes in a round-robin fashion. This program is a bit +involved, and while only snippets are included in the book, it is recommended +to read the full code to really understand it. + +The worker process is quite simple, since the file-descriptor is handed over to +it by the master. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c + :linenos: + :lines: 7-9,81- + :emphasize-lines: 6-8 + +``queue`` is the pipe connected to the master process on the other end, along +which new file descriptors get sent. It is important to set the ``ipc`` +argument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for +inter-process communication! Since the master will write the file handle to the +standard input of the worker, we connect the pipe to ``stdin`` using +``uv_pipe_open``. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c + :linenos: + :lines: 51-79 + :emphasize-lines: 10,15,20 + +First we call ``uv_pipe_pending_count()`` to ensure that a handle is available +to read out. If your program could deal with different types of handles, +``uv_pipe_pending_type()`` can be used to determine the type. +Although ``accept`` seems odd in this code, it actually makes sense. What +``accept`` traditionally does is get a file descriptor (the client) from +another file descriptor (The listening socket). Which is exactly what we do +here. Fetch the file descriptor (``client``) from ``queue``. From this point +the worker does standard echo server stuff. + +Turning now to the master, let's take a look at how the workers are launched to +allow load balancing. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 9-13 + +The ``child_worker`` structure wraps the process, and the pipe between the +master and the individual process. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 51,61-95 + :emphasize-lines: 17,20-21 + +In setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to +get the number of CPUs so we can launch an equal number of workers. Again it is +important to initialize the pipe acting as the IPC channel with the third +argument as 1. We then indicate that the child process' ``stdin`` is to be +a readable pipe (from the point of view of the child). Everything is +straightforward till here. The workers are launched and waiting for file +descriptors to be written to their standard input. + +It is in ``on_new_connection`` (the TCP infrastructure is initialized in +``main()``), that we accept the client socket and pass it along to the next +worker in the round-robin. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c + :linenos: + :lines: 31-49 + :emphasize-lines: 9,12-13 + +The ``uv_write2`` call handles all the abstraction and it is simply a matter of +passing in the handle (``client``) as the right argument. With this our +multi-process echo server is operational. + +Thanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty +buffer even when sending handles. + +.. _pointing out: https://github.com/nikhilm/uvbook/issues/56 + +---- + +.. [#] In this section domain sockets stands in for named pipes on Windows as + well. diff --git a/3rd/libuv-1.19.2/docs/src/guide/threads.rst b/3rd/libuv-1.19.2/docs/src/guide/threads.rst new file mode 100644 index 00000000..b6a4fd85 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/threads.rst @@ -0,0 +1,381 @@ +Threads +======= + +Wait a minute? Why are we on threads? Aren't event loops supposed to be **the +way** to do *web-scale programming*? Well... no. Threads are still the medium in +which processors do their jobs. Threads are therefore mighty useful sometimes, even +though you might have to wade through various synchronization primitives. + +Threads are used internally to fake the asynchronous nature of all of the system +calls. libuv also uses threads to allow you, the application, to perform a task +asynchronously that is actually blocking, by spawning a thread and collecting +the result when it is done. + +Today there are two predominant thread libraries: the Windows threads +implementation and POSIX's `pthreads`_. libuv's thread API is analogous to +the pthreads API and often has similar semantics. + +A notable aspect of libuv's thread facilities is that it is a self contained +section within libuv. Whereas other features intimately depend on the event +loop and callback principles, threads are complete agnostic, they block as +required, signal errors directly via return values, and, as shown in the +:ref:`first example `, don't even require a running +event loop. + +libuv's thread API is also very limited since the semantics and syntax of +threads are different on all platforms, with different levels of completeness. + +This chapter makes the following assumption: **There is only one event loop, +running in one thread (the main thread)**. No other thread interacts +with the event loop (except using ``uv_async_send``). + +Core thread operations +---------------------- + +There isn't much here, you just start a thread using ``uv_thread_create()`` and +wait for it to close using ``uv_thread_join()``. + +.. _thread-create-example: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c + :linenos: + :lines: 26-36 + :emphasize-lines: 3-7 + +.. tip:: + + ``uv_thread_t`` is just an alias for ``pthread_t`` on Unix, but this is an + implementation detail, avoid depending on it to always be true. + +The second parameter is the function which will serve as the entry point for +the thread, the last parameter is a ``void *`` argument which can be used to pass +custom parameters to the thread. The function ``hare`` will now run in a separate +thread, scheduled pre-emptively by the operating system: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c + :linenos: + :lines: 6-14 + :emphasize-lines: 2 + +Unlike ``pthread_join()`` which allows the target thread to pass back a value to +the calling thread using a second parameter, ``uv_thread_join()`` does not. To +send values use :ref:`inter-thread-communication`. + +Synchronization Primitives +-------------------------- + +This section is purposely spartan. This book is not about threads, so I only +catalogue any surprises in the libuv APIs here. For the rest you can look at +the pthreads `man pages `_. + +Mutexes +~~~~~~~ + +The mutex functions are a **direct** map to the pthread equivalents. + +.. rubric:: libuv mutex functions +.. literalinclude:: ../../../include/uv.h + :lines: 1355-1360 + +The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()`` +functions will return 0 on success, and an error code otherwise. + +If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``, +``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error. +Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other +than* ``EAGAIN`` or ``EBUSY``. + +Recursive mutexes are supported, but you should not rely on them. Also, they +should not be used with ``uv_cond_t`` variables. + +The default BSD mutex implementation will raise an error if a thread which has +locked a mutex attempts to lock it again. For example, a construct like:: + + uv_mutex_init(a_mutex); + uv_mutex_lock(a_mutex); + uv_thread_create(thread_id, entry, (void *)a_mutex); + uv_mutex_lock(a_mutex); + // more things here + +can be used to wait until another thread initializes some stuff and then +unlocks ``a_mutex`` but will lead to your program crashing if in debug mode, or +return an error in the second call to ``uv_mutex_lock()``. + +.. note:: + + Mutexes on Windows are always recursive. + +Locks +~~~~~ + +Read-write locks are a more granular access mechanism. Two readers can access +shared memory at the same time. A writer may not acquire the lock when it is +held by a reader. A reader or writer may not acquire a lock when a writer is +holding it. Read-write locks are frequently used in databases. Here is a toy +example. + +.. rubric:: locks/main.c - simple rwlocks +.. literalinclude:: ../../code/locks/main.c + :linenos: + :emphasize-lines: 13,16,27,31,42,55 + +Run this and observe how the readers will sometimes overlap. In case of +multiple writers, schedulers will usually give them higher priority, so if you +add two writers, you'll see that both writers tend to finish first before the +readers get a chance again. + +We also use barriers in the above example so that the main thread can wait for +all readers and writers to indicate they have ended. + +Others +~~~~~~ + +libuv also supports semaphores_, `condition variables`_ and barriers_ with APIs +very similar to their pthread counterparts. + +.. _semaphores: http://en.wikipedia.org/wiki/Semaphore_(programming) +.. _condition variables: http://en.wikipedia.org/wiki/Condition_variable#Waiting_and_signaling +.. _barriers: http://en.wikipedia.org/wiki/Barrier_(computer_science) + +In addition, libuv provides a convenience function ``uv_once()``. Multiple +threads can attempt to call ``uv_once()`` with a given guard and a function +pointer, **only the first one will win, the function will be called once and +only once**:: + + /* Initialize guard */ + static uv_once_t once_only = UV_ONCE_INIT; + + int i = 0; + + void increment() { + i++; + } + + void thread1() { + /* ... work */ + uv_once(once_only, increment); + } + + void thread2() { + /* ... work */ + uv_once(once_only, increment); + } + + int main() { + /* ... spawn threads */ + } + +After all threads are done, ``i == 1``. + +.. _libuv-work-queue: + +libuv v0.11.11 onwards also added a ``uv_key_t`` struct and api_ for +thread-local storage. + +.. _api: http://docs.libuv.org/en/v1.x/threading.html#thread-local-storage + +libuv work queue +---------------- + +``uv_queue_work()`` is a convenience function that allows an application to run +a task in a separate thread, and have a callback that is triggered when the +task is done. A seemingly simple function, what makes ``uv_queue_work()`` +tempting is that it allows potentially any third-party libraries to be used +with the event-loop paradigm. When you use event loops, it is *imperative to +make sure that no function which runs periodically in the loop thread blocks +when performing I/O or is a serious CPU hog*, because this means that the loop +slows down and events are not being handled at full capacity. + +However, a lot of existing code out there features blocking functions (for example +a routine which performs I/O under the hood) to be used with threads if you +want responsiveness (the classic 'one thread per client' server model), and +getting them to play with an event loop library generally involves rolling your +own system of running the task in a separate thread. libuv just provides +a convenient abstraction for this. + +Here is a simple example inspired by `node.js is cancer`_. We are going to +calculate fibonacci numbers, sleeping a bit along the way, but run it in +a separate thread so that the blocking and CPU bound task does not prevent the +event loop from performing other activities. + +.. rubric:: queue-work/main.c - lazy fibonacci +.. literalinclude:: ../../code/queue-work/main.c + :linenos: + :lines: 17-29 + +The actual task function is simple, nothing to show that it is going to be +run in a separate thread. The ``uv_work_t`` structure is the clue. You can pass +arbitrary data through it using the ``void* data`` field and use it to +communicate to and from the thread. But be sure you are using proper locks if +you are changing things while both threads may be running. + +The trigger is ``uv_queue_work``: + +.. rubric:: queue-work/main.c +.. literalinclude:: ../../code/queue-work/main.c + :linenos: + :lines: 31-44 + :emphasize-lines: 10 + +The thread function will be launched in a separate thread, passed the +``uv_work_t`` structure and once the function returns, the *after* function +will be called on the thread the event loop is running in. It will be passed +the same structure. + +For writing wrappers to blocking libraries, a common :ref:`pattern ` +is to use a baton to exchange data. + +Since libuv version `0.9.4` an additional function, ``uv_cancel()``, is +available. This allows you to cancel tasks on the libuv work queue. Only tasks +that *are yet to be started* can be cancelled. If a task has *already started +executing, or it has finished executing*, ``uv_cancel()`` **will fail**. + +``uv_cancel()`` is useful to cleanup pending tasks if the user requests +termination. For example, a music player may queue up multiple directories to +be scanned for audio files. If the user terminates the program, it should quit +quickly and not wait until all pending requests are run. + +Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set +up a signal handler for termination. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 43- + +When the user triggers the signal by pressing ``Ctrl+C`` we send +``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 33-41 + :emphasize-lines: 6 + +For tasks that do get cancelled successfully, the *after* function is called +with ``status`` set to ``UV_ECANCELED``. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c + :linenos: + :lines: 28-31 + :emphasize-lines: 2 + +``uv_cancel()`` can also be used with ``uv_fs_t`` and ``uv_getaddrinfo_t`` +requests. For the filesystem family of functions, ``uv_fs_t.errorno`` will be +set to ``UV_ECANCELED``. + +.. TIP:: + + A well designed program would have a way to terminate long running workers + that have already started executing. Such a worker could periodically check + for a variable that only the main process sets to signal termination. + +.. _inter-thread-communication: + +Inter-thread communication +-------------------------- + +Sometimes you want various threads to actually send each other messages *while* +they are running. For example you might be running some long duration task in +a separate thread (perhaps using ``uv_queue_work``) but want to notify progress +to the main thread. This is a simple example of having a download manager +informing the user of the status of running downloads. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 7-8,34- + :emphasize-lines: 2,11 + +The async thread communication works *on loops* so although any thread can be +the message sender, only threads with libuv loops can be receivers (or rather +the loop is the receiver). libuv will invoke the callback (``print_progress``) +with the async watcher whenever it receives a message. + +.. warning:: + + It is important to realize that since the message send is *async*, the callback + may be invoked immediately after ``uv_async_send`` is called in another + thread, or it may be invoked after some time. libuv may also combine + multiple calls to ``uv_async_send`` and invoke your callback only once. The + only guarantee that libuv makes is -- The callback function is called *at + least once* after the call to ``uv_async_send``. If you have no pending + calls to ``uv_async_send``, the callback won't be called. If you make two + or more calls, and libuv hasn't had a chance to run the callback yet, it + *may* invoke your callback *only once* for the multiple invocations of + ``uv_async_send``. Your callback will never be called twice for just one + event. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 10-23 + :emphasize-lines: 7-8 + +In the download function, we modify the progress indicator and queue the message +for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also +non-blocking and will return immediately. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 30-33 + +The callback is a standard libuv pattern, extracting the data from the watcher. + +Finally it is important to remember to clean up the watcher. + +.. rubric:: progress/main.c +.. literalinclude:: ../../code/progress/main.c + :linenos: + :lines: 25-28 + :emphasize-lines: 3 + +After this example, which showed the abuse of the ``data`` field, bnoordhuis_ +pointed out that using the ``data`` field is not thread safe, and +``uv_async_send()`` is actually only meant to wake up the event loop. Use +a mutex or rwlock to ensure accesses are performed in the right order. + +.. note:: + + mutexes and rwlocks **DO NOT** work inside a signal handler, whereas + ``uv_async_send`` does. + +One use case where ``uv_async_send`` is required is when interoperating with +libraries that require thread affinity for their functionality. For example in +node.js, a v8 engine instance, contexts and its objects are bound to the thread +that the v8 instance was started in. Interacting with v8 data structures from +another thread can lead to undefined results. Now consider some node.js module +which binds a third party library. It may go something like this: + +1. In node, the third party library is set up with a JavaScript callback to be + invoked for more information:: + + var lib = require('lib'); + lib.on_progress(function() { + console.log("Progress"); + }); + + lib.do(); + + // do other stuff + +2. ``lib.do`` is supposed to be non-blocking but the third party lib is + blocking, so the binding uses ``uv_queue_work``. + +3. The actual work being done in a separate thread wants to invoke the progress + callback, but cannot directly call into v8 to interact with JavaScript. So + it uses ``uv_async_send``. + +4. The async callback, invoked in the main loop thread, which is the v8 thread, + then interacts with v8 to invoke the JavaScript callback. + +.. _pthreads: http://man7.org/linux/man-pages/man7/pthreads.7.html + +---- + +.. _node.js is cancer: http://teddziuba.github.io/2011/10/node-js-is-cancer.html +.. _bnoordhuis: https://github.com/bnoordhuis diff --git a/3rd/libuv-1.19.2/docs/src/guide/utilities.rst b/3rd/libuv-1.19.2/docs/src/guide/utilities.rst new file mode 100644 index 00000000..abe6fa8d --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/guide/utilities.rst @@ -0,0 +1,433 @@ +Utilities +========= + +This chapter catalogues tools and techniques which are useful for common tasks. +The `libev man page`_ already covers some patterns which can be adopted to +libuv through simple API changes. It also covers parts of the libuv API that +don't require entire chapters dedicated to them. + +Timers +------ + +Timers invoke the callback after a certain time has elapsed since the timer was +started. libuv timers can also be set to invoke at regular intervals instead of +just once. + +Simple use is to init a watcher and start it with a ``timeout``, and optional ``repeat``. +Timers can be stopped at any time. + +.. code-block:: c + + uv_timer_t timer_req; + + uv_timer_init(loop, &timer_req); + uv_timer_start(&timer_req, callback, 5000, 2000); + +will start a repeating timer, which first starts 5 seconds (the ``timeout``) after the execution +of ``uv_timer_start``, then repeats every 2 seconds (the ``repeat``). Use: + +.. code-block:: c + + uv_timer_stop(&timer_req); + +to stop the timer. This can be used safely from within the callback as well. + +The repeat interval can be modified at any time with:: + + uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat); + +which will take effect **when possible**. If this function is called from +a timer callback, it means: + +* If the timer was non-repeating, the timer has already been stopped. Use + ``uv_timer_start`` again. +* If the timer is repeating, the next timeout has already been scheduled, so + the old repeat interval will be used once more before the timer switches to + the new interval. + +The utility function:: + + int uv_timer_again(uv_timer_t *) + +applies **only to repeating timers** and is equivalent to stopping the timer +and then starting it with both initial ``timeout`` and ``repeat`` set to the +old ``repeat`` value. If the timer hasn't been started it fails (error code +``UV_EINVAL``) and returns -1. + +An actual timer example is in the :ref:`reference count section +`. + +.. _reference-count: + +Event loop reference count +-------------------------- + +The event loop only runs as long as there are active handles. This system +works by having every handle increase the reference count of the event loop +when it is started and decreasing the reference count when stopped. It is also +possible to manually change the reference count of handles using:: + + void uv_ref(uv_handle_t*); + void uv_unref(uv_handle_t*); + +These functions can be used to allow a loop to exit even when a watcher is +active or to use custom objects to keep the loop alive. + +The latter can be used with interval timers. You might have a garbage collector +which runs every X seconds, or your network service might send a heartbeat to +others periodically, but you don't want to have to stop them along all clean +exit paths or error scenarios. Or you want the program to exit when all your +other watchers are done. In that case just unref the timer immediately after +creation so that if it is the only watcher running then ``uv_run`` will still +exit. + +This is also used in node.js where some libuv methods are being bubbled up to +the JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per +JS object and can be ref/unrefed. + +.. rubric:: ref-timer/main.c +.. literalinclude:: ../../code/ref-timer/main.c + :linenos: + :lines: 5-8, 17- + :emphasize-lines: 9 + +We initialize the garbage collector timer, then immediately ``unref`` it. +Observe how after 9 seconds, when the fake job is done, the program +automatically exits, even though the garbage collector is still running. + +Idler pattern +------------- + +The callbacks of idle handles are invoked once per event loop. The idle +callback can be used to perform some very low priority activity. For example, +you could dispatch a summary of the daily application performance to the +developers for analysis during periods of idleness, or use the application's +CPU time to perform SETI calculations :) An idle watcher is also useful in +a GUI application. Say you are using an event loop for a file download. If the +TCP socket is still being established and no other events are present your +event loop will pause (**block**), which means your progress bar will freeze +and the user will face an unresponsive application. In such a case queue up and +idle watcher to keep the UI operational. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c + :linenos: + :lines: 5-9, 34- + :emphasize-lines: 13 + +Here we initialize the idle watcher and queue it up along with the actual +events we are interested in. ``crunch_away`` will now be called repeatedly +until the user types something and presses Return. Then it will be interrupted +for a brief amount as the loop deals with the input data, after which it will +keep calling the idle callback again. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c + :linenos: + :lines: 10-19 + +.. _baton: + +Passing data to worker thread +----------------------------- + +When using ``uv_queue_work`` you'll usually need to pass complex data through +to the worker thread. The solution is to use a ``struct`` and set +``uv_work_t.data`` to point to it. A slight variation is to have the +``uv_work_t`` itself as the first member of this struct (called a baton [#]_). +This allows cleaning up the work request and all the data in one free call. + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + struct ftp_baton { + uv_work_t req; + char *host; + int port; + char *username; + char *password; + } + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton)); + baton->req.data = (void*) baton; + baton->host = strdup("my.webhost.com"); + baton->port = 21; + // ... + + uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup); + +Here we create the baton and queue the task. + +Now the task function can extract the data it needs: + +.. code-block:: c + :linenos: + :emphasize-lines: 2, 12 + + void ftp_session(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + fprintf(stderr, "Connecting to %s\n", baton->host); + } + + void ftp_cleanup(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + free(baton->host); + // ... + free(baton); + } + +We then free the baton which also frees the watcher. + +External I/O with polling +------------------------- + +Usually third-party libraries will handle their own I/O, and keep track of +their sockets and other files internally. In this case it isn't possible to use +the standard stream I/O operations, but the library can still be integrated +into the libuv event loop. All that is required is that the library allow you +to access the underlying file descriptors and provide functions that process +tasks in small increments as decided by your application. Some libraries though +will not allow such access, providing only a standard blocking function which +will perform the entire I/O transaction and only then return. It is unwise to +use these in the event loop thread, use the :ref:`libuv-work-queue` instead. Of +course, this will also mean losing granular control on the library. + +The ``uv_poll`` section of libuv simply watches file descriptors using the +operating system notification mechanism. In some sense, all the I/O operations +that libuv implements itself are also backed by ``uv_poll`` like code. Whenever +the OS notices a change of state in file descriptors being polled, libuv will +invoke the associated callback. + +Here we will walk through a simple download manager that will use libcurl_ to +download files. Rather than give all control to libcurl, we'll instead be +using the libuv event loop, and use the non-blocking, async multi_ interface to +progress with the download whenever libuv notifies of I/O readiness. + +.. _libcurl: http://curl.haxx.se/libcurl/ +.. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html + +.. rubric:: uvwget/main.c - The setup +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 1-9,140- + :emphasize-lines: 7,21,24-25 + +The way each library is integrated with libuv will vary. In the case of +libcurl, we can register two callbacks. The socket callback ``handle_socket`` +is invoked whenever the state of a socket changes and we have to start polling +it. ``start_timeout`` is called by libcurl to notify us of the next timeout +interval, after which we should drive libcurl forward regardless of I/O status. +This is so that libcurl can handle errors or do whatever else is required to +get the download moving. + +Our downloader is to be invoked as:: + + $ ./uvwget [url1] [url2] ... + +So we add each argument as an URL + +.. rubric:: uvwget/main.c - Adding urls +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 39-56 + :emphasize-lines: 13-14 + +We let libcurl directly write the data to a file, but much more is possible if +you so desire. + +``start_timeout`` will be called immediately the first time by libcurl, so +things are set in motion. This simply starts a libuv `timer `_ which +drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it +times out. ``curl_multi_socket_action`` is what drives libcurl, and what we +call whenever sockets change state. But before we go into that, we need to poll +on sockets whenever ``handle_socket`` is called. + +.. rubric:: uvwget/main.c - Setting up polling +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 102-140 + :emphasize-lines: 9,11,15,21,24 + +We are interested in the socket fd ``s``, and the ``action``. For every socket +we create a ``uv_poll_t`` handle if it doesn't exist, and associate it with the +socket using ``curl_multi_assign``. This way ``socketp`` points to it whenever +the callback is invoked. + +In the case that the download is done or fails, libcurl requests removal of the +poll. So we stop and free the poll handle. + +Depending on what events libcurl wishes to watch for, we start polling with +``UV_READABLE`` or ``UV_WRITABLE``. Now libuv will invoke the poll callback +whenever the socket is ready for reading or writing. Calling ``uv_poll_start`` +multiple times on the same handle is acceptable, it will just update the events +mask with the new value. ``curl_perform`` is the crux of this program. + +.. rubric:: uvwget/main.c - Driving libcurl. +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 81-95 + :emphasize-lines: 2,6-7,12 + +The first thing we do is to stop the timer, since there has been some progress +in the interval. Then depending on what event triggered the callback, we set +the correct flags. Then we call ``curl_multi_socket_action`` with the socket +that progressed and the flags informing about what events happened. At this +point libcurl does all of its internal tasks in small increments, and will +attempt to return as fast as possible, which is exactly what an evented program +wants in its main thread. libcurl keeps queueing messages into its own queue +about transfer progress. In our case we are only interested in transfers that +are completed. So we extract these messages, and clean up handles whose +transfers are done. + +.. rubric:: uvwget/main.c - Reading transfer status. +.. literalinclude:: ../../code/uvwget/main.c + :linenos: + :lines: 58-79 + :emphasize-lines: 6,9-10,13-14 + +Check & Prepare watchers +------------------------ + +TODO + +Loading libraries +----------------- + +libuv provides a cross platform API to dynamically load `shared libraries`_. +This can be used to implement your own plugin/extension/module system and is +used by node.js to implement ``require()`` support for bindings. The usage is +quite simple as long as your library exports the right symbols. Be careful with +sanity and security checks when loading third party code, otherwise your +program will behave unpredictably. This example implements a very simple +plugin system which does nothing except print the name of the plugin. + +Let us first look at the interface provided to plugin authors. + +.. rubric:: plugin/plugin.h +.. literalinclude:: ../../code/plugin/plugin.h + :linenos: + +You can similarly add more functions that plugin authors can use to do useful +things in your application [#]_. A sample plugin using this API is: + +.. rubric:: plugin/hello.c +.. literalinclude:: ../../code/plugin/hello.c + :linenos: + +Our interface defines that all plugins should have an ``initialize`` function +which will be called by the application. This plugin is compiled as a shared +library and can be loaded by running our application:: + + $ ./plugin libhello.dylib + Loading libhello.dylib + Registered plugin "Hello World!" + +.. NOTE:: + + The shared library filename will be different depending on platforms. On + Linux it is ``libhello.so``. + +This is done by using ``uv_dlopen`` to first load the shared library +``libhello.dylib``. Then we get access to the ``initialize`` function using +``uv_dlsym`` and invoke it. + +.. rubric:: plugin/main.c +.. literalinclude:: ../../code/plugin/main.c + :linenos: + :lines: 7- + :emphasize-lines: 15, 18, 24 + +``uv_dlopen`` expects a path to the shared library and sets the opaque +``uv_lib_t`` pointer. It returns 0 on success, -1 on error. Use ``uv_dlerror`` +to get the error message. + +``uv_dlsym`` stores a pointer to the symbol in the second argument in the third +argument. ``init_plugin_function`` is a function pointer to the sort of +function we are looking for in the application's plugins. + +.. _shared libraries: http://en.wikipedia.org/wiki/Shared_library#Shared_libraries + +TTY +--- + +Text terminals have supported basic formatting for a long time, with a `pretty +standardised`_ command set. This formatting is often used by programs to +improve the readability of terminal output. For example ``grep --colour``. +libuv provides the ``uv_tty_t`` abstraction (a stream) and related functions to +implement the ANSI escape codes across all platforms. By this I mean that libuv +converts ANSI codes to the Windows equivalent, and provides functions to get +terminal information. + +.. _pretty standardised: http://en.wikipedia.org/wiki/ANSI_escape_sequences + +The first thing to do is to initialize a ``uv_tty_t`` with the file descriptor +it reads/writes from. This is achieved with:: + + int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable) + +Set ``readable`` to true if you plan to use ``uv_read_start()`` on the stream. + +It is then best to use ``uv_tty_set_mode`` to set the mode to *normal* +which enables most TTY formatting, flow-control and other settings. Other_ modes +are also available. + +.. _Other: http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t + +Remember to call ``uv_tty_reset_mode`` when your program exits to restore the +state of the terminal. Just good manners. Another set of good manners is to be +aware of redirection. If the user redirects the output of your command to +a file, control sequences should not be written as they impede readability and +``grep``. To check if the file descriptor is indeed a TTY, call +``uv_guess_handle`` with the file descriptor and compare the return value with +``UV_TTY``. + +Here is a simple example which prints white text on a red background: + +.. rubric:: tty/main.c +.. literalinclude:: ../../code/tty/main.c + :linenos: + :emphasize-lines: 11-12,14,17,27 + +The final TTY helper is ``uv_tty_get_winsize()`` which is used to get the +width and height of the terminal and returns ``0`` on success. Here is a small +program which does some animation using the function and character position +escape codes. + +.. rubric:: tty-gravity/main.c +.. literalinclude:: ../../code/tty-gravity/main.c + :linenos: + :emphasize-lines: 19,25,38 + +The escape codes are: + +====== ======================= +Code Meaning +====== ======================= +*2* J Clear part of the screen, 2 is entire screen +H Moves cursor to certain position, default top-left +*n* B Moves cursor down by n lines +*n* C Moves cursor right by n columns +m Obeys string of display settings, in this case green background (40+2), white text (30+7) +====== ======================= + +As you can see this is very useful to produce nicely formatted output, or even +console based arcade games if that tickles your fancy. For fancier control you +can try `ncurses`_. + +.. _ncurses: http://www.gnu.org/software/ncurses/ncurses.html + +---- + +.. [#] I was first introduced to the term baton in this context, in Konstantin + Käfer's excellent slides on writing node.js bindings -- + http://kkaefer.github.com/node-cpp-modules/#baton +.. [#] mfp is My Fancy Plugin + +.. _libev man page: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_OR_BOTH diff --git a/3rd/libuv-1.19.2/docs/src/handle.rst b/3rd/libuv-1.19.2/docs/src/handle.rst new file mode 100644 index 00000000..cdfb76bf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/handle.rst @@ -0,0 +1,264 @@ + +.. _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. + +Libuv handles are not movable. Pointers to handle structures passed to +functions must remain valid for the duration of the requested operation. Take +care when using stack allocated handles. + +Data types +---------- + +.. c:type:: uv_handle_t + + The base libuv handle type. + +.. c:type:: uv_handle_type + + The kind of the libuv handle. + + :: + + typedef enum { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX + } uv_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 allocate memory and fill the supplied + :c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length, + a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the + :c:type:`uv_read_cb` callback. + + A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, + not related in any way to the pending data to be read. The user is free to allocate the amount + of memory they decide. + + As an example, applications with custom allocation schemes such as using freelists, allocation + pools or slab based allocators may decide to use a different size which matches the memory + chunks they already have. + + Example: + + :: + + static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; + } + +.. 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:: uv_handle_type uv_handle_t.type + + The :c:type:`uv_handle_type`, indicating the type of the underlying handle. 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. + +.. c:function:: uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) + + Returns `handle->loop`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_get_data(const uv_handle_t* handle) + + Returns `handle->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data) + + Sets `handle->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_handle_type uv_handle_get_type(const uv_handle_t* handle) + + Returns `handle->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_handle_type_name(uv_handle_type type) + + Returns the name for the equivalent struct for a given handle type, + e.g. `"pipe"` (as in :c:type:`uv_pipe_t`) for `UV_NAMED_PIPE`. + + If no such handle type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 + +.. _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/3rd/libuv-1.19.2/docs/src/idle.rst b/3rd/libuv-1.19.2/docs/src/idle.rst new file mode 100644 index 00000000..1f51c4a1 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/index.rst b/3rd/libuv-1.19.2/docs/src/index.rst new file mode 100644 index 00000000..5ec2beb5 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/index.rst @@ -0,0 +1,62 @@ + +Welcome to the libuv 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 `_! + +.. _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 + + +Documentation +------------- + +.. toctree:: + :maxdepth: 1 + + design + api + guide + upgrading + + +Downloads +--------- + +libuv can be downloaded from `here `_. + + +Installation +------------ + +Installation instructions can be found in `the README `_. + diff --git a/3rd/libuv-1.19.2/docs/src/loop.rst b/3rd/libuv-1.19.2/docs/src/loop.rst new file mode 100644 index 00000000..86a99adf --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/loop.rst @@ -0,0 +1,236 @@ + +.. _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 and does not + touch this field. + + +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) + + Releases all internal loop resources. Call this function only when the loop + has finished executing and all open handles and requests have been closed, + or it will return UV_EBUSY. After this function returns, the user can 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. + + .. warning:: + This function is not thread safe. + +.. 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 referenced active handles, active + requests or closing handles 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`. + +.. c:function:: int uv_loop_fork(uv_loop_t* loop) + + .. versionadded:: 1.12.0 + + Reinitialize any kernel state necessary in the child process after + a :man:`fork(2)` system call. + + Previously started watchers will continue to be started in the + child process. + + It is necessary to explicitly call this function on every event + loop created in the parent process that you plan to continue to + use in the child, including the default loop (even if you don't + continue to use it in the parent). This function must be called + before calling :c:func:`uv_run` or any other API function using + the loop in the child. Failure to do so will result in undefined + behaviour, possibly including duplicate events delivered to both + parent and child or aborting the child process. + + When possible, it is preferred to create a new loop in the child + process instead of reusing a loop created in the parent. New loops + created in the child process after the fork should not use this + function. + + This function is not implemented on Windows, where it returns ``UV_ENOSYS``. + + .. caution:: + + This function is experimental. It may contain bugs, and is subject to + change or removal. API and ABI stability is not guaranteed. + + .. note:: + + On Mac OS X, if directory FS event handles were in use in the + parent process *for any event loop*, the child process will no + longer be able to use the most efficient FSEvent + implementation. Instead, uses of directory FS event handles in + the child will fall back to the same implementation used for + files and on other kqueue-based systems. + + .. caution:: + + On AIX and SunOS, FS event handles that were already started in + the parent process at the time of forking will *not* deliver + events in the child process; they must be closed and restarted. + On all other platforms, they will continue to work normally + without any further intervention. + + .. caution:: + + Any previous value returned from :c:func:`uv_backend_fd` is now + invalid. That function must be called again to determine the + correct backend file descriptor. + +.. c:function:: void* uv_loop_get_data(const uv_loop_t* loop) + + Returns `loop->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data) + + Sets `loop->data` to `data`. + + .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/migration_010_100.rst b/3rd/libuv-1.19.2/docs/src/migration_010_100.rst new file mode 100644 index 00000000..bb6ac1a8 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/misc.rst b/3rd/libuv-1.19.2/docs/src/misc.rst new file mode 100644 index 00000000..07908c98 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/misc.rst @@ -0,0 +1,519 @@ + +.. _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. + + .. c:member:: size_t uv_buf_t.len + + Total bytes in the buffer. + + .. 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_pid_t + + Cross platform representation of a `pid_t`. + + .. versionadded:: 1.16.0 + +.. 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 (X) */ + uint64_t ru_idrss; /* integral unshared data size (X) */ + uint64_t ru_isrss; /* integral unshared stack size (X) */ + uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps (X) */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent (X) */ + uint64_t ru_msgrcv; /* IPC messages received (X) */ + uint64_t ru_nsignals; /* signals received (X) */ + uint64_t ru_nvcsw; /* voluntary context switches (X) */ + uint64_t ru_nivcsw; /* involuntary context switches (X) */ + } uv_rusage_t; + + Members marked with `(X)` are unsupported on Windows. + See :man:`getrusage(2)` for supported fields on Unix + +.. 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; + +.. c:type:: uv_passwd_t + + Data type for password file information. + + :: + + typedef struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; + } uv_passwd_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. You *must* call `uv_setup_args` + before calling this function. If `buffer` is `NULL` or `size` is zero, + `UV_EINVAL` is returned. If `size` cannot accommodate the process title and + terminating `NULL` character, the function returns `UV_ENOBUFS`. + + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + +.. c:function:: int uv_set_process_title(const char* title) + + Sets the current process title. You *must* call `uv_setup_args` before + calling this function. On platforms with a fixed size buffer for the process + title the contents of `title` will be copied to the buffer and truncated if + larger than the available space. Other platforms will return `UV_ENOMEM` if + they cannot allocate enough space to duplicate the contents of `title`. + + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. + +.. 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. + See :c:type:`uv_rusage_t` for more details. + +.. c:function:: uv_pid_t uv_os_getpid(void) + + Returns the current process ID. + + .. versionadded:: 1.18.0 + +.. c:function:: uv_pid_t uv_os_getppid(void) + + Returns the parent process ID. + + .. versionadded:: 1.16.0 + +.. 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: ``_ + + .. 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:macro:: UV_IF_NAMESIZE + + Maximum IPv6 interface identifier name length. Defined as + `IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows. + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) + + IPv6-capable implementation of :man:`if_indextoname(3)`. When called, + `*size` indicates the length of the `buffer`, which is used to store the + result. + On success, zero is returned, `buffer` contains the interface name, and + `*size` represents the string length of the `buffer`, excluding the NUL + terminator byte from `*size`. On error, a negative result is + returned. If `buffer` is not large enough to hold the result, + `UV_ENOBUFS` is returned, and `*size` represents the necessary size in + bytes, including the NUL terminator byte into the `*size`. + + On Unix, the returned interface name can be used directly as an + interface identifier in scoped IPv6 addresses, e.g. + `fe80::abc:def1:2345%en0`. + + On Windows, the returned interface cannot be used as an interface + identifier, as Windows uses numerical interface identifiers, e.g. + `fe80::abc:def1:2345%5`. + + To get an interface identifier in a cross-platform compatible way, + use `uv_if_indextoiid()`. + + Example: + + :: + + char ifname[UV_IF_NAMESIZE]; + size_t size = sizeof(ifname); + uv_if_indextoname(sin6->sin6_scope_id, ifname, &size); + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) + + Retrieves a network interface identifier suitable for use in an IPv6 scoped + address. On Windows, returns the numeric `ifindex` as a string. On all other + platforms, `uv_if_indextoname()` is called. The result is written to + `buffer`, with `*size` indicating the length of `buffer`. If `buffer` is not + large enough to hold the result, then `UV_ENOBUFS` is returned, and `*size` + represents the size, including the NUL byte, required to hold the + result. + + See `uv_if_indextoname` for further details. + + .. versionadded:: 1.16.0 + +.. 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, and stores it in `buffer`. If the + current working directory is too large to fit in `buffer`, this function + returns `UV_ENOBUFS`, and sets `size` to the required length, including the + null terminator. + + .. versionchanged:: 1.1.0 + + On Unix the path no longer ends in a slash. + + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + +.. 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 `size` is set + to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_homedir()` is not thread safe. + + .. versionadded:: 1.6.0 + +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success `size` is set to the string length of `buffer` (which does not + include the terminating null). On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + +.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) + + Gets a subset of the password file entry for the current effective uid (not + the real uid). The populated data includes the username, euid, gid, shell, + and home directory. On non-Windows systems, all data comes from + :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no + meaning, and shell is `NULL`. After successfully calling this function, the + memory allocated to `pwd` needs to be freed with + :c:func:`uv_os_free_passwd`. + + .. versionadded:: 1.9.0 + +.. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) + + Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. + + .. versionadded:: 1.9.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 + +.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size) + + Retrieves the environment variable specified by `name`, copies its value + into `buffer`, and sets `size` to the string length of the value. When + calling this function, `size` must be set to the amount of storage available + in `buffer`, including the null terminator. If the environment variable + exceeds the storage available in `buffer`, `UV_ENOBUFS` is returned, and + `size` is set to the amount of storage required to hold the value. If no + matching environment variable exists, `UV_ENOENT` is returned. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_setenv(const char* name, const char* value) + + Creates or updates the environment variable specified by `name` with + `value`. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_unsetenv(const char* name) + + Deletes the environment variable specified by `name`. If no such environment + variable exists, this function returns successfully. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_gethostname(char* buffer, size_t* size) + + Returns the hostname as a null-terminated string in `buffer`, and sets + `size` to the string length of the hostname. When calling this function, + `size` must be set to the amount of storage available in `buffer`, including + the null terminator. If the hostname exceeds the storage available in + `buffer`, `UV_ENOBUFS` is returned, and `size` is set to the amount of + storage required to hold the value. + + .. versionadded:: 1.12.0 diff --git a/3rd/libuv-1.19.2/docs/src/pipe.rst b/3rd/libuv-1.19.2/docs/src/pipe.rst new file mode 100644 index 00000000..bdaeeba9 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/pipe.rst @@ -0,0 +1,113 @@ + +.. _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. + +.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags) + + Alters pipe permissions, allowing it to be accessed from processes run by + different users. Makes the pipe writable or readable by all users. Mode can + be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This + function is blocking. + + .. versionadded:: 1.16.0 diff --git a/3rd/libuv-1.19.2/docs/src/poll.rst b/3rd/libuv-1.19.2/docs/src/poll.rst new file mode 100644 index 00000000..aba89158 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/poll.rst @@ -0,0 +1,121 @@ + +.. _poll: + +:c:type:`uv_poll_t` --- Poll handle +=================================== + +Poll handles are used to watch file descriptors for readability, +writability and disconnection 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. + +.. note:: + On AIX, watching for disconnection is not supported. + +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, + UV_DISCONNECT = 4, + UV_PRIORITIZED = 8 + }; + + +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 made up of + UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. 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. + + The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band + messages. + + The UV_DISCONNECT event is optional in the sense that it may not be + reported and the user is free to ignore it, but it can help optimize the shutdown + path because an extra read or write call might be avoided. + + 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. + + .. note:: + Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set + on the `events` field in the callback. + + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event. + +.. 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/3rd/libuv-1.19.2/docs/src/prepare.rst b/3rd/libuv-1.19.2/docs/src/prepare.rst new file mode 100644 index 00000000..aca58155 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/process.rst b/3rd/libuv-1.19.2/docs/src/process.rst new file mode 100644 index 00000000..ecc3cbf3 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/process.rst @@ -0,0 +1,231 @@ + +.. _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. + +.. c:function:: uv_pid_t uv_process_get_pid(const uv_process_t* handle) + + Returns `handle->pid`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/request.rst b/3rd/libuv-1.19.2/docs/src/request.rst new file mode 100644 index 00000000..54d9a2f3 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/request.rst @@ -0,0 +1,109 @@ + +.. _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. + +.. c:function:: void* uv_req_get_data(const uv_req_t* req) + + Returns `req->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data) + + Sets `req->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_req_type uv_req_get_type(const uv_req_t* req) + + Returns `req->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_req_type_name(uv_req_type type) + + Returns the name for the equivalent struct for a given request type, + e.g. `"connect"` (as in :c:type:`uv_connect_t`) for `UV_CONNECT`. + + If no such request type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 diff --git a/3rd/libuv-1.19.2/docs/src/signal.rst b/3rd/libuv-1.19.2/docs/src/signal.rst new file mode 100644 index 00000000..24354e4f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/signal.rst @@ -0,0 +1,78 @@ + +.. _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. + +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. + +.. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. + +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_start_oneshot(uv_signal_t* signal, uv_signal_cb cb, int signum) + + .. versionadded:: 1.12.0 + + Same functionality as :c:func:`uv_signal_start` but the signal handler is reset the moment + the signal is received. + +.. 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/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py b/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py new file mode 100644 index 00000000..1d1dc379 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/docs/src/static/architecture.png b/3rd/libuv-1.19.2/docs/src/static/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..81e8749f2495741d4b4c2c5dd8a6bca8803d8818 GIT binary patch literal 206767 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

|<0@v3w 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 aM1obxbA2B^pWMfP?%y@PQ+oUP>;DChUmDi{ literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg new file mode 100644 index 0000000000000000000000000000000000000000..439f58109369c37760ce8f9b4710711c17993d8e GIT binary patch literal 19328 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 literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ffb21ff22457dac44441fb7e83272c72fbc4d59e GIT binary patch literal 12655 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 N?>yyS+aZMU{|8A0VY&bS literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip new file mode 100644 index 0000000000000000000000000000000000000000..17aedace14faf8f2990df3232565328901209d5a GIT binary patch literal 71160 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 + + + + Template: White (2014-02-28 09:41) + M6.2.2-1878-1 + + diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier new file mode 100644 index 00000000..ddb18f01 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier @@ -0,0 +1 @@ +F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA \ No newline at end of file diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist new file mode 100644 index 0000000000000000000000000000000000000000..74bc69317de4fc4ae87da8c71d1615385d70d1f2 GIT binary patch literal 340 zcmYc)$jK}&F)+B!$i&RT%Er#Y$;HjX%NJ3UT9#RynV%Pylb@WJlNytfpIn-onpYAU z>gf_)mRbao1G6)WeM@snG6NFRQ{x2$(=u~X-SUfa6HCG%Y9fm>5{ptnD&qyz4Xmup z3`|U&4UCL+jhsv!bxoX{O?55Y%*}M23@scDT}@4m%q)yTQ}g2eeBuRE+{`RpEuCE~ zbzNQE40TP6fZ8lw98GkADjm(;Tn!D4oE(A5h%u8h)KJez&wxln88{fk859`Q8B7=) l75HPbcg8&-~3o|P_8#_BY8yg!t2RA1> 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

2KUY7yz-7_`p(lc`HgEPC5(QDJ#Lr#t zQ^aB(fVC3L!ZYuq*lJP7o#$yPv1Q!V<6_&gb;|vv1XzW0l5+cH$-|XSlRBgvb2po>t_~klZ4LmXjqMiJc-Xb?uEcxH0v=emyM2q@q(h5iIU9fqCHwlg(>A%tIa9(ozERMq_yGzK|2@=orTX*I*A8ZzojexyQ?>JU2GShr=XdTQ z&Z8QWKcQ>ZmVo}2E_Zna+F2_vD!Uge$_Uv>JnzR5ul67(Kbn+ct5_|quZOV&_ZB~- zD^N9wFlV^q%@0U;cM%vcbU1;%obShM(_ag?O(TkYX4|9}6ZY;EtjQN#V8bLZQte<9 zz~TiKVF`U&8Tf!TNX6~Dd^%KYJ=u&~3Pb@&+&q1&6=-agis@Fobn5~=+M6_FF+X_k z_x(Q0KG)2x?HCMiIe48S^^YWDOZ}0e}1R!W2 zl#AwFr7MhWQG7RIlg7nRZT8g`pb2OUNOz(B??AUW+s7d+a5;Daduei-YE3d5V~S5}+Dt4cD;|oZXEY^ZVAgtLKJ7>pLRMtZseLG^40D;uRkDg>$^j+iSV%+(p5Ah z&-l%vPxw21Y5<&e(_I82D#AG6mrekGtpFDzs!sIol|zE_rJ}wXHaaWFp$x!wG2cFg zeJrtj3w3JI91Wm*`W_rZ{o7scqKHS?)<-yX>L>rNOUvYc2Elq6)b2_6Mw#Hyo{48~5WB4;8d z%1;L6Z{D59Mr6~UeGB4(Q@V#5p{W&7(tI_oRV=C0E!20=e0l!=2dc?|16#x#1Ol`WqxN zN}ZN?1?FXLJ)`8g1@pi}MucfD-I*DdM&e9)9Lj^WtVY)%ZANT-SRPJS19Wcw51kV@ z!dhcKJX%ayE{y8@amz#ps^&OsA6|9YnDSORnFr=AvG!juSE&bJ4wQp$$3JBc)$+O5 zB@f)e7r?_{OHF77T$(_-W2aA9BR7nSh7u-XmT0U>G95AJ8yuAT+oNLM33IRhJ1;H^ zX)WlcQq?n)#v#~D9iNy@8FJ;Qg?K-;oEjmG#>@9=Bzb>rbm~xLm5pm@N2hzNb9U~dHZsjgv$3M5QbTp&DXy2*LNI-G z3N6NND0D;k(=_W5NUr*EbB~bd9axJh6J+)2SMtwyU*1>+9oJ8xDw-kEtc*_yMFX|cO=kZSxwwf|Y(Ri24^z<8kqSmelGoEfegtKX&C^b^a=l9NrCN7h-zLtsbmHdV` zTUsn`Yn$+i|AFUA+O@>vy*|BiK zxVD;&MGCv@8b?Mstu*+BlW*q#^a$zLdEj`Xlv)t~TTc!Hb{yk@6@8Ns_kuY=T zSH&}n5>h~CNg0}~fd>|GgoN-RAWb1tq5+p9OHdhIjY-nvCWsetV}kTIaB{tG;jSBj zf3imWXafqef^_hMY2n?F8HoB+xdY;gr9;#|NA1}%PeV^{a9nA|+LdsbcVjmnqb%L) zTDJ6xjhQMlai3{6$^sd%ax9PMPehK!J~rV>H|xI|7VOBVUazfEhJ-2<^Ix3cQ{*{- z_v{rzs&0A5fj+!;M`gNK$e)bJH_!};KxsKmpCWA*r<;v`2|5c2am)i< zv=VbkVi0e3@~-rk!lPOq7I_JGdit0}WhVk*B+caPh9KPz<&HWznIP$)n|>tpztTD% z*S1cU9RqRG&p3i*HtCq7%irqwqlX*yNm}|>V@L;?&qvBfya!>c^N~Yx_?mk+C6yL> zSWgIwXrxt%mv($AC3Ey>J?Av;F!o^2fyl`wB|3W5n`z7q9Df|u7$|Ak1k z#81&ggqhdHvOGMA?jOLi3VTg0LU=(QfEcKAI!#Mb`r5I=Ep;w+aY{pUyjwcekNhCZ z8w#$TE}7%mk=^S$Omb9Zvf*J5=x)RTK)iSfdMvdwBr+@u{Wzf;a!TUl49Spst;i(4 z{wz3AJpG1N?Rc98i66)Yq<>c+8I%d+)DYU~X2gfdDGZbP_w8y|X9To7|EfVEJKDi$ z%^jPs!LqT2-c_JvvkNc`W_4y{g?_+RcQpUx`E+S1Oh-*!_nO9_0{mcp@V=gT!|up8 zNr;vL4ZHU{cNy9^1-l0h{Y?kIrE}^uH`PV=%$ghFfP^m`(B@7tJI$(tMJj9r-b_?x zKTteoMFZDLms_dlPtMxAn=;bF6gvGkK;MSO5^svp z(-1T>tz8p&ww^5iPI7pGF!03#N0#4pRIKULfY&E~;=9(t?$^mi3F|H5;ue{C9_7sh z<$F@gWT3HtFjoVKt-ckWNcx(1FN{Rjqbk%u6t-1CxSV-W8>B$ z86*(8M$AGbN0qNA!e;v2ppMcdhW0dz{3d&H#8cPsbn4+%K)JZ+;?sr5!NSjL1yXmK z+{Jot=Ug-MAQ_y8kIm-$YVI*zN!pp!!1f8Uf6u-aOVdNR-Py<%pDW4v_Lj*>kBhBg z&R6gEds(!u#WQlfJ?9OBOG7>S0-@%bH$bLl;LbwyPaF#KQUrCSK8!{E%_4=&nqOcc zS6*0>w)z+Qaw~@M(#r?hqA&sxNT|QbvV(xl%=NNwK%S;nD2{)1arXG77sL@B$d|!6 z{(jE)02u=wu|NCd2xC;Y*yp>KlVu$OYkw}BHgLv=PEDD8ZC2TJN_<2CA9z%Ib$#*9 zlQRhFc1Uo&#!&-s&R5aIrL-XN%hseN(fIl*=lq2UBncw% zhzi5u9?=Nf!+8Srl{_k+!mY>d>uO?el@pUAJ6{htoO;E&xqsGQQQBNJ)mBV`)mkC=6o!pe1I(?fE$0m%IFw6g-jR(GJI8XRg zofl9rwZTI+ptfKPhe>0!4Vt)w_<^d3RU5Lo5cmwgYYGD^Hw|uyFNqoa0gbp{>MQ;0 zmBBdeK0r;F88Y<~I|{tB^eu-)#ZHf0eHR?Z@C>pPTDS9{3ICN?Bz6RbZo&!V!1vxW zU@sN%#Xwm4vB7{J0s`5vg93 zdj-A@$o$5`O1vRB!lxMFr9U7nweSx%+KJUB^vC+w4Y9$b<(Ai_&vil6K##Mt!j8qT z8M6)(N){@LnJy;^K04joAW(Tw)LwR2ewcAhR^pMIF}+FXK+bY#UKYa2{__0By_|X( z0U$+lx2Z~5jZd~yM*j1&62MT-4@~f!lSWRZoo@fv z94rBVfn0p}|8e&JMV#?2Q(>vOe#p~JtN<{Z@@eXBZz=su0IzU=Nx;^_**1ysMop<> zY_p%dU5+*=%L;v5k`n+ToN2njUlm3lN9Q^kq~3e#Z0Nxt6dgvN800(s8sGXO>R#E< zNR=|r<0^{acDf}<%_5feupLqJ{+$U-Gt!AchF7ub>E(lVthD~G+pmVG|H7(6sp&xNc~_vH#OZ zCF0Rbks!rr!BgD4B&?l$iH6whmfiQjdV-uDe00TV)4hLjA$TVRh!iM{;M=S>;(@o) z8Ih6Sf$2%@w+XhEMt` zb~@o_Ie$Q_?w2P2N%lJbkUeiZm=w7bfu}~*Rot11DQKBU5vSm6jAtC4cm-0a?5(K9 z-@!f_ZDZPcxs7M2jhZ2S#aVI>1d?RcS5)$N`D5fqsdkWQ1b{V10Bdpo6V^s$nqRfn z+Z@~$m24+z^$WZ*hqd$jJ-Sj@>?^hDopJoC!a$GFm+xT@18bdh`G+exg?CQ;c%^I8 z*R5V6g*JFCIpY}XbzkYk2NB_{ z>@Hy97Ri$$;^BLmnG2R_ddc|!G{WBj|Q@nVjE zm?wvgh}N~$GwCsMVZP|XrBEvkRt&qs4i%b zZ(IHk#(2trrB>;2PLI{Q=D#=m2gF(^fu+{(dH)4gD_D01wt!$=|HJhEYh#@P2+&3^ ztiWpD_8mBoK@guG!`g3SeaMC?DUFJ+82+)k-~axLE-X-A@T9&)b9N(;PJdHFLES)` zEKOdoJD=9l{Yfi+A*avJTz|o=7fENgp*O38W+e5UdV#Gb?_#SDQyK0Jug_m+R9*_#nVy}$H(BjJU7%y#>#{rah{pV-{pI@@VP zTv`wIR%v&NbP~+cD@-B+oa!I93NMO>@fE?A!l2Uc4<;Rs=3&1mAtw&d{*OdQf8pXS z9PWDl2PA}Kf_*+M?KI_lw)h&DTVQ67cvod%s3%~y?r9Sb3LpOfK=^mY7uJ5W#fL@2 z-eY%1{<{Y3ND$h80l)O? zo&XRZsR1@(?G#wA$eLYeYWM{jg7rXJ{U=8BMGr4dF$36+|M@XYvv^Xg)lEi!k86-U z@bKow81P*E)yZ!6EoT}3fP_mx3j%6zk_+G#R{Gf!dx^Ee1Aa-(5`o;}2Rsr$Y%e%w z6yU@bZ;nml;JDA<{-S>jw%i58%RP3T9Ub$2(qCW$>-vyb-KDbf9eMYW55(G9H*bs-w%P(l2ofycq{qO?bR(mA^u+Crq zzHCf|4OeuVZGh3#4bk`@2=%|o#N_7J;pJgL*_Z$r(qH4+kD9AO1ssSwr?=jX+;KDk7`eMX4{D9-YKXP3WT zV6i%7EZ(&5->vnu@mcCu*zb7FnD+{zW}$M%Tu zZ4Q8|1~GeKfRl(*!SdpsN+AwcG41rPB@Z(3vl;IX6$KIrfo_TLPO}prNhnbVkN}|q zQn!}EOyv@8)HPEsEN<~~p^t61|C#a?|3Sw&u-P}-;fl+J+AIG52057j1n~t2Y707_0X?u_^ZB1FXZ**S(`SlvWDq&aW;2})yH;`Z+=jQeW#crp?`C`*68Tb;?3ck z2)z*{IxZ>ASOm!j7#wo*5riDGAb92z<7IdodNiZh|17+k{|($!v6oxF3t3IIPgo4l zlboM#5mp#i@P0E`A#-ouz%GHqYkB_YqJ%`4aGzxTA|d!188;QuJ{^;Q3jgs3#BkEP zhv(gre%I(kCU~nk&?K9;Sox|~L%Nvmncm3W-KJa#C0rhq%?tkKSBv}7Rbl)!8aeYh zqAH)j9_FwqYf&VH{76e+hb=yP@y-r{QUMy<*B6R6!DGrGyU8a+uvOF} zew7A0e}M(b5qjQ)+E@W@n1Ae?ms#;Jog!YuOIb3wZv{cgC!s9;ksaLQ?sp9STi~>8 z{+O+1F9u(}&=@&jupYVP=Z1PQ4XeWR z{HS8=HhNd)I16on-oG^KUL>|p^7avqZV~b3eeuoin<|XQ&6Fe;_}D=!=Y1!sz)?9*hjm;~x8<4LC6{Vsd~Q>S3mJZ;z8!I6Rp#$$_dSD?3) zC>@TUR}CN!SwFGLR#7|Yo){-{lJ&@gB}MpI)DJQ&Y0lsAj9RZC!ierFquGMEOv`ZD z^dp#qf*Gs*3m$4iXxEyRM8Vw=;w-B`%V2^IAf=;d0_T zau6}GGPdR7lRL;x!E1+})9!<8CJ0}vJ%{?;u$AcHh}XmjJKpg}gKVT!YTT`{FY!E; zW{*r@?QBqnVM(uACl-a)5#h34$oWJgq)ZL)Gs0zy0wBM%TNTzKyga;nT}GwB1o7C! z?;XlNV(>5u`-rsL^)j8jXXTU%E9^vwi=P8CdFk|;QXpm~uSiyrbjSVwfF*DCixGN2 z`259w#WDRvaW*jT+<02s2fa-JXz`-qk%QV>1(3pIW~!gee~sh2k$`skk;!f{LludY z^OJKpWwZigc9|2+qS%;%oP?aHZPeKD^vDSCfV&qhtepo>BbFUv$^~NGXNHpi8|dNP zm-c|!hC`*lKD8aiGg^Je5_Ooa}%9!26c4z@zZ= zHIb%=olQil^Gv6tufW-YX3`j6JQ)cJsYbLbvA{oJe3o)1Iqpy7LU@s+Rsw4W*RolkTJ1xj0`~_fU5Full|xy)>Vx{jiAPuK%IV0tQ-P)0nEocpuwI zChdkOnPEMWbLWJHv&=Ec%Y947Z>CQ4qsvd*A}ThU5Df4Wrezw%vTZ7+CD8?CMXaa( zFzsJkLusFf0E9p$`}EvI$rU0wXkCbOLZ{o-a{P!T$ptLN7N7RD*b(SzA&EK z%Tqm>R%fcl$U5~vpnik{mL)jI6W)oWw5w{eg|d$bnL^qs&7Q79vn1$_{d=&~=gaSR zBTj{xANy-x68-^Y8>Pi9{vFv5cDzUBs<$V_wW+!er!o4D(?Xkb^6G7I3}QJiIRX15 zJKVIyX{Glvc0$i7*7Rn5k|kac)i3c}ych(zyyLekjHRAhj((~qXWhNiiCT21lf=po zYF7RAUaW9!lbX;YCl=$J(_=ZaH)N2)cYe^@lV4(*ZTYkl@bPDdkUk?B}_oe6T7 zQ!(N*5+K4Yi)bx=VFL8&c^JA<=PDztL`otSWUHkynuTxapT#|h0s!_}dmA@mf z8}^%xQb%C8dVT=snem+k@o?P0uG>Eo?(ui^3Q1b62;%&tA{^7gS0$k&UE9EmT2zzh zff3HmM+nJUFF(y_Ql4pTaKkta`ke!JdyC5x{v7ICptNV9a=;?A~ftBVHh5& zA52-V;s#72KfY<&aWrflQUu4}el6FbvoPGLNfrH8Wa`6Pvdy1Y?|or%zYC18FHrNV z=3|}Gtc4@OD^6<@OCCU(g<3_3b8e&{_KApN=qcw7+=JZHLGv9ml!{YWy=N&;TYW)Gp>5}kt$ zbB}Xc1D1XAu7wbPhX?g#k5d>^jQuY46g!^z3U@ZzJY>w~~>Z6MDO=ydeT#7~1$zbG##`k_;EEep|4m zIG}v3_q{!vL?0t~dvZ}2iS^at0OncBPxNttiCd3wT<(5KmIPki`t+ZrYivd{PRs;4 zH<)eDY_j*HwB3_63PN``&CfTRgwMT<*Lg>NicJLo|4jhn0Qkjoq{Ldy^}A&!$Jgil zG2e0ga*(BjMY74|3`Cbe9-3)f-{#U>7GLwv`f`1$3r22`Zi-1&2m#7KiXI~eOTL=1 zVrl?O2N#H2}ut7*Bi&6vuXZ9+H2Wyl?o zrb&f}8Ch@1RSZHJGb8(QtaFUx^nJ$tH~L|IIj?!W=FI2$Jn!u}&vUL`ITzi8+ZgU} z!pCcEJ;Wp60zswQV!K~Vz3Q~Qcme-LYhHl^BhqM@BrB4>1)ug0-%?@rbDJz4J7{H~weU@WGyZc;3MbY_u!{=+Pj>2R}8P7*H8irN---eUXA#u$wVT18{p!cxglA5f$f^|EOVz0E1#j6Y`g zo%I||q7J)cqO#*qBY1$OO!&v|!=Zh_G(PR6yQE1+DsiS^2Q+RR2AlRuGEyF&xQT6{ z1lbAtcYu8}y8|O4`_ky9mjSbW{nu#73XjT)psM$i=PNrc18yXBZ6`77%(#rIib1=} zKm%+?F<-nM2s%t3Y)K9;F8=3KB+`Rr0L8dqHAuGp=$vj^qjQV9@&bpS87nqvoR)k0 zOAq4C=aTHX`G9h5SZktDIV~tx-%k%NJQlGpQ0`Chxjm=5ff99%+jqoEE2s%7M*mk` zu0z@Py9*E!&)OIr0*842gm>CCk6sbsSP5o6DTV9#Y7gwcZifc$Lh8%TTFp>D!JLI` z80Lrd^FHAcjo zr!9}^?qJZ74dZ-DIeEpisX}9vE&f78mnu}j1h_%L;u~G%d)xFwarz&L>02}Hxw;B; zH}Awko|dIjMgqMFr>0zCYhK0{!X#Gi6m@`xl^@1eb|NIqaz$4|RQXT>UUE$^i}Vwk z+9!Ss?(V9^mo~l@jz+Jtz(>*yuXg4uCD&CW%>6QcIIWXe|6Ph_G3RxRYzrYCf`E{I zjdNC8zBZ|%7Nx#&Az(7)!-uYFKJ_r4kXG2};_{Ak{q+X-x8Qmf?4Ww&g*O~`tY524 z?@zIxHS(5mNu=mXDTg!pE%ixwrAz7bMUzLQL9ST?YrVnSI}0mH&NXg4yVp^hONJtO zu-@Z(@05e*%es(@(i$x`yO@2mL>UKRR#yfpX8=8%h&c?z#a_pC`xNa$=|y`cSGGwc z&@@p198?xj6E3JPw7%jAMzbF3_b`Cd_@8x^U05SU@dc*y))J-!1R{M6K7XNqrBawv z`7f^=BysqcCrj|KKBlfEsNsGPc+B{VZt|w{oEW_o=i1G)x;YZ5lFvkU!AECFyE+aONjmpSBRb%vw_k2Kp$Xn{z9%yFn@W4;RO~)MERM>DjY*>x-2 zM5M#rn#M6W7dSbb{6~tpbyZwRVQq6>`ZrbjhwguS0r-3JchTg0?D5KhAE>G0?!68x zOSV{sCLK}s<{KdVN#cw_I&C1{{XKmdPNsT!(5{YAe!32Pc6m^CO{85yM9utRq&Keu zc-F%eeL(^e#`)`=qPph!z@^3SQmC8?R5+_tF4Erl>MRcNit(qdh*U7`MF&B}uEYMD zhk{AX%9umpf$K(tLFXI291UXK`Knn8UQe_>UUqzr2YgX+IbMxy^5o*OSwog$llhWY zj4SP3$#4w-cQxqok=LO$^u~z93ftFQy_2qw|5V0)$a)Dh9g(m9ta0nimb3Hn#aB2- z@>hF4&kv5xJM;b>>Di@ObILdGf8Jr;H1AWfBOc{(kxY_f>i@>|eC?H@B+iHcoDr(- z}Ik)i>9+)liQUO7QPL{vM z(|Sr=ZT{nxcKy3!ih>k3yj>Odq%GBT$9{ZnfP`5@tym#8hHP^+FRY|Kvl-1<_|+dg zKyZpH!m3o82AE`q2(;E4qT{@V$Fs)1KbaxQ1it=@%Z}9!o7(z)4%0g2iWX?FKCO=8 z%=1s1!R3Blh5~oAE;((+w6E&KIQ#}noX*~yP=^gB256r)u)amVz)XH*m}L**l&4SS z1=}cba>tgM0WLuf({bi!7z;Uv8>{G+`k7blAAn6MwwUqbfjr0&9~+T$;k~GFQTrpI z0eoB6hC8_mq8Om!zMQ5MDuy~ll9t9QN3F62t0jI8?o$DwSOvQ-0+@(O;(mtRg( zq$O6H?QgA3wK^(8gk@R-ec+eQ&r^KAOC9gv+mE!L(T$$h?{2LEbHRvzlxB3Gz$|gW zEyB1fU-K3?X7}77ac8SHDrW&D9kbp!8M3_A;%)Ih;Hs!<#j89s8nqRU+9Yayc4>so zjNF73tDSTOAd&8q24L^$cd35Od-|w%NiA4iyKPV2cE7L1$@1jp?^11cT$RxA4Oqqn zz;4a_yBWsM;6ausswW6RTUSY-V;|WGnymJlGF{oY-%5k^ND8%hB2P$)Qe{7A_7_kw zE;^_x*N?a)!^-`gI&hcz^Q4J~cM@-tkG+h-US6Hja{67PsIq(sxc&v(SqvGGlx+5h zjvv#f3f~7vgfy=i3_g~gbpW#R*A@(aU>OC=Ja zV@=)(*plXRsOi8(^dZ59C*Gpy1Qa|7iO#!CQXHDDnTdK)1@!J3@qhXx6n@L!Cg2$+ zl7ChC^-IXMtMnsNMQ7pRf$U0+U^0;(pz+(;tXI;kZVbVqbrleZdP7#E<~_87k%125 z!Jhl+u)bLx(;RUL4-t&Rwasa`eB~y}+?E|YctH|I zf9=|d6g`^Rf|1A{FqwX_;jGFZ-0f%qHh#*jth}<|pMrFc#l7nWJ28l{i9$Hoj|-)Z zSg22%EykR}9fTaM>A|aC8#2C{?#jWOz|mMjP9W;*%;wpo*$}QCDG4? zoG^oGuBCreG~MVXpBZ2aPa4sa*_an?eU_g5*QMQ2kJk$4A|McuOYB9vj6GHLjdp5?^cUO% z8kTVp7)w^Y%5~0iQ1fQ|FugChbZI4f|7w90I9k<8T}*ShrLItQxn0qV7r1g1`MLCO zG6Bj=pboAP(AM*)-E4*eM=Y-iS;?bvdQi5bGW8NxWh@&V1qe#!fQ%`svKWB$?Zb$E zx=)LG!pDmi_KfDShrn_ux<+LSsBz4~*(poA{ANRu7pg-w?$kqo;<_<(+O%KmoYonj zxS}jdhABa)92P1#5g!~4(_MbQvM9b?iu|1tdjb+6%Io-X_ZrJ`4mD=wx8Zc|_gKs4x-Z6|Er^^@gkqj2nsM6pN!(sY7G@H`{E9uc)s+yN~x)2Q8`-RL~BdW(YlnuyL}Lc~9v; z2EXLU2GtGsaYXy0^8eESJk-$c)Ny&;=>a@!5L!o)4upJtdxA8Vz3;YcEDqC;O&B?? zXRBb9dT>gSqUPr(lj*Nk{!qcAt7}9raob&8`@FL|iUy=Ce%_V-Lf)*>Sk>Ll&D~B_ Y>c{6t4Sw{%j~@8Z1FJo-=6lco0p?d?5&!@I literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/favicon.ico b/3rd/libuv-1.19.2/docs/src/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2c40694cd282ff3d0db2c495c23f3beca40c17fa GIT binary patch literal 15086 zcmeI3J!oE47{^bE(6L>dlR?3;f?AMDoTP|gC(+GON^N!X18j$O66~NjsaQd=(xSMC zL)z#dI2x#nOSZwR!m3x7+NM_xVsKV)SFb<|EpaeeASlj(+q}%U2&yoPD*;Lm&Ey_UhK~ z_4og5Xr+DRP_sk!#l?%;Y8ZWV*^pfGuZHnl8XJu9Yiq#y(Ek|pp24Oo_K^744vEX% z&VG-&+OikQSk~Z?A1-gL|EIsK{O26#L%+nJ84qMmd3jchtG#hWC&Nw%vpc1cK(nJjju2B;@Lx= zdb$)`edHiu4|NQ8|RdXF;=Y~_aQds zM-KRv4+sy(@ZfC92gKI6;H2E;6K(qX-UX~%j0>mIj{8FYL$I_j$2@PzKi(Uqj$`zO z#4L5N(?>*Nx>uvT*8k+fg{fl8rQ8qrD`mB~$cC=BvHB2S^BB zo_6@a7e4Xb##oy-YQyg-4(0Y@Zd<>ncpwkI?I z#(nm2&Rk}dLs#8nOwJ%bGaw_^Z@yn{`_@$KJMZd%`rc^{L%16&qPZZ8yy&yXqHe8E zp4v^DL$+J0`R4$#?Y4)|~%PII2w6MbC!=E%c&^QfI|YuvXc=!{*1Y4?qsL2`h* z$o-C7&RrON*x$_I{LppiJ7@Zwgz&bZi%;^2d%G)#^1eckdtnIwS=8R#;7=cfx8p9} zQLZlb%I^mM$iuvbtO1gd?cjn{}^(OGIzMtu55|%vU*fmf#WDj|cBmZ3E&ULE z^DEBxoq?V3_c`Snao@w)J2O5Htv$MtTiLJ8Ps<-ZzF*?kddj;CIdjfw6M5D+I$xWc zhQGY!fnWQebuQ(MwWVLXOObWGTVP`@;#mIJ;fE&YSX18%)QRXmF?Jtf*EjFnSpH>g zJddJ&XMw)QMPI~mOn)r@Xj{7voZk&B*MxEA-}y5>b8-Dk``zH!=QGwGJ^1uJznGg9 z|1$TION}?{8}*_O`a|A9*KPP*J_HMHIpwG&wQL$C-RQE%*QsQ_U2XFL*_t?GB)|p zoTFdrz*D)r%G#KV^AR(r&U;7R5&a!b^kMysGZx8@XQ0nP@+p19c=pHC-WnK_JFI=lYsh%FxQ85$b^U(; zyvsXi2xoM5o45Q$;<>lsOiqr6az+ok?5p#43dY+lgu~eV!XCTR_3p~Qe5cL4mf+UW zmb(1x$@eO7H!864g(1E`#3$lv{^Anj&Bm9F=&$E59)YX*%ShmI{=yP?CV$TeB#Hb_ z`=8LKQ_5!f8%mqFnE#H7@%+D--L>Nu^WRyOxXOI~8?33Y;%}S(z@z1r`L%pA%3o~Y ik^kAsb9poGOsuT~U&vzKIyJc*jGI?B>sZ!zWBd=1T7Db= literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/logo.png b/3rd/libuv-1.19.2/docs/src/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eaf1eee577b6774c345d5e21be51130a23b16627 GIT binary patch literal 33545 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 W3*P8um*8Y!7&$3rXpMwP!2bZAf*ghb literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png b/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png new file mode 100644 index 0000000000000000000000000000000000000000..e769cf338b4456ea688b0abf888b646a4253e0eb GIT binary patch literal 80528 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 literal 0 HcmV?d00001 diff --git a/3rd/libuv-1.19.2/img/logos.svg b/3rd/libuv-1.19.2/img/logos.svg new file mode 100644 index 00000000..d6185f8b --- /dev/null +++ b/3rd/libuv-1.19.2/img/logos.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3rd/libuv-1.19.2/include/android-ifaddrs.h b/3rd/libuv-1.19.2/include/android-ifaddrs.h new file mode 100644 index 00000000..9cd19fec --- /dev/null +++ b/3rd/libuv-1.19.2/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 . Note that if 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 + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/3rd/libuv-1.19.2/include/pthread-barrier.h b/3rd/libuv-1.19.2/include/pthread-barrier.h new file mode 100644 index 00000000..07db9b8a --- /dev/null +++ b/3rd/libuv-1.19.2/include/pthread-barrier.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#if !defined(__MVS__) +#include /* sem_t */ +#endif + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 +#define UV__PTHREAD_BARRIER_FALLBACK 1 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#else +# define UV_BARRIER_STRUCT_PADDING 0 +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} 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 /* _UV_PTHREAD_BARRIER_ */ diff --git a/3rd/libuv-1.19.2/include/stdint-msvc2008.h b/3rd/libuv-1.19.2/include/stdint-msvc2008.h new file mode 100644 index 00000000..d02608a5 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap 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 +#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 +#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/3rd/libuv-1.19.2/include/tree.h b/3rd/libuv-1.19.2/include/tree.h new file mode 100644 index 00000000..f936416e --- /dev/null +++ b/3rd/libuv-1.19.2/include/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * 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/3rd/libuv-1.19.2/include/uv-aix.h b/3rd/libuv-1.19.2/include/uv-aix.h new file mode 100644 index 00000000..7dc992fa --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-bsd.h b/3rd/libuv-1.19.2/include/uv-bsd.h new file mode 100644 index 00000000..2d72b3d7 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-darwin.h b/3rd/libuv-1.19.2/include/uv-darwin.h new file mode 100644 index 00000000..d2264158 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +# include +# include +# include +# 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/3rd/libuv-1.19.2/include/uv-errno.h b/3rd/libuv-1.19.2/include/uv-errno.h new file mode 100644 index 00000000..aa4d4509 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-errno.h @@ -0,0 +1,437 @@ +/* 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 +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + +#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 UV__ERR(E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES UV__ERR(EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE UV__ERR(EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN UV__ERR(EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY UV__ERR(EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF UV__ERR(EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY UV__ERR(EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED UV__ERR(ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET UV__ERR(ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED UV__ERR(ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET UV__ERR(ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST UV__ERR(EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT UV__ERR(EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR UV__ERR(EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL UV__ERR(EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO UV__ERR(EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN UV__ERR(EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR UV__ERR(EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP UV__ERR(ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE UV__ERR(EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE UV__ERR(EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN UV__ERR(ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH UV__ERR(ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE UV__ERR(ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS UV__ERR(ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV UV__ERR(ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT UV__ERR(ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM UV__ERR(ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET UV__ERR(ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC UV__ERR(ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS UV__ERR(ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN UV__ERR(ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR UV__ERR(ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK UV__ERR(ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP UV__ERR(ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM UV__ERR(EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE UV__ERR(EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO UV__ERR(EPROTO) +#else +# define UV__EPROTO UV__ERR(4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS UV__ERR(EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE UV__ERR(ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH UV__ERR(ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY UV__ERR(ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV UV__ERR(EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG UV__ERR(EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE UV__ERR(ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO UV__ERR(ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + +#if defined(EMLINK) && !defined(_WIN32) +# define UV__EMLINK UV__ERR(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 UV__ERR(EHOSTDOWN) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) +# define UV__EHOSTDOWN (-64) +#else +# define UV__EHOSTDOWN (-4031) +#endif + +#if defined(EREMOTEIO) && !defined(_WIN32) +# define UV__EREMOTEIO UV__ERR(EREMOTEIO) +#else +# define UV__EREMOTEIO (-4030) +#endif + +#if defined(ENOTTY) && !defined(_WIN32) +# define UV__ENOTTY UV__ERR(ENOTTY) +#else +# define UV__ENOTTY (-4029) +#endif + + +#endif /* UV_ERRNO_H_ */ diff --git a/3rd/libuv-1.19.2/include/uv-linux.h b/3rd/libuv-1.19.2/include/uv-linux.h new file mode 100644 index 00000000..9b38405a --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-os390.h b/3rd/libuv-1.19.2/include/uv-os390.h new file mode 100644 index 00000000..39e7384d --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-os390.h @@ -0,0 +1,33 @@ +/* Copyright 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. + */ + +#ifndef UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#define UV_PLATFORM_LOOP_FIELDS \ + void* ep; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + char rfis_rftok[8]; \ + +#endif /* UV_MVS_H */ diff --git a/3rd/libuv-1.19.2/include/uv-posix.h b/3rd/libuv-1.19.2/include/uv-posix.h new file mode 100644 index 00000000..9a96634d --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-posix.h @@ -0,0 +1,31 @@ +/* Copyright 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. + */ + +#ifndef UV_POSIX_H +#define UV_POSIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + struct pollfd* poll_fds; \ + size_t poll_fds_used; \ + size_t poll_fds_size; \ + unsigned char poll_fds_iterating; \ + +#endif /* UV_POSIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-sunos.h b/3rd/libuv-1.19.2/include/uv-sunos.h new file mode 100644 index 00000000..04216642 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/include/uv-threadpool.h b/3rd/libuv-1.19.2/include/uv-threadpool.h new file mode 100644 index 00000000..9708ebdd --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/include/uv-unix.h b/3rd/libuv-1.19.2/include/uv-unix.h new file mode 100644 index 00000000..da32f86e --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-unix.h @@ -0,0 +1,464 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(__MVS__) +#include +#endif +#include +#include + +#include "uv-threadpool.h" + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined (__MVS__) +# include "uv-os390.h" +#elif defined(_PASE) +# include "uv-posix.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(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#elif defined(__CYGWIN__) || defined(__MSYS__) +# include "uv-posix.h" +#endif + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.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_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 +}; + +#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; +typedef pid_t uv_pid_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; +typedef pthread_barrier_t uv_barrier_t; + + +/* 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]; \ + void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ + uv__io_t async_io_watcher; \ + int async_wfd; \ + 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 \ + +/* fs open() flags supported on this platform: */ +#if defined(O_APPEND) +# define UV_FS_O_APPEND O_APPEND +#else +# define UV_FS_O_APPEND 0 +#endif +#if defined(O_CREAT) +# define UV_FS_O_CREAT O_CREAT +#else +# define UV_FS_O_CREAT 0 +#endif +#if defined(O_DIRECT) +# define UV_FS_O_DIRECT O_DIRECT +#else +# define UV_FS_O_DIRECT 0 +#endif +#if defined(O_DIRECTORY) +# define UV_FS_O_DIRECTORY O_DIRECTORY +#else +# define UV_FS_O_DIRECTORY 0 +#endif +#if defined(O_DSYNC) +# define UV_FS_O_DSYNC O_DSYNC +#else +# define UV_FS_O_DSYNC 0 +#endif +#if defined(O_EXCL) +# define UV_FS_O_EXCL O_EXCL +#else +# define UV_FS_O_EXCL 0 +#endif +#if defined(O_EXLOCK) +# define UV_FS_O_EXLOCK O_EXLOCK +#else +# define UV_FS_O_EXLOCK 0 +#endif +#if defined(O_NOATIME) +# define UV_FS_O_NOATIME O_NOATIME +#else +# define UV_FS_O_NOATIME 0 +#endif +#if defined(O_NOCTTY) +# define UV_FS_O_NOCTTY O_NOCTTY +#else +# define UV_FS_O_NOCTTY 0 +#endif +#if defined(O_NOFOLLOW) +# define UV_FS_O_NOFOLLOW O_NOFOLLOW +#else +# define UV_FS_O_NOFOLLOW 0 +#endif +#if defined(O_NONBLOCK) +# define UV_FS_O_NONBLOCK O_NONBLOCK +#else +# define UV_FS_O_NONBLOCK 0 +#endif +#if defined(O_RDONLY) +# define UV_FS_O_RDONLY O_RDONLY +#else +# define UV_FS_O_RDONLY 0 +#endif +#if defined(O_RDWR) +# define UV_FS_O_RDWR O_RDWR +#else +# define UV_FS_O_RDWR 0 +#endif +#if defined(O_SYMLINK) +# define UV_FS_O_SYMLINK O_SYMLINK +#else +# define UV_FS_O_SYMLINK 0 +#endif +#if defined(O_SYNC) +# define UV_FS_O_SYNC O_SYNC +#else +# define UV_FS_O_SYNC 0 +#endif +#if defined(O_TRUNC) +# define UV_FS_O_TRUNC O_TRUNC +#else +# define UV_FS_O_TRUNC 0 +#endif +#if defined(O_WRONLY) +# define UV_FS_O_WRONLY O_WRONLY +#else +# define UV_FS_O_WRONLY 0 +#endif + +/* fs open() flags supported on other platforms: */ +#define UV_FS_O_RANDOM 0 +#define UV_FS_O_SHORT_LIVED 0 +#define UV_FS_O_SEQUENTIAL 0 +#define UV_FS_O_TEMPORARY 0 + +#endif /* UV_UNIX_H */ diff --git a/3rd/libuv-1.19.2/include/uv-version.h b/3rd/libuv-1.19.2/include/uv-version.h new file mode 100644 index 00000000..c2753d51 --- /dev/null +++ b/3rd/libuv-1.19.2/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 19 +#define UV_VERSION_PATCH 2 +#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/3rd/libuv-1.19.2/include/uv-win.h b/3rd/libuv-1.19.2/include/uv-win.h new file mode 100644 index 00000000..4c6c50a2 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv-win.h @@ -0,0 +1,676 @@ +/* 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 0x0600 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include + +#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 +#include +#include + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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 int uv_pid_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 */ \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + 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; + +#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 + +/* fs open() flags supported on this platform: */ +#define UV_FS_O_APPEND _O_APPEND +#define UV_FS_O_CREAT _O_CREAT +#define UV_FS_O_EXCL _O_EXCL +#define UV_FS_O_RANDOM _O_RANDOM +#define UV_FS_O_RDONLY _O_RDONLY +#define UV_FS_O_RDWR _O_RDWR +#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL +#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED +#define UV_FS_O_TEMPORARY _O_TEMPORARY +#define UV_FS_O_TRUNC _O_TRUNC +#define UV_FS_O_WRONLY _O_WRONLY + +/* fs open() flags supported on other platforms (or mapped on this platform): */ +#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECTORY 0 +#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ +#define UV_FS_O_NOATIME 0 +#define UV_FS_O_NOCTTY 0 +#define UV_FS_O_NOFOLLOW 0 +#define UV_FS_O_NONBLOCK 0 +#define UV_FS_O_SYMLINK 0 +#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/3rd/libuv-1.19.2/include/uv.h b/3rd/libuv-1.19.2/include/uv.h new file mode 100644 index 00000000..9794d996 --- /dev/null +++ b/3rd/libuv-1.19.2/include/uv.h @@ -0,0 +1,1567 @@ +/* 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 +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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") \ + XX(EREMOTEIO, "remote I/O error") \ + XX(ENOTTY, "inappropriate ioctl for device") \ + +#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 struct uv_passwd_s uv_passwd_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_loop_fork(uv_loop_t* loop); + +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 int uv_translate_sys_error(int sys_errno); + +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 uv_handle_type uv_handle_get_type(const uv_handle_t* handle); +UV_EXTERN const char* uv_handle_type_name(uv_handle_type type); +UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle); +UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle); +UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data); + +UV_EXTERN size_t uv_req_size(uv_req_type type); +UV_EXTERN void* uv_req_get_data(const uv_req_t* req); +UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data); +UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req); +UV_EXTERN const char* uv_req_type_name(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 size_t uv_stream_get_write_queue_size(const uv_stream_t* stream); + +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_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); +UV_EXTERN size_t uv_udp_get_send_queue_count(const 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(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); +UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); + + +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_DISCONNECT = 4, + UV_PRIORITIZED = 8 +}; + +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_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*); + + +/* + * 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; +}; + +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + +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); +UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); + +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_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); +UV_EXTERN uv_pid_t uv_os_getpid(void); +UV_EXTERN uv_pid_t uv_os_getppid(void); + +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); + +UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); +UV_EXTERN int uv_os_setenv(const char* name, const char* value); +UV_EXTERN int uv_os_unsetenv(const char* name); + +UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); + + +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_COPYFILE +} 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 uv_fs_type uv_fs_get_type(const uv_fs_t*); +UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); +UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); +UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); +UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); + +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); +/* + * This flag can be used with uv_fs_copyfile() to return an error if the + * destination already exists. + */ +#define UV_FS_COPYFILE_EXCL 0x0001 + +UV_EXTERN int uv_fs_copyfile(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_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_start_oneshot(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); + +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE (IFNAMSIZ + 1) +#else +# define UV_IF_NAMESIZE (16 + 1) +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, + char* buffer, + size_t* size); +UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, + char* buffer, + size_t* size); + +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 int uv_mutex_init_recursive(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 +}; + +UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); +UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); + +/* 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 +#undef UV__ERR + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/3rd/libuv-1.19.2/libuv.pc.in b/3rd/libuv-1.19.2/libuv.pc.in new file mode 100644 index 00000000..55c4b65d --- /dev/null +++ b/3rd/libuv-1.19.2/libuv.pc.in @@ -0,0 +1,12 @@ +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. +URL: http://libuv.org/ + +Libs: -L${libdir} -luv @LIBS@ +Cflags: -I${includedir} diff --git a/3rd/libuv-1.19.2/m4/.gitignore b/3rd/libuv-1.19.2/m4/.gitignore new file mode 100644 index 00000000..c44e4c29 --- /dev/null +++ b/3rd/libuv-1.19.2/m4/.gitignore @@ -0,0 +1,4 @@ +# Ignore libtoolize-generated files. +*.m4 +!as_case.m4 +!libuv-check-flags.m4 diff --git a/3rd/libuv-1.19.2/m4/as_case.m4 b/3rd/libuv-1.19.2/m4/as_case.m4 new file mode 100644 index 00000000..c7ae0f0f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 b/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 new file mode 100644 index 00000000..59c30635 --- /dev/null +++ b/3rd/libuv-1.19.2/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à +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/3rd/libuv-1.19.2/samples/.gitignore b/3rd/libuv-1.19.2/samples/.gitignore new file mode 100644 index 00000000..f868091b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore b/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore new file mode 100644 index 00000000..c177f374 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE b/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE new file mode 100644 index 00000000..63c1447f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp b/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp new file mode 100644 index 00000000..771a1e14 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/samples/socks5-proxy/client.c b/3rd/libuv-1.19.2/samples/socks5-proxy/client.c new file mode 100644 index 00000000..aa2a91c9 --- /dev/null +++ b/3rd/libuv-1.19.2/samples/socks5-proxy/client.c @@ -0,0 +1,736 @@ +/* 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 +#include +#include + +/* 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); +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) { + conn *c; + + 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/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h b/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h new file mode 100644 index 00000000..99ee8160 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* sockaddr_in, sockaddr_in6 */ +#include /* size_t, ssize_t */ +#include +#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c b/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c new file mode 100644 index 00000000..8481b226 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +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/3rd/libuv-1.19.2/samples/socks5-proxy/main.c b/3rd/libuv-1.19.2/samples/socks5-proxy/main.c new file mode 100644 index 00000000..04020cbd --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#if HAVE_UNISTD_H +#include /* 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

[-h] [-p ]\n" + "\n" + "Options:\n" + "\n" + " -b Bind to this address or hostname.\n" + " Default: \"127.0.0.1\"\n" + " -h Show this help message.\n" + " -p Bind to this port number. Default: 1080\n" + "", + progname); + exit(1); +} diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c new file mode 100644 index 00000000..4f08e345 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include /* abort() */ +#include /* 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/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h b/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h new file mode 100644 index 00000000..715f3222 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/samples/socks5-proxy/server.c b/3rd/libuv-1.19.2/samples/socks5-proxy/server.c new file mode 100644 index 00000000..3f1ba42c --- /dev/null +++ b/3rd/libuv-1.19.2/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 /* INET6_ADDRSTRLEN */ +#include +#include + +#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/3rd/libuv-1.19.2/samples/socks5-proxy/util.c b/3rd/libuv-1.19.2/samples/socks5-proxy/util.c new file mode 100644 index 00000000..af34f055 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/src/fs-poll.c b/3rd/libuv-1.19.2/src/fs-poll.c new file mode 100644 index 00000000..ee73d5a2 --- /dev/null +++ b/3rd/libuv-1.19.2/src/fs-poll.c @@ -0,0 +1,256 @@ +/* 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 +#include +#include + +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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ctx->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + 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/3rd/libuv-1.19.2/src/heap-inl.h b/3rd/libuv-1.19.2/src/heap-inl.h new file mode 100644 index 00000000..1e2ed60e --- /dev/null +++ b/3rd/libuv-1.19.2/src/heap-inl.h @@ -0,0 +1,245 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 /* 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/3rd/libuv-1.19.2/src/inet.c b/3rd/libuv-1.19.2/src/inet.c new file mode 100644 index 00000000..da63a688 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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/3rd/libuv-1.19.2/src/queue.h b/3rd/libuv-1.19.2/src/queue.h new file mode 100644 index 00000000..ff3540a0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/queue.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 + +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/3rd/libuv-1.19.2/src/threadpool.c b/3rd/libuv-1.19.2/src/threadpool.c new file mode 100644 index 00000000..413d1c20 --- /dev/null +++ b/3rd/libuv-1.19.2/src/threadpool.c @@ -0,0 +1,318 @@ +/* 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" +#endif + +#include + +#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 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; + + uv_sem_post((uv_sem_t*) arg); + arg = NULL; + + 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 (nthreads == 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; +} +#endif + + +static void init_threads(void) { + unsigned int i; + const char* val; + uv_sem_t sem; + + 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); + + if (uv_sem_init(&sem, 0)) + abort(); + + for (i = 0; i < nthreads; i++) + if (uv_thread_create(threads + i, worker, &sem)) + abort(); + + for (i = 0; i < nthreads; i++) + uv_sem_wait(&sem); + + uv_sem_destroy(&sem); +} + + +#ifndef _WIN32 +static void reset_once(void) { + uv_once_t child_once = UV_ONCE_INIT; + memcpy(&once, &child_once, sizeof(child_once)); +} +#endif + + +static void init_once(void) { +#ifndef _WIN32 + /* Re-initialize the threadpool after fork. + * Note that this discards the global mutex and condition as well + * as the work queue. + */ + if (pthread_atfork(NULL, NULL, &reset_once)) + abort(); +#endif + init_threads(); +} + + +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/3rd/libuv-1.19.2/src/unix/aix-common.c b/3rd/libuv-1.19.2/src/unix/aix-common.c new file mode 100644 index 00000000..e17e4494 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/aix-common.c @@ -0,0 +1,292 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +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 UV_EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return UV_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 UV__ERR(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 UV_EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return UV_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 UV_EINVAL; + } +} + +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, inet6, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return UV__ERR(errno); + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(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) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return UV_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; + + inet6 = (p->ifr_addr.sa_family == AF_INET6); + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return UV_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 (inet6) + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return UV_ENOSYS; + } + + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); + + 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); +} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/aix.c b/3rd/libuv-1.19.2/src/unix/aix.c new file mode 100644 index 00000000..92de8148 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/aix.c @@ -0,0 +1,1041 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#ifdef HAVE_SYS_AHAFS_EVPRODS_H +#include +#endif + +#include +#include +#include +#include +#include + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static void* args_mem = NULL; +static char** process_argv = NULL; +static int process_argc = 0; +static char* process_title_ptr = NULL; + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +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; + } +} + + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + + return uv__platform_loop_init(loop); +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return UV__ERR(errno); + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + +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 have_signals; + 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; + } + + have_signals = 0; + 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; + } + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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_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 UV__ERR(errno); + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return UV__ERR(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 UV__ERR(errno); + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return UV__ERR(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 && errno != EEXIST) + 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 UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* 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"); + + /* In file / directory move cases, AIX Event infrastructure + * produces a second event with no data. + * Ignore it and return gracefully. + */ + if(bytes == 0) + return; + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* Unrecoverable error */ + if (rc == -1) + return; + + /* 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; + } else { + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else + p++; + } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; + + handle->cb(handle, 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 UV_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, str_offset = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char readlink_cwd[PATH_MAX]; + + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + } else { + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); + } + + 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(filename); + handle->cb = cb; + handle->dir_filename = NULL; + + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + + return 0; +#else + return UV_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 UV_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) { + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Save the original pointer to argv. + * AIX uses argv to read the process name. + * (Not the memory pointed to by argv[0..n] as on Linux.) + */ + process_argv = argv; + process_argc = argc; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + /* 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) { + char* new_title; + + /* We cannot free this pointer when libuv shuts down, + * the process may still be using it. + */ + new_title = uv__strdup(title); + if (new_title == NULL) + return UV_ENOMEM; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + /* If this is the first time this is set, + * don't free and set argv[1] to NULL. + */ + if (process_title_ptr != NULL) + uv__free(process_title_ptr); + + process_title_ptr = new_title; + + process_argv[0] = process_title_ptr; + if (process_argc > 1) + process_argv[1] = NULL; + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + len = strlen(process_argv[0]); + if (buffer == NULL || size == 0) + return UV_EINVAL; + else if (size <= len) + return UV_ENOBUFS; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + memcpy(buffer, process_argv[0], len + 1); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} + + +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 UV__ERR(errno); + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = UV_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; + + boot_time = 0; + 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 UV_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 UV_ENOSYS; + } + + ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); + if (result == -1) { + return UV_ENOSYS; + } + + ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); + if (!ps_cpus) { + return UV_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 UV_ENOSYS; + } + + *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + uv__free(ps_cpus); + return UV_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__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/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c new file mode 100644 index 00000000..bf30b141 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c @@ -0,0 +1,710 @@ +/* +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 +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(pid_t *p_pid) +{ + struct sockaddr_nl l_addr; + socklen_t l_len; + + 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; + } + + l_len = sizeof(l_addr); + if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) + { + close(l_socket); + return -1; + } + *p_pid = l_addr.nl_pid; + + 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, pid_t p_pid, 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) + { + 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 != p_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, pid_t p_pid) +{ + 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, p_pid, &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 = IFA_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_rtaDataSize + 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 = IFA_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); + unsigned 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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +{ + + int l_numLinks = 0; + 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 != p_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, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +{ + 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 != p_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; + pid_t l_pid; + NetlinkList *l_linkResults; + NetlinkList *l_addrResults; + + if(!ifap) + { + return -1; + } + *ifap = NULL; + + l_socket = netlink_socket(&l_pid); + if(l_socket < 0) + { + return -1; + } + + l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + l_result = 0; + l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, 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/3rd/libuv-1.19.2/src/unix/async.c b/3rd/libuv-1.19.2/src/unix/async.c new file mode 100644 index 00000000..0b450ae0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/async.c @@ -0,0 +1,269 @@ +/* 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 +#include /* snprintf() */ +#include +#include +#include +#include + +static void uv__async_send(uv_loop_t* loop); +static int uv__async_start(uv_loop_t* loop); +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); + 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); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + QUEUE_REMOVE(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + char buf[1024]; + ssize_t r; + QUEUE queue; + QUEUE* q; + uv_async_t* h; + + assert(w == &loop->async_io_watcher); + + for (;;) { + r = read(w->fd, buf, sizeof(buf)); + + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + 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_send(uv_loop_t* loop) { + const void* buf; + ssize_t len; + int fd; + int r; + + buf = ""; + len = 1; + fd = loop->async_wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = loop->async_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(); +} + + +static int uv__async_start(uv_loop_t* loop) { + int pipefd[2]; + int err; + + if (loop->async_io_watcher.fd != -1) + return 0; + + err = uv__async_eventfd(); + if (err >= 0) { + pipefd[0] = err; + pipefd[1] = -1; + } + else if (err == UV_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(&loop->async_io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &loop->async_io_watcher, POLLIN); + loop->async_wfd = pipefd[1]; + + return 0; +} + + +int uv__async_fork(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) /* never started */ + return 0; + + uv__async_stop(loop); + + return uv__async_start(loop); +} + + +void uv__async_stop(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) + return; + + if (loop->async_wfd != -1) { + if (loop->async_wfd != loop->async_io_watcher.fd) + uv__close(loop->async_wfd); + loop->async_wfd = -1; + } + + uv__io_stop(loop, &loop->async_io_watcher, POLLIN); + uv__close(loop->async_io_watcher.fd); + loop->async_io_watcher.fd = -1; +} + + +static int uv__async_eventfd(void) { +#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 UV__ERR(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 UV__ERR(errno); + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return UV_ENOSYS; +} diff --git a/3rd/libuv-1.19.2/src/unix/atomic-ops.h b/3rd/libuv-1.19.2/src/unix/atomic-ops.h new file mode 100644 index 00000000..7cac1f98 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/atomic-ops.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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 +#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; +#elif defined(__MVS__) + unsigned int op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) + return oldval; + else + return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_uint(ptr, oldval, newval); +#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; +#elif defined (__MVS__) +#ifdef _LP64 + unsigned long long op4; + if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, + (unsigned long long*) ptr, *ptr, &op4)) +#else + unsigned long op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) +#endif + return oldval; + else + return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_ulong(ptr, oldval, newval); +#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/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c b/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c new file mode 100644 index 00000000..0d021544 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c @@ -0,0 +1,152 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +#include +#include +#if !defined(__CYGWIN__) && !defined(__MSYS__) +#include +#endif + +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; +#if !defined(__CYGWIN__) && !defined(__MSYS__) + /* + * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` + * equals to `AF_LINK` or not. Otherwise, the result depends on the operation + * system with `AF_LINK` or `PF_INET`. + */ + if (exclude_type == UV__EXCLUDE_IFPHYS) + return (ent->ifa_addr->sa_family != AF_LINK); +#endif +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + /* + * On BSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + return 1; +#elif defined(__NetBSD__) + if (ent->ifa_addr->sa_family != PF_INET && + ent->ifa_addr->sa_family != PF_INET6) + return 1; +#elif defined(__OpenBSD__) + if (ent->ifa_addr->sa_family != PF_INET) + return 1; +#endif + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs* addrs; + struct ifaddrs* ent; + uv_interface_address_t* address; + int i; + + if (getifaddrs(&addrs) != 0) + return UV__ERR(errno); + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + continue; + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (*addresses == NULL) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) + continue; + + address = *addresses; + + for (i = 0; i < *count; i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { +#if defined(__CYGWIN__) || defined(__MSYS__) + memset(address->phys_addr, 0, sizeof(address->phys_addr)); +#else + struct sockaddr_dl* sa_addr; + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); +#endif + } + 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/3rd/libuv-1.19.2/src/unix/core.c b/3rd/libuv-1.19.2/src/unix/core.c new file mode 100644 index 00000000..3741c1d0 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/core.c @@ -0,0 +1,1355 @@ +/* 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 /* NULL */ +#include /* printf */ +#include +#include /* strerror */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* INT_MAX, PATH_MAX, IOV_MAX */ +#include /* writev */ +#include /* getrusage */ +#include + +#ifdef __sun +# include /* MAXHOSTNAMELEN on Solaris */ +# include +# include +# include +#endif + +#ifdef __APPLE__ +# include /* _NSGetExecutablePath */ +# include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif +#endif + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) +# include +# include +# include +# define UV__O_CLOEXEC O_CLOEXEC +# if defined(__FreeBSD__) && __FreeBSD__ >= 10 +# define uv__accept4 accept4 +# endif +# if defined(__NetBSD__) +# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) +# endif +# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) +# 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 + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + +#if defined(__MVS__) +#include +#endif + +#if !defined(__MVS__) +#include /* MAXHOSTNAMELEN on Linux and the BSDs */ +#endif + +/* Fallback for the maximum hostname length */ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#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(!uv__is_closing(handle)); + + 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 UV_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 UV_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 UV__ERR(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 UV__ERR(errno); +#endif + + sockfd = socket(domain, type, protocol); + if (sockfd == -1) + return UV__ERR(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; +} + +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd < 0) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + + +int uv__accept(int sockfd) { + int peerfd; + int err; + + assert(sockfd >= 0); + + while (1) { +#if defined(__linux__) || \ + (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ + defined(__NetBSD__) + 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 UV__ERR(errno); + + no_accept4 = 1; +skip: +#endif + + peerfd = accept(sockfd, NULL, NULL); + if (peerfd == -1) { + if (errno == EINTR) + continue; + return UV__ERR(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_nocheckstdio(int fd) { + int saved_errno; + int rc; + + assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ + + saved_errno = errno; + rc = close(fd); + if (rc == -1) { + rc = UV__ERR(errno); + if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) + rc = 0; /* The close is in progress, not an error. */ + errno = saved_errno; + } + + return rc; +} + + +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ +#if defined(__MVS__) + epoll_file_close(fd); +#endif + return uv__close_nocheckstdio(fd); +} + + +int uv__nonblock_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, FIONBIO, &set); + while (r == -1 && errno == EINTR); + + if (r) + return UV__ERR(errno); + + return 0; +} + + +#if !defined(__CYGWIN__) && !defined(__MSYS__) +int uv__cloexec_ioctl(int fd, int set) { + int r; + + do + r = ioctl(fd, set ? FIOCLEX : FIONCLEX); + while (r == -1 && errno == EINTR); + + if (r) + return UV__ERR(errno); + + return 0; +} +#endif + + +int uv__nonblock_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFL); + while (r == -1 && errno == EINTR); + + if (r == -1) + return UV__ERR(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 UV__ERR(errno); + + return 0; +} + + +int uv__cloexec_fcntl(int fd, int set) { + int flags; + int r; + + do + r = fcntl(fd, F_GETFD); + while (r == -1 && errno == EINTR); + + if (r == -1) + return UV__ERR(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 UV__ERR(errno); + + return 0; +} + + +/* 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 UV__ERR(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 UV__ERR(errno); + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return UV__ERR(errno); + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return UV__ERR(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 UV_EINVAL; + + if (getcwd(buffer, *size) == NULL) + return UV__ERR(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 UV__ERR(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 UV_EINVAL; + } + + if (uv__is_closing(handle) || fd_out == -1) + return UV_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, 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + 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) + 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + 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, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + 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 & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); + assert(0 != events); + return 0 != (w->pevents & events); +} + + +int uv_getrusage(uv_rusage_t* rusage) { + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + return UV__ERR(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; + +#if !defined(__MVS__) + 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; +#endif + + return 0; +} + + +int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(UV__O_CLOEXEC) + static int no_cloexec; + + if (!no_cloexec) { + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return UV__ERR(errno); + + /* O_CLOEXEC not supported. */ + no_cloexec = 1; + } +#endif + + fd = open(path, flags); + if (fd == -1) + return UV__ERR(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) || defined(__NetBSD__) + r = dup3(oldfd, newfd, O_CLOEXEC); + if (r == -1) + return UV__ERR(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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + + err = uv__cloexec(newfd, 1); + if (err) { + uv__close(newfd); + return err; + } + + return r; + } +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + char* buf; + size_t len; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Check if the HOME environment variable is set first */ + buf = getenv("HOME"); + + if (buf != NULL) { + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + + return 0; + } + + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return UV_ENOSYS; +#endif + + if (pwd == NULL) + return UV_EINVAL; + + initsize = sysconf(_SC_GETPW_R_SIZE_MAX); + + if (initsize <= 0) + bufsize = 4096; + else + bufsize = (size_t) initsize; + + uid = geteuid(); + buf = NULL; + + for (;;) { + uv__free(buf); + buf = uv__malloc(bufsize); + + if (buf == NULL) + return UV_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 UV_ENOENT; + } + + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); + + if (pwd->username == NULL) { + uv__free(buf); + return UV_ENOMEM; + } + + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + + uv__free(buf); + + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + The memory for name, shell, and homedir are allocated in a single + uv__malloc() call. The base of the pointer is stored in pwd->username, so + that is the field that needs to be freed. + */ + uv__free(pwd->username); + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} + + +int uv_translate_sys_error(int sys_errno) { + /* If < 0 then it's already a libuv error. */ + return sys_errno <= 0 ? sys_errno : -sys_errno; +} + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + char* var; + size_t len; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + var = getenv(name); + + if (var == NULL) + return UV_ENOENT; + + len = strlen(var); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, var, len + 1); + *size = len; + + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + if (name == NULL || value == NULL) + return UV_EINVAL; + + if (setenv(name, value, 1) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + if (name == NULL) + return UV_EINVAL; + + if (unsetenv(name) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_gethostname(char* buffer, size_t* size) { + /* + On some platforms, if the input buffer is not large enough, gethostname() + succeeds, but truncates the result. libuv can detect this and return ENOBUFS + instead by creating a large enough buffer and comparing the hostname length + to the size input. + */ + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (gethostname(buf, sizeof(buf)) != 0) + return UV__ERR(errno); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return fd; +} + + +uv_pid_t uv_os_getpid(void) { + return getpid(); +} + + +uv_pid_t uv_os_getppid(void) { + return getppid(); +} diff --git a/3rd/libuv-1.19.2/src/unix/cygwin.c b/3rd/libuv-1.19.2/src/unix/cygwin.c new file mode 100644 index 00000000..9fe4093e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/cygwin.c @@ -0,0 +1,54 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +int uv_uptime(double* uptime) { + struct sysinfo info; + + if (sysinfo(&info) < 0) + return UV__ERR(errno); + + *uptime = info.uptime; + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + /* FIXME: read /proc/meminfo? */ + *rss = 0; + return UV_ENOSYS; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + /* FIXME: read /proc/stat? */ + *cpu_infos = NULL; + *count = 0; + return UV_ENOSYS; +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + (void)cpu_infos; + (void)count; +} diff --git a/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c b/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c new file mode 100644 index 00000000..dabde223 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c @@ -0,0 +1,209 @@ +/* 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 +#include +#include +#include + +#include + +#if !TARGET_OS_IPHONE +# include +# include +#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 UV_ENOSYS; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + err = dynamic_pthread_setname_np(namebuf); + if (err) + return UV__ERR(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 = UV_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 = UV_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 = UV_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/3rd/libuv-1.19.2/src/unix/darwin.c b/3rd/libuv-1.19.2/src/unix/darwin.c new file mode 100644 index 00000000..31ad8a9e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/darwin.c @@ -0,0 +1,231 @@ +/* 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 +#include +#include + +#include +#include +#include /* _NSGetExecutablePath */ +#include +#include +#include /* sysconf */ + + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->cf_state = NULL; + + if (uv__kqueue_init(loop)) + return UV__ERR(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 UV_EINVAL; + + exepath_size = sizeof(exepath); + if (_NSGetExecutablePath(exepath, &exepath_size)) + return UV_EIO; + + if (realpath(exepath, abspath) != abspath) + return UV__ERR(errno); + + abspath_size = strlen(abspath); + if (abspath_size == 0) + return UV_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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + } + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) + return UV__ERR(errno); + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, + (processor_info_array_t*)&info, + &msg_type) != KERN_SUCCESS) { + return UV_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 UV_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); +} diff --git a/3rd/libuv-1.19.2/src/unix/dl.c b/3rd/libuv-1.19.2/src/unix/dl.c new file mode 100644 index 00000000..fc1c052b --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +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/3rd/libuv-1.19.2/src/unix/freebsd.c b/3rd/libuv-1.19.2/src/unix/freebsd.c new file mode 100644 index 00000000..70ccb130 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/freebsd.c @@ -0,0 +1,375 @@ +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include /* VM_LOADAVG */ +#include +#include +#include /* sysconf */ +#include + +#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 uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +#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 UV_EINVAL; + + abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); + if (abspath_size < 0) + return UV__ERR(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 UV_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 UV__ERR(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 UV__ERR(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 UV__ERR(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]; + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_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); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\0'; + + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + struct kinfo_proc kinfo; + size_t page_size; + size_t kinfo_size; + int mib[4]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + kinfo_size = sizeof(kinfo); + + if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) + return UV__ERR(errno); + + page_size = getpagesize(); + +#ifdef __DragonFly__ + *rss = kinfo.kp_vm_rssize * page_size; +#else + *rss = kinfo.ki_rssize * page_size; +#endif + + return 0; +} + + +int uv_uptime(double* uptime) { + int r; + struct timespec sp; + r = clock_gettime(CLOCK_MONOTONIC, &sp); + if (r) + return UV__ERR(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; + const char* model_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 + +#if defined(__arm__) || defined(__aarch64__) + /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ + model_key = "hw.machine"; + cpuspeed = 0; +#else + model_key = "hw.model"; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) + return -errno; +#endif + + size = sizeof(model); + if (sysctlbyname(model_key, &model, &size, NULL, 0)) + return UV__ERR(errno); + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return UV_ENOMEM; + + *count = numcpus; + + /* 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)) { + uv__free(*cpu_infos); + return UV__ERR(errno); + } + + size = maxcpus * CPUSTATES * sizeof(long); + + cp_times = uv__malloc(size); + if (cp_times == NULL) { + uv__free(*cpu_infos); + return UV_ENOMEM; + } + + if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return UV__ERR(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); +} diff --git a/3rd/libuv-1.19.2/src/unix/fs.c b/3rd/libuv-1.19.2/src/unix/fs.c new file mode 100644 index 00000000..92e2d255 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/fs.c @@ -0,0 +1,1513 @@ +/* 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 +#include +#include +#include +#include /* PATH_MAX */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_PREADV 1 +#else +# define HAVE_PREADV 0 +#endif + +#if defined(__linux__) || defined(__sun) +# include +#endif + +#if defined(__APPLE__) +# include +#endif + +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + UV_REQ_INIT(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->bufs = 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) \ + return UV_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) \ + return UV_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__req_register(loop, req); \ + 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_fsync(uv_fs_t* req) { +#if defined(__APPLE__) + /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache + * to the drive platters. This is in contrast to Linux's fdatasync and fsync + * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we should fall back to fsync(). This is the + * same approach taken by sqlite. + */ + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0 && errno == ENOTTY) + r = fsync(req->file); + return r; +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); +#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 = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(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 = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(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(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__sun) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; +# if defined(__sun) + return futimesat(req->file, NULL, tv); +# else + return futimes(req->file, tv); +# endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); +#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) + 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(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) +#define UV_CONST_DIRENT uv__dirent_t +#else +#define UV_CONST_DIRENT const uv__dirent_t +#endif + + +static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) { + return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; +} + + +static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { + return strcmp((*a)->d_name, (*b)->d_name); +} + + +static ssize_t uv__fs_scandir(uv_fs_t* req) { + uv__dirent_t **dents; + int n; + + dents = NULL; + n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort); + + /* NOTE: We will use nbufs as an index field */ + req->nbufs = 0; + + if (n == 0) { + /* OS X still needs to deallocate some memory. + * Memory was allocated using the system allocator, so use free() here. + */ + free(dents); + dents = NULL; + } else if (n == -1) { + return n; + } + + req->ptr = dents; + + 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 +#error "PATH_MAX undefined in the current platform" +#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; + } + +#if defined(__MVS__) + len = os390_readlink(req->path, buf, len); +#else + len = readlink(req->path, buf, len); +#endif + + + 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(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) + { + 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); +#elif defined(__FreeBSD_kernel__) + len = 0; + r = bsd_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 ssize_t uv__fs_copyfile(uv_fs_t* req) { +#if defined(__APPLE__) && !TARGET_OS_IPHONE + /* On macOS, use the native copyfile(3). */ + copyfile_flags_t flags; + + flags = COPYFILE_ALL; + + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + + return copyfile(req->path, req->new_path, NULL, flags); +#else + uv_fs_t fs_req; + uv_file srcfd; + uv_file dstfd; + struct stat statsbuf; + int dst_flags; + int result; + int err; + size_t bytes_to_send; + int64_t in_offset; + + dstfd = -1; + err = 0; + + /* Open the source file. */ + srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); + uv_fs_req_cleanup(&fs_req); + + if (srcfd < 0) + return srcfd; + + /* Get the source file's mode. */ + if (fstat(srcfd, &statsbuf)) { + err = UV__ERR(errno); + goto out; + } + + dst_flags = O_WRONLY | O_CREAT | O_TRUNC; + + if (req->flags & UV_FS_COPYFILE_EXCL) + dst_flags |= O_EXCL; + + /* Open the destination file. */ + dstfd = uv_fs_open(NULL, + &fs_req, + req->new_path, + dst_flags, + statsbuf.st_mode, + NULL); + uv_fs_req_cleanup(&fs_req); + + if (dstfd < 0) { + err = dstfd; + goto out; + } + + if (fchmod(dstfd, statsbuf.st_mode) == -1) { + err = UV__ERR(errno); + goto out; + } + + bytes_to_send = statsbuf.st_size; + in_offset = 0; + while (bytes_to_send != 0) { + err = uv_fs_sendfile(NULL, + &fs_req, + dstfd, + srcfd, + in_offset, + bytes_to_send, + NULL); + uv_fs_req_cleanup(&fs_req); + if (err < 0) + break; + bytes_to_send -= fs_req.result; + in_offset += fs_req.result; + } + +out: + if (err < 0) + result = err; + else + result = 0; + + /* Close the source file. */ + err = uv__close_nocheckstdio(srcfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Close the destination file if it is open. */ + if (dstfd >= 0) { + err = uv__close_nocheckstdio(dstfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Remove the destination file if something went wrong. */ + if (result != 0) { + uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); + /* Ignore the unlink return value, as an error already happened. */ + uv_fs_req_cleanup(&fs_req); + } + } + + return result; +#endif +} + +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_atimensec; + dst->st_mtim.tv_sec = src->st_mtime; + dst->st_mtim.tv_nsec = src->st_mtimensec; + dst->st_ctim.tv_sec = src->st_ctime; + dst->st_ctim.tv_nsec = src->st_ctimensec; + dst->st_birthtim.tv_sec = src->st_ctime; + dst->st_birthtim.tv_nsec = src->st_ctimensec; + dst->st_flags = 0; + dst->st_gen = 0; +#elif !defined(_AIX) && ( \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + 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(__FreeBSD__) || \ + 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); + if (ret == 0) + 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); + if (ret == 0) + 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); + if (ret == 0) + 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 (errno == EINTR && total == -1) + return total; + + if (bufs != req->bufsml) + uv__free(bufs); + + req->bufs = NULL; + req->nbufs = 0; + + 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(COPYFILE, uv__fs_copyfile(req)); + 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, uv__fs_fsync(req)); + 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 = UV__ERR(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 == UV_ECANCELED) { + assert(req->result == 0); + req->result = UV_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) + return UV_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) { + INIT(READ); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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) + return UV_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) { + INIT(WRITE); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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) + return UV_ENOMEM; + + memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); + + req->off = off; + POST; +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + + /* 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->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + + if (req->ptr != &req->statbuf) + uv__free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + + PATH2; + req->flags = flags; + POST; +} diff --git a/3rd/libuv-1.19.2/src/unix/fsevents.c b/3rd/libuv-1.19.2/src/unix/fsevents.c new file mode 100644 index 00000000..47d8024b --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/fsevents.c @@ -0,0 +1,919 @@ +/* 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 +#include +#include +#include + +#include +#include + +/* 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; + FSEventStreamEventFlags flags; + 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++) { + flags = eventFlags[i]; + + /* Ignore system events */ + if (flags & 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; +#else + if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) + 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); + event->events = UV_RENAME; + +#ifdef MAC_OS_X_VERSION_10_7 + if (0 != (flags & kFSEventsModified) && + 0 == (flags & kFSEventsRenamed)) { + event->events = UV_CHANGE; + } +#else + if (0 != (flags & kFSEventsModified) && + 0 != (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { + event->events = UV_CHANGE; + } + if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { + event->events = UV_CHANGE; + } +#endif /* MAC_OS_X_VERSION_10_7 */ + + 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 UV_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; + + /* 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 = UV_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 = UV_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 = UV_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 = UV_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 UV_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 = UV_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 = UV__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 UV_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 UV__ERR(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 = UV_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 UV_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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/getaddrinfo.c b/3rd/libuv-1.19.2/src/unix/getaddrinfo.c new file mode 100644 index 00000000..10e8afd7 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/getaddrinfo.c @@ -0,0 +1,232 @@ +/* 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 +#include /* NULL */ +#include +#include +#include /* if_indextoname() */ + +/* EAI_* constants. */ +#include + + +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 UV__ERR(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 == UV_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 UV_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 UV_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); +} + + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + char ifname_buf[UV_IF_NAMESIZE]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (if_indextoname(ifindex, ifname_buf) == NULL) + return UV__ERR(errno); + + len = strnlen(ifname_buf, sizeof(ifname_buf)); + + if (*size <= len) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ifname_buf, len); + buffer[len] = '\0'; + *size = len; + + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + return uv_if_indextoname(ifindex, buffer, size); +} diff --git a/3rd/libuv-1.19.2/src/unix/getnameinfo.c b/3rd/libuv-1.19.2/src/unix/getnameinfo.c new file mode 100644 index 00000000..9a436722 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include + +#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 == 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_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/3rd/libuv-1.19.2/src/unix/ibmi.c b/3rd/libuv-1.19.2/src/unix/ibmi.c new file mode 100644 index 00000000..c50a4e76 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/ibmi.c @@ -0,0 +1,112 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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]) { + avg[0] = avg[1] = avg[2] = 0; + return; +} + + +int uv_resident_set_memory(size_t* rss) { + return UV_ENOSYS; +} + + +int uv_uptime(double* uptime) { + return UV_ENOSYS; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus, idx = 0; + uv_cpu_info_t* cpu_info; + + *cpu_infos = NULL; + *count = 0; + + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + + *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + return UV_ENOMEM; + } + + cpu_info = *cpu_infos; + for (idx = 0; idx < numcpus; idx++) { + cpu_info->speed = 0; + cpu_info->model = uv__strdup("unknown"); + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + cpu_info++; + } + *count = numcpus; + + return 0; +} \ No newline at end of file diff --git a/3rd/libuv-1.19.2/src/unix/internal.h b/3rd/libuv-1.19.2/src/unix/internal.h new file mode 100644 index 00000000..2bb3773c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/internal.h @@ -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. + */ + +#ifndef UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "uv-common.h" + +#include +#include /* abort */ +#include /* strrchr */ +#include /* O_CLOEXEC, may be */ +#include +#include + +#if defined(__STRICT_ANSI__) +# define inline __inline +#endif + +#if defined(__linux__) +# include "linux-syscalls.h" +#endif /* __linux__ */ + +#if defined(__MVS__) +# include "os390-syscalls.h" +#endif /* __MVS__ */ + +#if defined(__sun) +# include +# include +#endif /* __sun */ + +#if defined(_AIX) +# define reqevents events +# define rtnevents revents +# include +#else +# include +#endif /* _AIX */ + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +#endif + +#if defined(__ANDROID__) +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 + +#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 + +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 +#endif + +#ifdef POLLPRI +# define UV__POLLPRI POLLPRI +#else +# define UV__POLLPRI 0 +#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. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ +}; + +/* loop flags */ +enum { + UV_LOOP_BLOCK_SIGPROF = 1 +}; + +/* flags of excluding ifaddr */ +enum { + UV__EXCLUDE_IFPHYS, + UV__EXCLUDE_IFADDR +}; + +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]; +}; + + +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + +/* core */ +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(int fd, int set); +int uv__nonblock_ioctl(int fd, int set); +int uv__nonblock_fcntl(int fd, int set); +int uv__close(int fd); +int uv__close_nocheckstdio(int fd); +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); +int uv__io_check_fd(uv_loop_t* loop, int fd); +void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ +int uv__io_fork(uv_loop_t* loop); + +/* async */ +void uv__async_stop(uv_loop_t* loop); +int uv__async_fork(uv_loop_t* loop); + + +/* 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); +int uv__signal_loop_fork(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); +FILE* uv__open_file(const char* path); +int uv__getpwuid_r(uv_passwd_t* pwd); + + +#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__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; +} + +#if defined(__linux__) +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); +#endif + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/kqueue.c b/3rd/libuv-1.19.2/src/unix/kqueue.c new file mode 100644 index 00000000..a30fd730 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/kqueue.c @@ -0,0 +1,533 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Required on + * - Until at least FreeBSD 11.0 + * - Older versions of Mac OS X + * + * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp + */ +#ifndef EV_OOBAND +#define EV_OOBAND EV_FLAG1 +#endif + +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 UV__ERR(errno); + + uv__cloexec(loop->backend_fd, 1); + + return 0; +} + + +#if defined(__APPLE__) +static int uv__has_forked_with_cfrunloop; +#endif + +int uv__io_fork(uv_loop_t* loop) { + int err; + loop->backend_fd = -1; + err = uv__kqueue_init(loop); + if (err) + return err; + +#if defined(__APPLE__) + if (loop->cf_state != NULL) { + /* We cannot start another CFRunloop and/or thread in the child + process; CF aborts if you try or if you try to touch the thread + at all to kill it. So the best we can do is ignore it from now + on. This means we can't watch directories in the same way + anymore (like other BSDs). It also means we cannot properly + clean up the allocated resources; calling + uv__fsevents_loop_delete from uv_loop_close will crash the + process. So we sidestep the issue by pretending like we never + started it in the first place. + */ + uv__has_forked_with_cfrunloop = 1; + uv__free(loop->cf_state); + loop->cf_state = NULL; + } +#endif + return err; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = UV__ERR(errno); + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + +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 have_signals; + 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 & POLLIN) == 0 && (w->pevents & 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 & POLLOUT) == 0 && (w->pevents & 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; + } + } + + if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { + EV_SET(events + nevents, w->fd, EV_OOBAND, 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; + } + + have_signals = 0; + 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 == POLLIN); + assert(w->pevents == POLLIN); + w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + nevents++; + continue; + } + + revents = 0; + + if (ev->filter == EVFILT_READ) { + if (w->pevents & POLLIN) { + revents |= 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 == EV_OOBAND) { + if (w->pevents & UV__POLLPRI) { + revents |= UV__POLLPRI; + 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 & POLLOUT) { + revents |= 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 |= POLLERR; + + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + + if (revents == 0) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + + nevents++; + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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 UV_EINVAL; + + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return UV__ERR(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__) + if (uv__has_forked_with_cfrunloop) + goto fallback; + + /* 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, 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__has_forked_with_cfrunloop || 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/3rd/libuv-1.19.2/src/unix/linux-core.c b/3rd/libuv-1.19.2/src/unix/linux-core.c new file mode 100644 index 00000000..b63c25f3 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-core.c @@ -0,0 +1,951 @@ +/* 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. + */ + +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +# endif +# include +# include +# include +#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 but we can't + * include that file because it conflicts with . 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(FILE* statfile_fp, + 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 UV__ERR(errno); + + return 0; +} + + +int uv__io_fork(uv_loop_t* loop) { + int err; + void* old_watchers; + + old_watchers = loop->inotify_watchers; + + uv__close(loop->backend_fd); + loop->backend_fd = -1; + uv__platform_loop_delete(loop); + + err = uv__platform_loop_init(loop); + if (err) + return err; + + return uv__inotify_fork(loop, old_watchers); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->inotify_fd == -1) return; + uv__io_stop(loop, &loop->inotify_read_watcher, 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); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = POLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = UV__ERR(errno); + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +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 have_signals; + 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); + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + 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; + } + + have_signals = 0; + 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 | POLLERR | 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 == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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; +} + + +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 UV__ERR(errno); + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + uv__close(fd); + if (n == -1) + return UV__ERR(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 UV_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 UV__ERR(errno); + + *uptime = now.tv_sec; + return 0; +} + + +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + return UV_EIO; + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + if (num == 0) + return UV_EIO; + + *numcpus = num; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus; + uv_cpu_info_t* ci; + int err; + FILE* statfile_fp; + + *cpu_infos = NULL; + *count = 0; + + statfile_fp = uv__open_file("/proc/stat"); + if (statfile_fp == NULL) + return UV__ERR(errno); + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + goto out; + + err = UV_ENOMEM; + ci = uv__calloc(numcpus, sizeof(*ci)); + if (ci == NULL) + goto out; + + err = read_models(numcpus, ci); + if (err == 0) + err = read_times(statfile_fp, numcpus, ci); + + if (err) { + uv_free_cpu_info(ci, numcpus); + goto out; + } + + /* 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; + err = 0; + +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; +} + + +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 = uv__open_file("/proc/cpuinfo"); + if (fp == NULL) + return UV__ERR(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 UV_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 UV_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 UV_ENOMEM; + ci[model_idx++].model = model; + } + + return 0; +} + + +static int read_times(FILE* statfile_fp, + 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]; + + clock_ticks = sysconf(_SC_CLK_TCK); + assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != 0); + + rewind(statfile_fp); + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (num >= numcpus) + break; + + if (strncmp(buf, "cpu", 3)) + break; + + /* skip "cpu " 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; + } + 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 = uv__open_file(buf); + 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); +} + +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + /* + * 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) + return exclude_type; + return !exclude_type; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { +#ifndef HAVE_IFADDRS_H + return UV_ENOSYS; +#else + struct ifaddrs *addrs, *ent; + uv_interface_address_t* address; + int i; + struct sockaddr_ll *sll; + + if (getifaddrs(&addrs)) + return UV__ERR(errno); + + *count = 0; + *addresses = NULL; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + continue; + + (*count)++; + } + + if (*count == 0) + return 0; + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) + 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 (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) + 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/3rd/libuv-1.19.2/src/unix/linux-inotify.c b/3rd/libuv-1.19.2/src/unix/linux-inotify.c new file mode 100644 index 00000000..bcad630f --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-inotify.c @@ -0,0 +1,352 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include + +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 void maybe_free_watcher_list(struct watcher_list* w, + uv_loop_t* loop); + +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 UV__ERR(errno); + + fd = uv__inotify_init(); + if (fd == -1) + return UV__ERR(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, POLLIN); + + return 0; +} + + +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { + /* Open the inotify_fd, and re-arm all the inotify watchers. */ + int err; + struct watcher_list* tmp_watcher_list_iter; + struct watcher_list* watcher_list; + struct watcher_list tmp_watcher_list; + QUEUE queue; + QUEUE* q; + uv_fs_event_t* handle; + char* tmp_path; + + if (old_watchers != NULL) { + /* We must restore the old watcher list to be able to close items + * out of it. + */ + loop->inotify_watchers = old_watchers; + + QUEUE_INIT(&tmp_watcher_list.watchers); + /* Note that the queue we use is shared with the start and stop() + * functions, making QUEUE_FOREACH unsafe to use. So we use the + * QUEUE_MOVE trick to safely iterate. Also don't free the watcher + * list until we're done iterating. c.f. uv__inotify_read. + */ + RB_FOREACH_SAFE(watcher_list, watcher_root, + CAST(&old_watchers), tmp_watcher_list_iter) { + watcher_list->iterating = 1; + QUEUE_MOVE(&watcher_list->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + /* It's critical to keep a copy of path here, because it + * will be set to NULL by stop() and then deallocated by + * maybe_free_watcher_list + */ + tmp_path = uv__strdup(handle->path); + assert(tmp_path != NULL); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&watcher_list->watchers, q); + uv_fs_event_stop(handle); + + QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); + handle->path = tmp_path; + } + watcher_list->iterating = 0; + maybe_free_watcher_list(watcher_list, loop); + } + + QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + QUEUE_REMOVE(q); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + tmp_path = handle->path; + handle->path = NULL; + err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); + uv__free(tmp_path); + if (err) + return err; + } + } + + 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 UV_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 UV__ERR(errno); + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + w = uv__malloc(sizeof(*w) + strlen(path) + 1); + if (w == NULL) + return UV_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/3rd/libuv-1.19.2/src/unix/linux-syscalls.c b/3rd/libuv-1.19.2/src/unix/linux-syscalls.c new file mode 100644 index 00000000..89998ded --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include +#include +#include + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define MSAN_ACTIVE 1 +# include +# 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/3rd/libuv-1.19.2/src/unix/linux-syscalls.h b/3rd/libuv-1.19.2/src/unix/linux-syscalls.h new file mode 100644 index 00000000..4c095e9b --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/linux-syscalls.h @@ -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. + */ + +#ifndef UV_LINUX_SYSCALL_H_ +#define UV_LINUX_SYSCALL_H_ + +#undef _GNU_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#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 + +/* 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/3rd/libuv-1.19.2/src/unix/loop-watcher.c b/3rd/libuv-1.19.2/src/unix/loop-watcher.c new file mode 100644 index 00000000..b8c1c2a7 --- /dev/null +++ b/3rd/libuv-1.19.2/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 UV_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/3rd/libuv-1.19.2/src/unix/loop.c b/3rd/libuv-1.19.2/src/unix/loop.c new file mode 100644 index 00000000..5b5b0e09 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/loop.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 "tree.h" +#include "internal.h" +#include "heap-inl.h" +#include +#include +#include + +int uv_loop_init(uv_loop_t* loop) { + void* saved_data; + int err; + + + saved_data = loop->data; + memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + + 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); + loop->async_io_watcher.fd = -1; + loop->async_wfd = -1; + 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; + + uv__signal_global_once_init(); + 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; +} + + +int uv_loop_fork(uv_loop_t* loop) { + int err; + unsigned int i; + uv__io_t* w; + + err = uv__io_fork(loop); + if (err) + return err; + + err = uv__async_fork(loop); + if (err) + return err; + + err = uv__signal_loop_fork(loop); + if (err) + return err; + + /* Rearm all the watchers that aren't re-queued by the above. */ + for (i = 0; i < loop->nwatchers; i++) { + w = loop->watchers[i]; + if (w == NULL) + continue; + + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) { + w->events = 0; /* Force re-registration in uv__io_poll. */ + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + } + + return 0; +} + + +void uv__loop_close(uv_loop_t* loop) { + uv__signal_loop_cleanup(loop); + uv__platform_loop_delete(loop); + uv__async_stop(loop); + + 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/3rd/libuv-1.19.2/src/unix/netbsd.c b/3rd/libuv-1.19.2/src/unix/netbsd.c new file mode 100644 index 00000000..2605c114 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/netbsd.c @@ -0,0 +1,309 @@ +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +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) { + /* Intermediate buffer, retrieving partial path name does not work + * As of NetBSD-8(beta), vnode->path translator does not handle files + * with longer names than 31 characters. + */ + char int_buf[PATH_MAX]; + size_t int_size; + int mib[4]; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = -1; + mib[3] = KERN_PROC_PATHNAME; + int_size = ARRAY_SIZE(int_buf); + + if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) + return UV__ERR(errno); + + /* Copy string from the intermediate buffer to outer one with appropriate + * length. + */ + strlcpy(buffer, int_buf, *size); + + /* Set new size. */ + *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 UV__ERR(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 UV__ERR(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) { + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\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 UV_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 UV__ERR(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 UV__ERR(errno); + } + + size = sizeof(numcpus); + if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) + return UV__ERR(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 UV_ENOMEM; + + if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) { + uv__free(cp_times); + uv__free(*cpu_infos); + return UV_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); +} diff --git a/3rd/libuv-1.19.2/src/unix/no-fsevents.c b/3rd/libuv-1.19.2/src/unix/no-fsevents.c new file mode 100644 index 00000000..158643af --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/no-fsevents.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return UV_ENOSYS; +} + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return UV_ENOSYS; +} + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return UV_ENOSYS; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} diff --git a/3rd/libuv-1.19.2/src/unix/no-proctitle.c b/3rd/libuv-1.19.2/src/unix/no-proctitle.c new file mode 100644 index 00000000..165740ca --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/no-proctitle.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +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 (buffer == NULL || size == 0) + return UV_EINVAL; + + buffer[0] = '\0'; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/openbsd.c b/3rd/libuv-1.19.2/src/unix/openbsd.c new file mode 100644 index 00000000..ce937cd3 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/openbsd.c @@ -0,0 +1,313 @@ +/* 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char *process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + return uv__kqueue_init(loop); +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { +} + + +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 UV_EINVAL; + + mypid = getpid(); + for (;;) { + err = UV_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 = UV__ERR(errno); + goto out; + } + argsbuf_size *= 2U; + } + + if (argsbuf[0] == NULL) { + err = UV_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 UV__ERR(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 UV__ERR(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) { + char* new_title; + + new_title = uv__strdup(title); + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOMEM; + } + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\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 UV__ERR(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 UV__ERR(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 UV__ERR(errno); + + which[1] = HW_NCPU; + size = sizeof(numcpus); + if (sysctl(which, 2, &numcpus, &size, NULL, 0)) + return UV__ERR(errno); + + *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); + if (!(*cpu_infos)) + return UV_ENOMEM; + + *count = numcpus; + + which[1] = HW_CPUSPEED; + size = sizeof(cpuspeed); + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { + uv__free(*cpu_infos); + return UV__ERR(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)) { + uv__free(*cpu_infos); + return UV__ERR(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); +} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.c b/3rd/libuv-1.19.2/src/unix/os390-syscalls.c new file mode 100644 index 00000000..21558ea8 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390-syscalls.c @@ -0,0 +1,499 @@ +/* Copyright 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. + */ + + +#include "os390-syscalls.h" +#include +#include +#include +#include +#include +#include + +#define CW_CONDVAR 32 + +#pragma linkage(BPX4CTW, OS) +#pragma linkage(BPX1CTW, OS) + +static int number_of_epolls; +static QUEUE global_epoll_queue; +static uv_mutex_t global_epoll_lock; +static uv_once_t once = UV_ONCE_INIT; + +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent*), + int (*compar)(const struct dirent**, + const struct dirent **)) { + struct dirent** nl; + struct dirent* dirent; + unsigned count; + size_t allocated; + DIR* mdir; + + nl = NULL; + count = 0; + allocated = 0; + mdir = opendir(maindir); + if (!mdir) + return -1; + + while (1) { + dirent = readdir(mdir); + if (!dirent) + break; + if (!filter || filter(dirent)) { + struct dirent* copy; + copy = uv__malloc(sizeof(*copy)); + if (!copy) { + while (count) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; + } + memcpy(copy, dirent, sizeof(*copy)); + + nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); + nl[count++] = copy; + } + } + + qsort(nl, count, sizeof(struct dirent *), + (int (*)(const void *, const void *)) compar); + + closedir(mdir); + + *namelist = nl; + return count; +} + + +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__os390_epoll* lst, unsigned int len) { + unsigned int newsize; + unsigned int i; + struct pollfd* newlst; + struct pollfd event; + + if (len <= lst->size) + return; + + if (lst->size == 0) + event.fd = -1; + else { + /* Extract the message queue at the end. */ + event = lst->items[lst->size - 1]; + lst->items[lst->size - 1].fd = -1; + } + + newsize = next_power_of_two(len); + newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); + + if (newlst == NULL) + abort(); + for (i = lst->size; i < newsize; ++i) + newlst[i].fd = -1; + + /* Restore the message queue at the end */ + newlst[newsize - 1] = event; + + lst->items = newlst; + lst->size = newsize; +} + + +static void init_message_queue(uv__os390_epoll* lst) { + struct { + long int header; + char body; + } msg; + + /* initialize message queue */ + lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); + if (lst->msg_queue == -1) + abort(); + + /* + On z/OS, the message queue will be affiliated with the process only + when a send is performed on it. Once this is done, the system + can be queried for all message queues belonging to our process id. + */ + msg.header = 1; + if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) + abort(); + + /* Clean up the dummy message sent above */ + if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) + abort(); +} + + +static void before_fork(void) { + uv_mutex_lock(&global_epoll_lock); +} + + +static void after_fork(void) { + uv_mutex_unlock(&global_epoll_lock); +} + + +static void child_fork(void) { + QUEUE* q; + uv_once_t child_once = UV_ONCE_INIT; + + /* reset once */ + memcpy(&once, &child_once, sizeof(child_once)); + + /* reset epoll list */ + while (!QUEUE_EMPTY(&global_epoll_queue)) { + uv__os390_epoll* lst; + q = QUEUE_HEAD(&global_epoll_queue); + QUEUE_REMOVE(q); + lst = QUEUE_DATA(q, uv__os390_epoll, member); + uv__free(lst->items); + lst->items = NULL; + lst->size = 0; + } + + uv_mutex_unlock(&global_epoll_lock); + uv_mutex_destroy(&global_epoll_lock); +} + + +static void epoll_init(void) { + QUEUE_INIT(&global_epoll_queue); + if (uv_mutex_init(&global_epoll_lock)) + abort(); + + if (pthread_atfork(&before_fork, &after_fork, &child_fork)) + abort(); +} + + +uv__os390_epoll* epoll_create1(int flags) { + uv__os390_epoll* lst; + + lst = uv__malloc(sizeof(*lst)); + if (lst != NULL) { + /* initialize list */ + lst->size = 0; + lst->items = NULL; + init_message_queue(lst); + maybe_resize(lst, 1); + lst->items[lst->size - 1].fd = lst->msg_queue; + lst->items[lst->size - 1].events = POLLIN; + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + } + + return lst; +} + + +int epoll_ctl(uv__os390_epoll* lst, + int op, + int fd, + struct epoll_event *event) { + uv_mutex_lock(&global_epoll_lock); + + if (op == EPOLL_CTL_DEL) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = ENOENT; + return -1; + } + lst->items[fd].fd = -1; + } else if (op == EPOLL_CTL_ADD) { + + /* Resizing to 'fd + 1' would expand the list to contain at least + * 'fd'. But we need to guarantee that the last index on the list + * is reserved for the message queue. So specify 'fd + 2' instead. + */ + maybe_resize(lst, fd + 2); + if (lst->items[fd].fd != -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = EEXIST; + return -1; + } + lst->items[fd].fd = fd; + lst->items[fd].events = event->events; + } else if (op == EPOLL_CTL_MOD) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); + errno = ENOENT; + return -1; + } + lst->items[fd].events = event->events; + } else + abort(); + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + + +int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, + int maxevents, int timeout) { + nmsgsfds_t size; + struct pollfd* pfds; + int pollret; + int reventcount; + + size = _SET_FDS_MSGS(size, 1, lst->size - 1); + pfds = lst->items; + pollret = poll(pfds, size, timeout); + if (pollret <= 0) + return pollret; + + pollret = _NFDS(pollret) + _NMSGS(pollret); + + reventcount = 0; + for (int i = 0; + i < lst->size && i < maxevents && reventcount < pollret; ++i) { + struct epoll_event ev; + + if (pfds[i].fd == -1 || pfds[i].revents == 0) + continue; + + ev.fd = pfds[i].fd; + ev.events = pfds[i].revents; + events[reventcount++] = ev; + } + + return reventcount; +} + + +int epoll_file_close(int fd) { + QUEUE* q; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_FOREACH(q, &global_epoll_queue) { + uv__os390_epoll* lst; + + lst = QUEUE_DATA(q, uv__os390_epoll, member); + if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) + lst->items[fd].fd = -1; + } + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + +void epoll_queue_close(uv__os390_epoll* lst) { + /* Remove epoll instance from global queue */ + uv_mutex_lock(&global_epoll_lock); + QUEUE_REMOVE(&lst->member); + uv_mutex_unlock(&global_epoll_lock); + + /* Free resources */ + msgctl(lst->msg_queue, IPC_RMID, NULL); + lst->msg_queue = -1; + uv__free(lst->items); + lst->items = NULL; +} + + +int nanosleep(const struct timespec* req, struct timespec* rem) { + unsigned nano; + unsigned seconds; + unsigned events; + unsigned secrem; + unsigned nanorem; + int rv; + int rc; + int rsn; + + nano = (int)req->tv_nsec; + seconds = req->tv_sec; + events = CW_CONDVAR; + +#if defined(_LP64) + BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#else + BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#endif + + assert(rv == -1 && errno == EAGAIN); + + if(rem != NULL) { + rem->tv_nsec = nanorem; + rem->tv_sec = secrem; + } + + return 0; +} + + +char* mkdtemp(char* path) { + static const char* tempchars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + char *ep, *cp; + unsigned int tries, i; + size_t len; + uint64_t v; + int fd; + int retval; + int saved_errno; + + len = strlen(path); + ep = path + len; + if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { + errno = EINVAL; + return NULL; + } + + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + return NULL; + + tries = TMP_MAX; + retval = -1; + do { + if (read(fd, &v, sizeof(v)) != sizeof(v)) + break; + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (mkdir(path, S_IRWXU) == 0) { + retval = 0; + break; + } + else if (errno != EEXIST) + break; + } while (--tries); + + saved_errno = errno; + uv__close(fd); + if (tries == 0) { + errno = EEXIST; + return NULL; + } + + if (retval == -1) { + errno = saved_errno; + return NULL; + } + + return path; +} + + +ssize_t os390_readlink(const char* path, char* buf, size_t len) { + ssize_t rlen; + ssize_t vlen; + ssize_t plen; + char* delimiter; + char old_delim; + char* tmpbuf; + char realpathstr[PATH_MAX + 1]; + + tmpbuf = uv__malloc(len + 1); + if (tmpbuf == NULL) { + errno = ENOMEM; + return -1; + } + + rlen = readlink(path, tmpbuf, len); + if (rlen < 0) { + uv__free(tmpbuf); + return rlen; + } + + if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { + /* Straightforward readlink. */ + memcpy(buf, tmpbuf, rlen); + uv__free(tmpbuf); + return rlen; + } + + /* + * There is a parmlib variable at the beginning + * which needs interpretation. + */ + tmpbuf[rlen] = '\0'; + delimiter = strchr(tmpbuf + 2, '/'); + if (delimiter == NULL) + /* No slash at the end */ + delimiter = strchr(tmpbuf + 2, '\0'); + + /* Read real path of the variable. */ + old_delim = *delimiter; + *delimiter = '\0'; + if (realpath(tmpbuf, realpathstr) == NULL) { + uv__free(tmpbuf); + return -1; + } + + /* realpathstr is not guaranteed to end with null byte.*/ + realpathstr[PATH_MAX] = '\0'; + + /* Reset the delimiter and fill up the buffer. */ + *delimiter = old_delim; + plen = strlen(delimiter); + vlen = strlen(realpathstr); + rlen = plen + vlen; + if (rlen > len) { + uv__free(tmpbuf); + errno = ENAMETOOLONG; + return -1; + } + memcpy(buf, realpathstr, vlen); + memcpy(buf + vlen, delimiter, plen); + + /* Done using temporary buffer. */ + uv__free(tmpbuf); + + return rlen; +} + + +size_t strnlen(const char* str, size_t maxlen) { + void* p = memchr(str, 0, maxlen); + if (p == NULL) + return maxlen; + else + return p - str; +} diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.h b/3rd/libuv-1.19.2/src/unix/os390-syscalls.h new file mode 100644 index 00000000..6e34a88c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390-syscalls.h @@ -0,0 +1,72 @@ +/* Copyright 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. + */ + + +#ifndef UV_OS390_SYSCALL_H_ +#define UV_OS390_SYSCALL_H_ + +#include "uv.h" +#include "internal.h" +#include +#include +#include + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 +#define MAX_EPOLL_INSTANCES 256 +#define MAX_ITEMS_PER_EPOLL 1024 + +#define UV__O_CLOEXEC 0x80000 +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD +#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL +#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD + +struct epoll_event { + int events; + int fd; +}; + +typedef struct { + QUEUE member; + struct pollfd* items; + unsigned long size; + int msg_queue; +} uv__os390_epoll; + +/* epoll api */ +uv__os390_epoll* epoll_create1(int flags); +int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event); +int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout); +int epoll_file_close(int fd); + +/* utility functions */ +int nanosleep(const struct timespec* req, struct timespec* rem); +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); +char *mkdtemp(char* path); +ssize_t os390_readlink(const char* path, char* buf, size_t len); +size_t strnlen(const char* str, size_t maxlen); + +#endif /* UV_OS390_SYSCALL_H_ */ diff --git a/3rd/libuv-1.19.2/src/unix/os390.c b/3rd/libuv-1.19.2/src/unix/os390.c new file mode 100644 index 00000000..f766b393 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/os390.c @@ -0,0 +1,998 @@ +/* Copyright 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. + */ + +#include "internal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__clang__) +#include "csrsic.h" +#else +#include "//'SYS1.SAMPLIB(CSRSIC)'" +#endif + +#define CVT_PTR 0x10 +#define PSA_PTR 0x00 +#define CSD_OFFSET 0x294 + +/* + Long-term average CPU service used by this logical partition, + in millions of service units per hour. If this value is above + the partition's defined capacity, the partition will be capped. + It is calculated using the physical CPU adjustment factor + (RCTPCPUA) so it may not match other measures of service which + are based on the logical CPU adjustment factor. It is available + if the hardware supports LPAR cluster. +*/ +#define RCTLACS_OFFSET 0xC4 + +/* 32-bit count of alive CPUs. This includes both CPs and IFAs */ +#define CSD_NUMBER_ONLINE_CPUS 0xD4 + +/* Address of system resources manager (SRM) control table */ +#define CVTOPCTP_OFFSET 0x25C + +/* Address of the RCT table */ +#define RMCTRCT_OFFSET 0xE4 + +/* Address of the rsm control and enumeration area. */ +#define CVTRCEP_OFFSET 0x490 + +/* + Number of frames currently available to system. + Excluded are frames backing perm storage, frames offline, and bad frames. +*/ +#define RCEPOOL_OFFSET 0x004 + +/* Total number of frames currently on all available frame queues. */ +#define RCEAFC_OFFSET 0x088 + +/* CPC model length from the CSRSI Service. */ +#define CPCMODEL_LENGTH 16 + +/* Pointer to the home (current) ASCB. */ +#define PSAAOLD 0x224 + +/* Pointer to rsm address space block extension. */ +#define ASCBRSME 0x16C + +/* + NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. + It does not include 2G frames. +*/ +#define RAXFMCT 0x2C + +/* Thread Entry constants */ +#define PGTH_CURRENT 1 +#define PGTH_LEN 26 +#define PGTHAPATH 0x20 +#pragma linkage(BPX4GTH, OS) +#pragma linkage(BPX1GTH, OS) + +/* TOD Clock resolution in nanoseconds */ +#define TOD_RES 4.096 + +typedef unsigned data_area_ptr_assign_type; + +typedef union { + struct { +#if defined(_LP64) + data_area_ptr_assign_type lower; +#endif + data_area_ptr_assign_type assign; + }; + char* deref; +} data_area_ptr; + + +void uv_loadavg(double avg[3]) { + /* TODO: implement the following */ + avg[0] = 0; + avg[1] = 0; + avg[2] = 0; +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + uv__os390_epoll* ep; + + ep = epoll_create1(0); + loop->ep = ep; + if (ep == NULL) + return UV__ERR(errno); + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->ep != NULL) { + epoll_queue_close(loop->ep); + loop->ep = NULL; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + unsigned long long timestamp; + __stckf(×tamp); + /* Convert to nanoseconds */ + return timestamp / TOD_RES; +} + + +/* + Get the exe path using the thread entry information + in the address space. +*/ +static int getexe(const int pid, char* buf, size_t len) { + struct { + int pid; + int thid[2]; + char accesspid; + char accessthid; + char asid[2]; + char loginname[8]; + char flag; + char len; + } Input_data; + + union { + struct { + char gthb[4]; + int pid; + int thid[2]; + char accesspid; + char accessthid[3]; + int lenused; + int offsetProcess; + int offsetConTTY; + int offsetPath; + int offsetCommand; + int offsetFileData; + int offsetThread; + } Output_data; + char buf[2048]; + } Output_buf; + + struct Output_path_type { + char gthe[4]; + short int len; + char path[1024]; + }; + + int Input_length; + int Output_length; + void* Input_address; + void* Output_address; + struct Output_path_type* Output_path; + int rv; + int rc; + int rsn; + + Input_length = PGTH_LEN; + Output_length = sizeof(Output_buf); + Output_address = &Output_buf; + Input_address = &Input_data; + memset(&Input_data, 0, sizeof Input_data); + Input_data.flag |= PGTHAPATH; + Input_data.pid = pid; + Input_data.accesspid = PGTH_CURRENT; + +#ifdef _LP64 + BPX4GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#else + BPX1GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#endif + + if (rv == -1) { + errno = rc; + return -1; + } + + /* Check highest byte to ensure data availability */ + assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); + + /* Get the offset from the lowest 3 bytes */ + Output_path = (char*)(&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + + if (Output_path->len >= len) { + errno = ENOBUFS; + return -1; + } + + strncpy(buf, Output_path->path, len); + + return 0; +} + + +/* + * 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 zOS - 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; + int pid; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + pid = getpid(); + res = getexe(pid, args, sizeof(args)); + if (res < 0) + return UV_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 UV__ERR(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 UV_EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return UV_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 UV_EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + uint64_t freeram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; + return freeram; +} + + +uint64_t uv_get_total_memory(void) { + uint64_t totalram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4; + return totalram; +} + + +int uv_resident_set_memory(size_t* rss) { + char* psa; + char* ascb; + char* rax; + size_t nframes; + + psa = PSA_PTR; + ascb = *(char* __ptr32 *)(psa + PSAAOLD); + rax = *(char* __ptr32 *)(ascb + ASCBRSME); + nframes = *(unsigned int*)(rax + RAXFMCT); + + *rss = nframes * sysconf(_SC_PAGESIZE); + return 0; +} + + +int uv_uptime(double* uptime) { + struct utmpx u ; + struct utmpx *v; + time64_t t; + + u.ut_type = BOOT_TIME; + v = getutxid(&u); + if (v == NULL) + return -1; + *uptime = difftime64(time64(&t), v->ut_tv.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + int idx; + siv1v2 info; + data_area_ptr cvt = {0}; + data_area_ptr csd = {0}; + data_area_ptr rmctrct = {0}; + data_area_ptr cvtopctp = {0}; + int cpu_usage_avg; + + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + + csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET)); + cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET)); + rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET)); + + *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS)); + cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET)); + + *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) + return UV_ENOMEM; + + cpu_info = *cpu_infos; + idx = 0; + while (idx < *count) { + cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability); + cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1); + memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1); + memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH); + cpu_info->cpu_times.user = cpu_usage_avg; + /* TODO: implement the following */ + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + ++cpu_info; + ++idx; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + for (int i = 0; i < count; ++i) + uv__free(cpu_infos[i].model); + uv__free(cpu_infos); +} + + +static int uv__interface_addresses_v6(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + __net_ifconf6header_t ifc; + __net_ifconf6entry_t* ifr; + __net_ifconf6entry_t* p; + __net_ifconf6entry_t flg; + + *count = 0; + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) + return UV__ERR(errno); + + ifc.__nif6h_version = 1; + ifc.__nif6h_buflen = maxsize; + ifc.__nif6h_buffer = uv__calloc(1, maxsize);; + + if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + + *count = 0; + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + ++(*count); + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return UV_ENOMEM; + } + address = *addresses; + + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + p = ifr; + ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); + + if (!(p->__nif6e_addr.sin6_family == AF_INET6 || + p->__nif6e_addr.sin6_family == AF_INET)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->__nif6e_name); + + if (p->__nif6e_addr.sin6_family == AF_INET6) + address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr); + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; + + address++; + } + + uv__close(sockfd); + return 0; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + struct ifconf ifc; + struct ifreq flg; + struct ifreq* ifr; + struct ifreq* p; + int count_v6; + + /* get the ipv6 addresses first */ + uv_interface_address_t* addresses_v6; + uv__interface_addresses_v6(&addresses_v6, &count_v6); + + /* now get the ipv4 addresses */ + *count = 0; + + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (0 > sockfd) + return UV__ERR(errno); + + ifc.ifc_req = uv__calloc(1, maxsize); + ifc.ifc_len = maxsize; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#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) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc((*count + count_v6) * + sizeof(uv_interface_address_t)); + + if (!(*addresses)) { + uv__close(sockfd); + return UV_ENOMEM; + } + address = *addresses; + + /* copy over the ipv6 addresses */ + memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); + address += count_v6; + *count += count_v6; + uv__free(addresses_v6); + + 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 UV_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); + } + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + address++; + } + +#undef ADDR_SIZE +#undef MAX + + 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 epoll_event* events; + struct epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct 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].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the epoll. */ + if (loop->ep != NULL) + epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + + +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* filename, unsigned int flags) { + uv__os390_epoll* ep; + _RFIS reg_struct; + char* path; + int rc; + + if (uv__is_active(handle)) + return UV_EINVAL; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_REG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); + + path = uv__strdup(filename); + if (path == NULL) + return UV_ENOMEM; + + rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0) + return UV__ERR(errno); + + uv__handle_start(handle); + handle->path = path; + handle->cb = cb; + memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, + sizeof(handle->rfis_rftok)); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + uv__os390_epoll* ep; + _RFIS reg_struct; + int rc; + + if (!uv__is_active(handle)) + return 0; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_UNREG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, + sizeof(handle->rfis_rftok)); + + /* + * This call will take "/" as the path argument in case we + * don't care to supply the correct path. The system will simply + * ignore it. + */ + rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0 && errno != EALREADY && errno != ENOENT) + abort(); + + uv__handle_stop(handle); + + return 0; +} + + +static int os390_message_queue_handler(uv__os390_epoll* ep) { + uv_fs_event_t* handle; + int msglen; + int events; + _RFIM msg; + + if (ep->msg_queue == -1) + return 0; + + msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT); + + if (msglen == -1 && errno == ENOMSG) + return 0; + + if (msglen == -1) + abort(); + + events = 0; + if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) + events = UV_CHANGE; + else if (msg.__rfim_event == _RFIM_RENAME) + events = UV_RENAME; + else + /* Some event that we are not interested in. */ + return 0; + + handle = *(uv_fs_event_t**)(msg.__rfim_utok); + handle->cb(handle, uv__basename_r(handle->path), events, 0); + return 1; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + static const int max_safe_timeout = 1789569; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + uv__os390_epoll* ep; + int real_timeout; + QUEUE* q; + uv__io_t* w; + uint64_t base; + 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)) { + uv_stream_t* stream; + + 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); + + stream= container_of(w, uv_stream_t, io_watcher); + + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.fd = 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 (epoll_ctl(loop->ep, 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 (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + int nevents = 0; + + nfds = 0; + for (;;) { + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + nfds = epoll_wait(loop->ep, 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. + */ + base = loop->time; + SAVE_ERRNO(uv__update_time(loop)); + if (nfds == 0) { + assert(timeout != -1); + + if (timeout > 0) { + timeout = real_timeout - timeout; + continue; + } + + 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; + } + + + 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->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + ep = loop->ep; + if (fd == ep->msg_queue) { + os390_message_queue_handler(ep); + 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. + */ + epoll_ctl(loop->ep, 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 | POLLERR | POLLHUP; + + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + 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; + } +} + +void uv__set_process_title(const char* title) { + /* do nothing */ +} + +int uv__io_fork(uv_loop_t* loop) { + /* + Nullify the msg queue but don't close it because + it is still being used by the parent. + */ + loop->ep = NULL; + + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} diff --git a/3rd/libuv-1.19.2/src/unix/pipe.c b/3rd/libuv-1.19.2/src/unix/pipe.c new file mode 100644 index 00000000..e640bf29 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/pipe.c @@ -0,0 +1,357 @@ +/* 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 +#include +#include +#include +#include +#include + + +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; + + /* Already bound? */ + if (uv__stream_fd(handle) >= 0) + return UV_EINVAL; + + /* Make a copy of the file name, it outlives this function's scope. */ + pipe_fname = uv__strdup(name); + if (pipe_fname == NULL) + return UV_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 = UV__ERR(errno); + /* Convert ENOENT to EACCES for compatibility with Windows. */ + if (err == UV_ENOENT) + err = UV_EACCES; + + uv__close(sockfd); + goto err_socket; + } + + /* Success. */ + handle->flags |= UV_HANDLE_BOUND; + handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->io_watcher.fd = sockfd; + return 0; + +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 UV_EINVAL; + +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + + if (listen(uv__stream_fd(handle), backlog)) + return UV__ERR(errno); + + handle->connection_cb = cb; + handle->io_watcher.cb = uv__server_io; + uv__io_start(handle->loop, &handle->io_watcher, 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 = UV__ERR(errno); +#if defined(__CYGWIN__) || defined(__MSYS__) + /* EBADF is supposed to mean that the socket fd is bad, but + Cygwin reports EBADF instead of ENOTSOCK when the file is + not a socket. We do not expect to see a bad fd here + (e.g. due to new_sock), so translate the error. */ + if (err == UV_EBADF) + err = UV_ENOTSOCK; +#endif + 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, POLLIN | 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); + +} + + +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 UV__ERR(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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, sa.sun_path, addrlen); + *size = addrlen; + + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + + 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); +} + + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + unsigned desired_mode; + struct stat pipe_stat; + char* name_buffer; + size_t name_len; + int r; + + if (handle == NULL || uv__stream_fd(handle) == -1) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) + return UV__ERR(errno); + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) + return 0; + + pipe_stat.st_mode |= desired_mode; + + /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ + name_len = 0; + r = uv_pipe_getsockname(handle, NULL, &name_len); + if (r != UV_ENOBUFS) + return r; + + name_buffer = uv__malloc(name_len); + if (name_buffer == NULL) + return UV_ENOMEM; + + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) { + uv__free(name_buffer); + return r; + } + + r = chmod(name_buffer, pipe_stat.st_mode); + uv__free(name_buffer); + + return r != -1 ? 0 : UV__ERR(errno); +} diff --git a/3rd/libuv-1.19.2/src/unix/poll.c b/3rd/libuv-1.19.2/src/unix/poll.c new file mode 100644 index 00000000..f3b0bf4e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/poll.c @@ -0,0 +1,147 @@ +/* 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 +#include +#include + + +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); + + /* + * As documented in the kernel source fs/kernfs/file.c #780 + * poll will return POLLERR|POLLPRI in case of sysfs + * polling. This does not happen in case of out-of-band + * TCP messages. + * + * The above is the case on (at least) FreeBSD and Linux. + * + * So to properly determine a POLLPRI or a POLLERR we need + * to check for both. + */ + if ((events & POLLERR) && !(events & UV__POLLPRI)) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + uv__handle_stop(handle); + handle->poll_cb(handle, UV_EBADF, 0); + return; + } + + pevents = 0; + if (events & POLLIN) + pevents |= UV_READABLE; + if (events & UV__POLLPRI) + pevents |= UV_PRIORITIZED; + if (events & POLLOUT) + pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; + + handle->poll_cb(handle, 0, pevents); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + int err; + + err = uv__io_check_fd(loop, fd); + if (err) + return err; + + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ + err = uv__nonblock(fd, 1); + if (err == UV_ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(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, + POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + uv__handle_stop(handle); + uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!uv__is_closing(handle)); + 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 | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); + assert(!uv__is_closing(handle)); + + uv__poll_stop(handle); + + if (pevents == 0) + return 0; + + events = 0; + if (pevents & UV_READABLE) + events |= POLLIN; + if (pevents & UV_PRIORITIZED) + events |= UV__POLLPRI; + if (pevents & UV_WRITABLE) + events |= POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; + + 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/3rd/libuv-1.19.2/src/unix/posix-hrtime.c b/3rd/libuv-1.19.2/src/unix/posix-hrtime.c new file mode 100644 index 00000000..323dfc20 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/posix-hrtime.c @@ -0,0 +1,35 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + +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); +} diff --git a/3rd/libuv-1.19.2/src/unix/posix-poll.c b/3rd/libuv-1.19.2/src/unix/posix-poll.c new file mode 100644 index 00000000..f356e76c --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/posix-poll.c @@ -0,0 +1,324 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +/* POSIX defines poll() as a portable way to wait on file descriptors. + * Here we maintain a dynamically sized array of file descriptors and + * events to pass as the first argument to poll(). + */ + +#include +#include +#include +#include +#include + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->poll_fds = NULL; + loop->poll_fds_used = 0; + loop->poll_fds_size = 0; + loop->poll_fds_iterating = 0; + return 0; +} + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__free(loop->poll_fds); + loop->poll_fds = NULL; +} + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + +/* Allocate or dynamically resize our poll fds array. */ +static void uv__pollfds_maybe_resize(uv_loop_t* loop) { + size_t i; + size_t n; + struct pollfd* p; + + if (loop->poll_fds_used < loop->poll_fds_size) + return; + + n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; + p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); + if (p == NULL) + abort(); + + loop->poll_fds = p; + for (i = loop->poll_fds_size; i < n; i++) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + loop->poll_fds_size = n; +} + +/* Primitive swap operation on poll fds array elements. */ +static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) { + struct pollfd pfd; + pfd = loop->poll_fds[l]; + loop->poll_fds[l] = loop->poll_fds[r]; + loop->poll_fds[r] = pfd; +} + +/* Add a watcher's fd to our poll fds array with its pending events. */ +static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { + size_t i; + struct pollfd* pe; + + /* If the fd is already in the set just update its events. */ + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == w->fd) { + loop->poll_fds[i].events = w->pevents; + return; + } + } + + /* Otherwise, allocate a new slot in the set for the fd. */ + uv__pollfds_maybe_resize(loop); + pe = &loop->poll_fds[loop->poll_fds_used++]; + pe->fd = w->fd; + pe->events = w->pevents; +} + +/* Remove a watcher's fd from our poll fds array. */ +static void uv__pollfds_del(uv_loop_t* loop, int fd) { + size_t i; + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == fd) { + /* swap to last position and remove */ + --loop->poll_fds_used; + uv__pollfds_swap(loop, i, loop->poll_fds_used); + loop->poll_fds[loop->poll_fds_used].fd = -1; + loop->poll_fds[loop->poll_fds_used].events = 0; + loop->poll_fds[loop->poll_fds_used].revents = 0; + return; + } + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + sigset_t* pset; + sigset_t set; + uint64_t time_base; + uint64_t time_diff; + QUEUE* q; + uv__io_t* w; + size_t i; + unsigned int nevents; + int nfds; + int have_signals; + struct pollfd* pe; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + /* Take queued watchers and add their fds to our poll fds array. */ + 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); + + uv__pollfds_add(loop, w); + + w->events = w->pevents; + } + + /* Prepare a set of signals to block around poll(), if any. */ + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + time_base = loop->time; + + /* Loop calls to poll() and processing of results. If we get some + * results from poll() but they turn out not to be interesting to + * our caller then we need to loop around and poll() again. + */ + for (;;) { + if (pset != NULL) + if (pthread_sigmask(SIG_BLOCK, pset, NULL)) + abort(); + nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); + if (pset != NULL) + if (pthread_sigmask(SIG_UNBLOCK, pset, 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); + 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; + } + + /* Tell uv__platform_invalidate_fd not to manipulate our array + * while we are iterating over it. + */ + loop->poll_fds_iterating = 1; + + /* Initialize a count of events that we care about. */ + nevents = 0; + have_signals = 0; + + /* Loop over the entire poll fds array looking for returned events. */ + for (i = 0; i < loop->poll_fds_used; i++) { + pe = loop->poll_fds + i; + fd = pe->fd; + + /* 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, ignore. */ + uv__platform_invalidate_fd(loop, fd); + continue; + } + + /* Filter out events that user has not requested us to watch + * (e.g. POLLNVAL). + */ + pe->revents &= w->pevents | POLLERR | POLLHUP; + + if (pe->revents != 0) { + /* Run signal watchers last. */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + w->cb(loop, w, pe->revents); + } + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->poll_fds_iterating = 0; + + /* Purge invalidated fds from our poll fds array. */ + uv__pollfds_del(loop, -1); + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) + return; + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + time_diff = loop->time - time_base; + if (time_diff >= (uint64_t) timeout) + return; + + timeout -= time_diff; + } +} + +/* Remove the given fd from our poll fds array because no one + * is interested in its events anymore. + */ +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + size_t i; + + if (loop->poll_fds_iterating) { + /* uv__io_poll is currently iterating. Just invalidate fd. */ + for (i = 0; i < loop->poll_fds_used; i++) + if (loop->poll_fds[i].fd == fd) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + } else { + /* uv__io_poll is not iterating. Delete fd from the set. */ + uv__pollfds_del(loop, fd); + } +} + +/* Check whether the given fd is supported by poll(). */ +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + if (rv == -1) + return UV__ERR(errno); + + if (p[0].revents & POLLNVAL) + return UV_EINVAL; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/process.c b/3rd/libuv-1.19.2/src/unix/process.c new file mode 100644 index 00000000..74113e3a --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/process.c @@ -0,0 +1,599 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# define environ (*_NSGetEnviron()) +#else +extern char **environ; +#endif + +#if defined(__linux__) || defined(__GLIBC__) +# include +#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 UV__ERR(errno); + + no_cloexec = 1; + +skip: +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return UV__ERR(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 UV__ERR(errno); + + no_pipe2 = 1; + +skip: +#endif + + if (pipe(fds)) + return UV__ERR(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 UV_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 UV_EINVAL; + + fds[1] = fd; + return 0; + + default: + assert(0 && "Unexpected flags"); + return UV_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) + 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) { + sigset_t set; + int close_fd; + int use_fd; + int err; + int fd; + int n; + + 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, UV__ERR(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, UV__ERR(errno)); + _exit(127); + } + } + } + + if (fd == use_fd) + uv__cloexec_fcntl(use_fd, 0); + else + fd = dup2(use_fd, fd); + + if (fd == -1) { + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + if (fd <= 2) + uv__nonblock_fcntl(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, UV__ERR(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, UV__ERR(errno)); + _exit(127); + } + + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + if (options->env != NULL) { + environ = options->env; + } + + /* Reset signal disposition. Use a hard-coded limit because NSIG + * is not fixed on Linux: it's either 32, 34 or 64, depending on + * whether RT signals are enabled. We are not allowed to touch + * RT signal handlers, glibc uses them internally. + */ + for (n = 1; n < 32; n += 1) { + if (n == SIGKILL || n == SIGSTOP) + continue; /* Can't be changed. */ + + if (SIG_ERR != signal(n, SIG_DFL)) + continue; + + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + /* Reset signal mask. */ + sigemptyset(&set); + err = pthread_sigmask(SIG_SETMASK, &set, NULL); + + if (err != 0) { + uv__write_int(error_fd, UV__ERR(err)); + _exit(127); + } + + execvp(options->file, options->args); + uv__write_int(error_fd, UV__ERR(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 UV_ENOSYS; +#else + int signal_pipe[2] = { -1, -1 }; + int pipes_storage[8][2]; + 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 = UV_ENOMEM; + pipes = pipes_storage; + if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) + 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 = UV__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_nocheckstdio(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; + + if (pipes != pipes_storage) + 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) + uv__close_nocheckstdio(pipes[i][0]); + if (pipes[i][1] != -1) + uv__close_nocheckstdio(pipes[i][1]); + } + + if (pipes != pipes_storage) + 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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/procfs-exepath.c b/3rd/libuv-1.19.2/src/unix/procfs-exepath.c new file mode 100644 index 00000000..00dc021f --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/procfs-exepath.c @@ -0,0 +1,45 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return UV__ERR(errno); + + buffer[n] = '\0'; + *size = n; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/proctitle.c b/3rd/libuv-1.19.2/src/unix/proctitle.c new file mode 100644 index 00000000..1a8c7a70 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/proctitle.c @@ -0,0 +1,132 @@ +/* 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 +#include + +extern void uv__set_process_title(const char* title); + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static void* args_mem; + +static struct { + char* str; + size_t len; +} process_title; + + +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + +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; + +#if defined(__MVS__) + /* argv is not adjacent. So just use argv[0] */ + process_title.str = argv[0]; + process_title.len = strlen(argv[0]); +#else + 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. */ +#endif + + /* 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) { + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title.len != 0) { + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + } + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (size <= process_title.len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + if (process_title.len != 0) + memcpy(buffer, process_title.str, process_title.len + 1); + + buffer[process_title.len] = '\0'; + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} diff --git a/3rd/libuv-1.19.2/src/unix/pthread-fixes.c b/3rd/libuv-1.19.2/src/unix/pthread-fixes.c new file mode 100644 index 00000000..fb179958 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/pthread-fixes.c @@ -0,0 +1,56 @@ +/* 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. */ +#include +#include +#include + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + static int workaround; + int err; + + if (workaround) { + return sigprocmask(how, set, oset); + } else { + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } + } + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/signal.c b/3rd/libuv-1.19.2/src/unix/signal.c new file mode 100644 index 00000000..b9d0a560 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/signal.c @@ -0,0 +1,564 @@ +/* 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 +#include +#include +#include +#include +#include + +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +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 int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); +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 void uv__signal_unregister_handler(int signum); + + +static uv_once_t uv__signal_global_init_guard = UV_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_reinit(void); + +static void uv__signal_global_init(void) { + if (!uv__signal_lock_pipefd[0]) + /* pthread_atfork can register before and after handlers, one + * for each child. This only registers one for the child. That + * state is both persistent and cumulative, so if we keep doing + * it the handler functions will be called multiple times. Thus + * we only want to do it once. + */ + if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) + abort(); + + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); +} + + +static void uv__signal_global_reinit(void) { + /* We can only use signal-safe functions here. + * That includes read/write and close, fortunately. + * We do all of this directly here instead of resetting + * uv__signal_global_init_guard because + * uv__signal_global_once_init is only called from uv_loop_init + * and this needs to function in existing loops. + */ + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + uv__signal_global_init(); +} + + +void uv__signal_global_once_init(void) { + uv_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.flags = 0; + 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, int oneshot) { + /* 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; + sa.sa_flags = SA_RESTART; + if (oneshot) + sa.sa_flags |= SA_RESETHAND; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return UV__ERR(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, POLLIN); + + return 0; +} + + +int uv__signal_loop_fork(uv_loop_t* loop) { + uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); + uv__close(loop->signal_pipefd[0]); + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + return uv__signal_loop_once_init(loop); +} + + +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) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +static int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { + sigset_t saved_sigmask; + int err; + uv_signal_t* first_handle; + + assert(!uv__is_closing(handle)); + + /* 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 + * 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. + * Also in case there's only one-shot handlers and a regular handler comes in. + */ + first_handle = uv__signal_first_handle(signum); + if (first_handle == NULL || + (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + err = uv__signal_register_handler(signum, oneshot); + if (err) { + /* Registering the signal handler failed. Must be an invalid signal. */ + uv__signal_unlock_and_unblock(&saved_sigmask); + return err; + } + } + + handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + + 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 (handle->flags & UV__SIGNAL_ONE_SHOT) + uv__signal_stop(handle); + + /* 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) { + int f1; + int f2; + /* 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; + + /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first + * handler returned is a one-shot handler, the rest will be too. + */ + f1 = w1->flags & UV__SIGNAL_ONE_SHOT; + f2 = w2->flags & UV__SIGNAL_ONE_SHOT; + if (f1 < f2) return -1; + if (f1 > f2) 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(!uv__is_closing(handle)); + uv__signal_stop(handle); + return 0; +} + + +static void uv__signal_stop(uv_signal_t* handle) { + uv_signal_t* removed_handle; + sigset_t saved_sigmask; + uv_signal_t* first_handle; + int rem_oneshot; + int first_oneshot; + int ret; + + /* 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. + */ + first_handle = uv__signal_first_handle(handle->signum); + if (first_handle == NULL) { + uv__signal_unregister_handler(handle->signum); + } else { + rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; + first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; + if (first_oneshot && !rem_oneshot) { + ret = uv__signal_register_handler(handle->signum, 1); + assert(ret == 0); + } + } + + uv__signal_unlock_and_unblock(&saved_sigmask); + + handle->signum = 0; + uv__handle_stop(handle); +} diff --git a/3rd/libuv-1.19.2/src/unix/spinlock.h b/3rd/libuv-1.19.2/src/unix/spinlock.h new file mode 100644 index 00000000..a20c83cc --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/spinlock.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013, Ben Noordhuis + * + * 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/3rd/libuv-1.19.2/src/unix/stream.c b/3rd/libuv-1.19.2/src/unix/stream.c new file mode 100644 index 00000000..3e786abe --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/stream.c @@ -0,0 +1,1696 @@ +/* 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* IOV_MAX */ + +#if defined(__APPLE__) +# include +# include +# include + +/* 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; +}; +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ + (errno == EMSGSIZE && send_handle)) +#else +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) +#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, POLLIN)) + FD_SET(fd, s->sread); + if (uv__io_active(&stream->io_watcher, 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 |= POLLIN; + if (FD_ISSET(fd, s->swrite)) + events |= 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 & (POLLIN | POLLOUT))); + + /* Invoke callback on event-loop */ + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); + + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, 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 UV__ERR(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; + + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + + uv__close(kq); + + if (ret == -1) + return UV__ERR(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 UV__ERR(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 = UV_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 UV_EBUSY; + + assert(fd >= 0); + stream->flags |= flags; + + if (stream->type == UV_TCP) { + if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return UV__ERR(errno); + + /* TODO Use delay the user passed in. */ + if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + return UV__ERR(errno); + } + +#if defined(__APPLE__) + enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && + errno != ENOTSOCK && + errno != EINVAL) { + return UV__ERR(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, POLLIN | 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, UV_ECANCELED); + stream->connect_req = NULL; + } + + uv__stream_flush_write_queue(stream, UV_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, UV_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 UV_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 == UV_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 & POLLIN); + assert(stream->accepted_fd == -1); + assert(!(stream->flags & UV_CLOSING)); + + uv__io_start(stream->loop, &stream->io_watcher, 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 == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) + return; /* Not an error. */ + + if (err == UV_ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ + + if (err == UV_EMFILE || err == UV_ENFILE) { + err = uv__emfile_trick(loop, uv__stream_fd(stream)); + if (err == UV_EAGAIN || err == UV__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, 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; + + assert(server->loop == client->loop); + + if (server->accepted_fd == -1) + return UV_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 UV_EINVAL; + } + + client->flags |= UV_HANDLE_BOUND; + +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, 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 = UV_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, 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 = UV__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; + int err; + +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) { + int fd_to_send; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + char data[64]; + struct cmsghdr alias; + } scratch; + + if (uv__is_closing(req->send_handle)) { + err = UV_EBADF; + goto error; + } + + fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + + memset(&scratch, 0, sizeof(scratch)); + + 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 = &scratch.alias; + 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 (!WRITE_RETRY_ON_ERROR(req->send_handle)) { + err = UV__ERR(errno); + goto error; + } 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, POLLOUT); + + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); + + return; + +error: + req->error = err; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) + uv__handle_stop(stream); + 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 sslen; + socklen_t len; + int type; + + memset(&ss, 0, sizeof(ss)); + sslen = sizeof(ss); + + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) + return UV_UNKNOWN_HANDLE; + + len = sizeof type; + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_STREAM) { +#if defined(_AIX) || defined(__DragonFly__) + /* on AIX/DragonFly 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 (sslen == 0) + return UV_NAMED_PIPE; +#endif + 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, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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 UV_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 UV_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; +} + + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wgnu-folding-constant" +#endif + +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); + + buf = uv_buf_init(NULL, 0); + stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); + if (buf.base == NULL || 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, POLLIN); + uv__stream_osx_interrupt_select(stream); + } + stream->read_cb(stream, 0, &buf); +#if defined(__CYGWIN__) || defined(__MSYS__) + } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { + uv__stream_eof(stream, &buf); + return; +#endif + } else { + /* Error. User should call uv_close(). */ + stream->read_cb(stream, UV__ERR(errno), &buf); + if (stream->flags & UV_STREAM_READING) { + stream->flags &= ~UV_STREAM_READING; + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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; + } + } + +#if defined(__MVS__) + if (is_ipc && msg.msg_controllen > 0) { + uv_buf_t blankbuf; + int nread; + struct iovec *old; + + blankbuf.base = 0; + blankbuf.len = 0; + old = msg.msg_iov; + msg.msg_iov = (struct iovec*) &blankbuf; + nread = 0; + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + msg.msg_iov = old; + return; + } + } while (nread == 0 && msg.msg_controllen > 0); + msg.msg_iov = old; + } +#endif + 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; + } + } + } +} + + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#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_TTY || + stream->type == UV_NAMED_PIPE); + + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || + stream->flags & UV_STREAM_SHUTTING || + uv__is_closing(stream)) { + return UV_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, 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 & (POLLIN | POLLERR | 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 & 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 & (POLLOUT | POLLERR | 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 = UV__ERR(error); + } + + if (error == UV__ERR(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, POLLOUT); + } + + if (req->cb) + req->cb(req, error); + + if (uv__stream_fd(stream) == -1) + return; + + if (error < 0) { + uv__stream_flush_write_queue(stream, UV_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 UV_EBADF; + + if (send_handle) { + if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) + return UV_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 UV_EBADF; + +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. + See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ + return UV_ENOSYS; +#endif + } + + /* 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 UV_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, 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 UV_EAGAIN; + + has_pollout = uv__io_active(&stream->io_watcher, 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, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } + + if (written == 0 && req_size != 0) + return UV_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 UV_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, 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, POLLIN); + if (!uv__io_active(&stream->io_watcher, 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, POLLIN | 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/3rd/libuv-1.19.2/src/unix/sunos.c b/3rd/libuv-1.19.2/src/unix/sunos.c new file mode 100644 index 00000000..b6b3dfea --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sunos.c @@ -0,0 +1,821 @@ +/* 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 +#include +#include +#include +#include +#include + +#ifndef SUNOS_NO_IFADDRS +# include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 + +#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 UV__ERR(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; + } +} + + +int uv__io_fork(uv_loop_t* loop) { +#if defined(PORT_SOURCE_FILE) + if (loop->fs_fd != -1) { + /* stop the watcher before we blow away its fileno */ + uv__io_stop(loop, &loop->fs_event_watcher, POLLIN); + } +#endif + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + + +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; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return UV__ERR(errno); + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + +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 have_signals; + 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; + } + + have_signals = 0; + 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; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + 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); + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + 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 UV_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 UV__ERR(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 UV_EBADF; + + if (port_associate(handle->loop->fs_fd, + PORT_SOURCE_FILE, + (uintptr_t) &handle->fo, + FILE_ATTRIB | FILE_MODIFIED, + handle) == -1) { + return UV__ERR(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 UV_EINVAL; + + first_run = 0; + if (handle->loop->fs_fd == -1) { + portfd = port_create(); + if (portfd == -1) + return UV__ERR(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) { + uv_fs_event_stop(handle); + 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, 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 UV_ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* filename, + unsigned int flags) { + return UV_ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return UV_ENOSYS; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + +#endif /* defined(PORT_SOURCE_FILE) */ + + +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 UV__ERR(errno); + + /* FIXME(bnoordhuis) Handle EINTR. */ + err = UV_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 UV_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 UV_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 UV_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); +} + +#ifdef SUNOS_NO_IFADDRS +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + return UV_ENOSYS; +} +#else /* SUNOS_NO_IFADDRS */ +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return UV__ERR(errno); + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} + + +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + if (ent->ifa_addr->sa_family != AF_INET && + ent->ifa_addr->sa_family != AF_INET6) + return 1; + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + struct ifaddrs* addrs; + struct ifaddrs* ent; + + if (getifaddrs(&addrs)) + return UV__ERR(errno); + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + continue; + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + if (!(*addresses)) { + freeifaddrs(addrs); + return UV_ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + 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)); + + uv__set_phys_addr(address, ent); + 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/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c b/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c new file mode 100644 index 00000000..ebad0e89 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c @@ -0,0 +1,36 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +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; +} diff --git a/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c b/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c new file mode 100644 index 00000000..23b4fc6e --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c @@ -0,0 +1,42 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/unix/tcp.c b/3rd/libuv-1.19.2/src/unix/tcp.c new file mode 100644 index 00000000..96f89312 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/tcp.c @@ -0,0 +1,444 @@ +/* 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 +#include +#include +#include + + +static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + int sockfd; + int err; + + 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; + } + + if (flags & UV_HANDLE_BOUND) { + /* Bind this new socket to an arbitrary port */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); + if (err) { + uv__close(sockfd); + return err; + } + + err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); + if (err) { + uv__close(sockfd); + return err; + } + } + + return 0; +} + + +static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + + if (domain == AF_UNSPEC) { + handle->flags |= flags; + return 0; + } + + if (uv__stream_fd(handle) != -1) { + + if (flags & UV_HANDLE_BOUND) { + + if (handle->flags & UV_HANDLE_BOUND) { + /* It is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Query to see if tcp socket is bound. */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) + return UV__ERR(errno); + + if ((saddr.ss_family == AF_INET6 && + ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || + (saddr.ss_family == AF_INET && + ((struct sockaddr_in*) &saddr)->sin_port != 0)) { + /* Handle is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Bind to arbitrary port */ + if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) + return UV__ERR(errno); + } + + handle->flags |= flags; + return 0; + } + + return new_socket(handle, domain, flags); +} + + +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 UV_EINVAL; + + if (flags & ~0xFF) + return UV_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 UV_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 UV__ERR(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) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return UV_EINVAL; +#endif + return UV__ERR(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 UV_EINVAL; + return UV__ERR(errno); + } + tcp->delayed_error = UV__ERR(errno); + + tcp->flags |= UV_HANDLE_BOUND; + 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 UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ + + err = maybe_new_socket(handle, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); + if (err) + return err; + + handle->delayed_error = 0; + + do { + errno = 0; + r = connect(uv__stream_fd(handle), addr, addrlen); + } while (r == -1 && errno == EINTR); + + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { + 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 = UV__ERR(errno); + else + return UV__ERR(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, 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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(uv__stream_fd(handle), name, &socklen)) + return UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getpeername(uv__stream_fd(handle), name, &socklen)) + return UV__ERR(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; + unsigned long flags; + 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; + + flags = UV_STREAM_READABLE; +#if defined(__MVS__) + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + flags |= UV_HANDLE_BOUND; +#endif + err = maybe_new_socket(tcp, AF_INET, flags); + if (err) + return err; + + if (listen(tcp->io_watcher.fd, backlog)) + return UV__ERR(errno); + + tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; + + /* Start listening for connections. */ + tcp->io_watcher.cb = uv__server_io; + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); + + return 0; +} + + +int uv__tcp_nodelay(int fd, int on) { + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) + return UV__ERR(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 UV__ERR(errno); + +#ifdef TCP_KEEPIDLE + if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return UV__ERR(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 UV__ERR(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/3rd/libuv-1.19.2/src/unix/thread.c b/3rd/libuv-1.19.2/src/unix/thread.c new file mode 100644 index 00000000..3def2945 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/thread.c @@ -0,0 +1,729 @@ +/* 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 +#include +#include + +#include +#include /* getrlimit() */ +#include /* getpagesize() */ + +#include + +#ifdef __MVS__ +#include +#include +#endif + +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + +#if defined(UV__PTHREAD_BARRIER_FALLBACK) +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} +#endif + + +/* On MacOS, threads other than the main thread are created with a reduced + * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. + * + * On Linux, threads created by musl have a much smaller stack than threads + * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. + */ +static size_t thread_stack_size(void) { +#if defined(__APPLE__) || defined(__linux__) + struct rlimit lim; + + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + return lim.rlim_cur; + } +#endif + +#if !defined(__linux__) + return 0; +#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) + return 4 << 20; /* glibc default. */ +#else + return 2 << 20; /* glibc default. */ +#endif +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + int err; + size_t stack_size; + pthread_attr_t* attr; + pthread_attr_t attr_storage; + + attr = NULL; + stack_size = thread_stack_size(); + + if (stack_size > 0) { + attr = &attr_storage; + + if (pthread_attr_init(attr)) + abort(); + + if (pthread_attr_setstacksize(attr, stack_size)) + abort(); + } + + err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); + + if (attr != NULL) + pthread_attr_destroy(attr); + + return UV__ERR(err); +} + + +uv_thread_t uv_thread_self(void) { + return pthread_self(); +} + +int uv_thread_join(uv_thread_t *tid) { + return UV__ERR(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 UV__ERR(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 UV__ERR(err); +#endif +} + + +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return UV__ERR(err); +} + + +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 UV_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 UV__ERR(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 UV_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 UV_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 UV_EINVAL; + if (err == KERN_RESOURCE_SHORTAGE) + return UV_ENOMEM; + + abort(); + return UV_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 UV_EAGAIN; + + abort(); + return UV_EINVAL; /* Satisfy the compiler. */ +} + +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + int err; + union { + int val; + struct semid_ds* buf; + unsigned short* array; + } arg; + + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return UV__ERR(errno); + + arg.val = value; + if (-1 == semctl(semid, 0, SETVAL, arg)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return UV__ERR(err); + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return UV_EAGAIN; + abort(); + } + + return 0; +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + if (sem_init(sem, 0, value)) + return UV__ERR(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 UV_EAGAIN; + abort(); + } + + return 0; +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) + +int uv_cond_init(uv_cond_t* cond) { + return UV__ERR(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 UV__ERR(err); + +#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) + 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 UV__ERR(err); +} + +#endif /* defined(__APPLE__) && defined(__MACH__) */ + +void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + 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(__MVS__) + struct timeval tv; +#endif + +#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 +#if defined(__MVS__) + if (gettimeofday(&tv, NULL)) + abort(); + timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; +#else + timeout += uv__hrtime(UV_CLOCK_PRECISE); +#endif + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + + /* + * 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_API__ */ +#endif + + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return UV_ETIMEDOUT; + + abort(); + return UV_EINVAL; /* Satisfy the compiler. */ +} + + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(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; +} + + +int uv_key_create(uv_key_t* key) { + return UV__ERR(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/3rd/libuv-1.19.2/src/unix/timer.c b/3rd/libuv-1.19.2/src/unix/timer.c new file mode 100644 index 00000000..54dabfe7 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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, uv_timer_t, heap_node); + b = container_of(hb, 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 UV_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 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) { + 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, 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/3rd/libuv-1.19.2/src/unix/tty.c b/3rd/libuv-1.19.2/src/unix/tty.c new file mode 100644 index 00000000..f22b3b80 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/tty.c @@ -0,0 +1,372 @@ +/* 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 +#include +#include +#include +#include +#include + +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + +static int orig_termios_fd = -1; +static struct termios orig_termios; +static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; + +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#elif defined(__NetBSD__) + /* + * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave + * device name for both descriptors, the master one and slave one. + * + * Implement function to compare major device number with pts devices. + * + * The major numbers are machine-dependent, on NetBSD/amd64 they are + * respectively: + * - master tty: ptc - major 6 + * - slave tty: pts - major 5 + */ + + struct stat sb; + /* Lookup device's major for the pts driver and cache it. */ + static devmajor_t pts = NODEVMAJOR; + + if (pts == NODEVMAJOR) { + pts = getdevmajor("pts", S_IFCHR); + if (pts == NODEVMAJOR) + abort(); + } + + /* Lookup stat structure behind the file descriptor. */ + if (fstat(fd, &sb) != 0) + abort(); + + /* Assert character device. */ + if (!S_ISCHR(sb.st_mode)) + abort(); + + /* Assert valid major. */ + if (major(sb.st_rdev) == NODEVMAJOR) + abort(); + + result = (pts == major(sb.st_rdev)); +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} + +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; + int saved_flags; + char path[256]; + + /* 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 UV_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) { + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; + + 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 != UV_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; + } + +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return UV__ERR(errno); + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + +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 (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + +#if defined(__APPLE__) + r = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (r) { + int rc = r; + if (newfd != -1) + uv__close(newfd); + QUEUE_REMOVE(&tty->handle_queue); + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; + } +#endif + + if (readable) + flags |= UV_STREAM_READABLE; + else + flags |= UV_STREAM_WRITABLE; + + 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); + +#if defined __sun || defined __MVS__ + /* + * 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 UV__ERR(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 UV__ERR(errno); + + tty->mode = mode; + return 0; +} + + +int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { + struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); + + if (err == -1) + return UV__ERR(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) || defined(__DragonFly__) + /* on AIX/DragonFly 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) || defined(__DragonFly__) */ + + 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 UV_EBUSY; /* In uv_tty_set_mode(). */ + + err = 0; + if (orig_termios_fd != -1) + if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) + err = UV__ERR(errno); + + uv_spinlock_unlock(&termios_spinlock); + errno = saved_errno; + + return err; +} diff --git a/3rd/libuv-1.19.2/src/unix/udp.c b/3rd/libuv-1.19.2/src/unix/udp.c new file mode 100644 index 00000000..74d613b6 --- /dev/null +++ b/3rd/libuv-1.19.2/src/unix/udp.c @@ -0,0 +1,902 @@ +/* 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 +#include +#include +#include +#include +#if defined(__MVS__) +#include +#endif + +#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, POLLIN | 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 = UV_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, POLLOUT); + if (!uv__io_active(&handle->io_watcher, 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 & POLLIN) + uv__udp_recvmsg(handle); + + if (revents & 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 { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); + if (buf.base == NULL || 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, UV__ERR(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) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + break; + } + + req->status = (size == -1 ? UV__ERR(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 UV__ERR(errno); +#else + yes = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(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 UV_EINVAL; + + /* Cannot set IPv6-only mode on non-IPv6 socket. */ + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) + return UV_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) + return err; + } + + if (flags & UV_UDP_IPV6ONLY) { +#ifdef IPV6_V6ONLY + yes = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { + err = UV__ERR(errno); + return err; + } +#else + err = UV_ENOTSUP; + return err; +#endif + } + + if (bind(fd, addr, addrlen)) { + err = UV__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 = UV_EINVAL; + return err; + } + + if (addr->sa_family == AF_INET6) + handle->flags |= UV_HANDLE_IPV6; + + handle->flags |= UV_HANDLE_BOUND; + return 0; +} + + +static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, + int domain, + unsigned int flags) { + union { + struct sockaddr_in6 in6; + struct sockaddr_in in; + struct sockaddr addr; + } taddr; + socklen_t addrlen; + + if (handle->io_watcher.fd != -1) + return 0; + + switch (domain) { + case AF_INET: + { + struct sockaddr_in* addr = &taddr.in; + 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 = &taddr.in6; + 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, &taddr.addr, 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 UV_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); + + /* `uv__udp_sendmsg` may not be able to do non-blocking write straight + * away. In such cases the `io_watcher` has to be queued for asynchronous + * write. + */ + if (!QUEUE_EMPTY(&handle->write_queue)) + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); + } else { + uv__io_start(handle->loop, &handle->io_watcher, 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 UV_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 || errno == ENOBUFS) + return UV_EAGAIN; + else + return UV__ERR(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 UV_EINVAL; + } + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return UV_ENODEV; +#endif + return UV__ERR(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 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->io_watcher.fd, + IPPROTO_IPV6, + optname, + &mreq, + sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return UV_ENODEV; +#endif + return UV__ERR(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 UV_EINVAL; + + if (flags & ~0xFF) + return UV_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 UV_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 UV_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 UV__ERR(errno); + + return 0; +} + +static int uv__setsockopt_maybe_char(uv_udp_t* handle, + int option4, + int option6, + int val) { +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + char arg = val; +#elif defined(__OpenBSD__) + unsigned char arg = val; +#else + int arg = val; +#endif + + if (val < 0 || val > 255) + return UV_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 UV__ERR(errno); + } + + return 0; +} + + +int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { + if (ttl < 1 || ttl > 255) + return UV_EINVAL; + +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + +/* + * 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__) || \ + defined(__MVS__) + + return uv__setsockopt(handle, + IP_TTL, + IPV6_UNICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ + + 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) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_TTL, + IPV6_MULTICAST_HOPS, + &ttl, + sizeof(ttl)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + 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) || defined(__MVS__) + if (handle->flags & UV_HANDLE_IPV6) + return uv__setsockopt(handle, + IP_MULTICAST_LOOP, + IPV6_MULTICAST_LOOP, + &on, + sizeof(on)); +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ + + 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 UV_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 UV__ERR(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 UV__ERR(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 UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (getsockname(handle->io_watcher.fd, name, &socklen)) + return UV__ERR(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 UV_EINVAL; + + if (uv__io_active(&handle->io_watcher, POLLIN)) + return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_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, POLLIN); + uv__handle_start(handle); + + return 0; +} + + +int uv__udp_recv_stop(uv_udp_t* handle) { + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); + + if (!uv__io_active(&handle->io_watcher, POLLOUT)) + uv__handle_stop(handle); + + handle->alloc_cb = NULL; + handle->recv_cb = NULL; + + return 0; +} diff --git a/3rd/libuv-1.19.2/src/uv-common.c b/3rd/libuv-1.19.2/src/uv-common.c new file mode 100644 index 00000000..bc7d1379 --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-common.c @@ -0,0 +1,664 @@ +/* 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 +#include +#include +#include /* NULL */ +#include +#include /* malloc */ +#include /* memset */ + +#if defined(_WIN32) +# include /* malloc */ +#else +# include /* 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) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; + uv__allocator.local_free(ptr); + errno = saved_errno; +} + +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 = ""; + } + + 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 + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, handle->path, required_len); + *size = required_len; + buffer[required_len] = '\0'; + + 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 +} + +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#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__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; +} + + +int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { + uv__dirent_t** dents; + uv__dirent_t* dent; + unsigned int* nbufs; + + /* Check to see if req passed */ + if (req->result < 0) + return req->result; + + /* Ptr will be null if req was canceled or no files found */ + if (!req->ptr) + return UV_EOF; + + nbufs = uv__get_nbufs(req); + assert(nbufs); + + dents = req->ptr; + + /* Free previous entity */ + if (*nbufs > 0) + uv__fs_scandir_free(dents[*nbufs - 1]); + + /* End was already reached */ + if (*nbufs == (unsigned int) req->result) { + uv__fs_scandir_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; +#ifndef NDEBUG + void* saved_data; +#endif + + 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 + saved_data = loop->data; + memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; +#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/3rd/libuv-1.19.2/src/uv-common.h b/3rd/libuv-1.19.2/src/uv-common.h new file mode 100644 index 00000000..d4fa22aa --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-common.h @@ -0,0 +1,260 @@ +/* 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 +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#include "uv.h" +#include "tree.h" +#include "queue.h" + +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + +#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__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ + UV__HANDLE_INTERNAL = 0x8000, + UV__HANDLE_ACTIVE = 0x4000, + UV__HANDLE_REF = 0x2000, + UV__HANDLE_CLOSING = 0 /* no-op on unix */ +}; +#else +# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 +# define UV__SIGNAL_ONE_SHOT 0x100 +# 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) + +/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of + * a circular dependency between src/uv-common.h and src/win/internal.h. + */ +#if defined(_WIN32) +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \ + } \ + while (0) +#else +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + } \ + while (0) +#endif + +#define uv__req_init(loop, req, typ) \ + do { \ + UV_REQ_INIT(req, typ); \ + uv__req_register(loop, req); \ + } \ + 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/3rd/libuv-1.19.2/src/uv-data-getter-setters.c b/3rd/libuv-1.19.2/src/uv-data-getter-setters.c new file mode 100644 index 00000000..533e4a2f --- /dev/null +++ b/3rd/libuv-1.19.2/src/uv-data-getter-setters.c @@ -0,0 +1,96 @@ +#include "uv.h" + +const char* uv_handle_type_name(uv_handle_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + case UV_FILE: return "file"; + case UV_HANDLE_TYPE_MAX: + case UV_UNKNOWN_HANDLE: return NULL; + } + return NULL; +} + +uv_handle_type uv_handle_get_type(const uv_handle_t* handle) { + return handle->type; +} + +void* uv_handle_get_data(const uv_handle_t* handle) { + return handle->data; +} + +uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) { + return handle->loop; +} + +void uv_handle_set_data(uv_handle_t* handle, void* data) { + handle->data = data; +} + +const char* uv_req_type_name(uv_req_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_REQ_TYPE_MAP(XX) +#undef XX + case UV_REQ_TYPE_MAX: + case UV_UNKNOWN_REQ: return NULL; + } + return NULL; +} + +uv_req_type uv_req_get_type(const uv_req_t* req) { + return req->type; +} + +void* uv_req_get_data(const uv_req_t* req) { + return req->data; +} + +void uv_req_set_data(uv_req_t* req, void* data) { + req->data = data; +} + +size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) { + return stream->write_queue_size; +} + +size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) { + return handle->send_queue_size; +} + +size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) { + return handle->send_queue_count; +} + +uv_pid_t uv_process_get_pid(const uv_process_t* proc) { + return proc->pid; +} + +uv_fs_type uv_fs_get_type(const uv_fs_t* req) { + return req->fs_type; +} + +ssize_t uv_fs_get_result(const uv_fs_t* req) { + return req->result; +} + +void* uv_fs_get_ptr(const uv_fs_t* req) { + return req->ptr; +} + +const char* uv_fs_get_path(const uv_fs_t* req) { + return req->path; +} + +uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) { + return &req->statbuf; +} + +void* uv_loop_get_data(const uv_loop_t* loop) { + return loop->data; +} + +void uv_loop_set_data(uv_loop_t* loop, void* data) { + loop->data = data; +} diff --git a/3rd/libuv-1.19.2/src/version.c b/3rd/libuv-1.19.2/src/version.c new file mode 100644 index 00000000..686dedd9 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/src/win/async.c b/3rd/libuv-1.19.2/src/win/async.c new file mode 100644 index 00000000..0b636ed1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/async.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 + +#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(req, 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/3rd/libuv-1.19.2/src/win/atomicops-inl.h b/3rd/libuv-1.19.2/src/win/atomicops-inl.h new file mode 100644 index 00000000..6d8126f6 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/atomicops-inl.h @@ -0,0 +1,57 @@ +/* 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" +#include "internal.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 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/3rd/libuv-1.19.2/src/win/core.c b/3rd/libuv-1.19.2/src/win/core.c new file mode 100644 index 00000000..9ed4e824 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/core.c @@ -0,0 +1,605 @@ +/* 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 +#include +#include +#include +#include +#include +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) +#include +#endif + +#include "uv.h" +#include "internal.h" +#include "queue.h" +#include "handle-inl.h" +#include "req-inl.h" + +/* 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 uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init(void) { + uv_mutex_init(&uv__loops_lock); +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + if (uv__loops_size == 0) { + uv__loops_capacity = 0; + uv__free(uv__loops); + uv__loops = NULL; + goto loop_removed; + } + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops(void) { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} + +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 + + /* Initialize tracking of all uv loops */ + uv__loops_init(); + + /* 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(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); +} + + +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; + + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + + 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; + + uv__loops_remove(loop); + + /* 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_loop_fork(uv_loop_t* loop) { + return UV_ENOSYS; +} + + +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; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + 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 target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +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; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + 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 target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + +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/3rd/libuv-1.19.2/src/win/detect-wakeup.c b/3rd/libuv-1.19.2/src/win/detect-wakeup.c new file mode 100644 index 00000000..72dfb7a1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(void); + +void uv__init_detect_system_wakeup(void) { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback(void) { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/3rd/libuv-1.19.2/src/win/dl.c b/3rd/libuv-1.19.2/src/win/dl.c new file mode 100644 index 00000000..97ac1c1a --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/dl.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 "internal.h" + +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); + + +int uv_dlopen(const char* filename, uv_lib_t* lib) { + WCHAR filename_w[32768]; + + lib->handle = NULL; + lib->errmsg = NULL; + + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, filename, GetLastError()); + } + + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, filename, 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, const char* filename, DWORD errorno) { + DWORD_PTR arg; + DWORD res; + char* msg; + + if (lib->errmsg) { + LocalFree(lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno == 0) + return 0; + + 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 && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) { + msg = lib->errmsg; + lib->errmsg = NULL; + arg = (DWORD_PTR) filename; + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + msg, + 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); + LocalFree(msg); + } + + if (!res) + uv__format_fallback_error(lib, errorno); + + return -1; +} diff --git a/3rd/libuv-1.19.2/src/win/error.c b/3rd/libuv-1.19.2/src/win/error.c new file mode 100644 index 00000000..9b03bfef --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/error.c @@ -0,0 +1,171 @@ +/* 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 +#include +#include +#include +#include + +#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); + } + + DebugBreak(); + 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_ELEVATION_REQUIRED: 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/3rd/libuv-1.19.2/src/win/fs-event.c b/3rd/libuv-1.19.2/src/win/fs-event.c new file mode 100644 index 00000000..95f843ad --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/fs-event.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 +#include +#include +#include + +#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 void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') + dirlen--; + relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); + if (!*relpath) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; +} + +static int uv_split_path(const WCHAR* filename, WCHAR** dir, + WCHAR** file) { + size_t len, i; + + if (filename == NULL) { + if (dir != NULL) + *dir = NULL; + *file = NULL; + return 0; + } + + len = wcslen(filename); + 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 + 2) * sizeof(WCHAR)); + if (!*dir) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = 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(&handle->req, 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_buffer[MAX_PATH]; + WCHAR* short_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 = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * + sizeof(WCHAR); + pathw = (WCHAR*)uv__malloc(name_size); + if (!pathw) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + 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. */ + 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. */ + short_path = short_path_buffer; + if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + short_path = NULL; + } + + 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; + } + + assert(is_path_dir ? pathw != NULL : pathw == NULL); + handle->dirw = pathw; + 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; + } + + if (uv__is_active(handle)) + uv__handle_stop(handle); + + 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; +} + + +static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) { + size_t str_len; + + if (str == NULL) + return -1; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + +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; + char* filename = NULL; + WCHAR* filenamew = NULL; + WCHAR* 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(!filenamew); + assert(!long_filenamew); + + /* + * Fire the event only if we were asked to watch a directory, + * or if the filename filter matches. + */ + if (handle->dirw || + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 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 / (DWORD)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. */ + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); + uv__free(long_filenamew); + long_filenamew = filenamew; + sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + 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. + */ + 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; + } + + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); + + 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; + 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/3rd/libuv-1.19.2/src/win/fs.c b/3rd/libuv-1.19.2/src/win/fs.c new file mode 100644 index 00000000..6e0bdc7b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/fs.c @@ -0,0 +1,2426 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" +#include "handle-inl.h" + +#include + + +#define UV_FS_FREE_PATHS 0x0002 +#define UV_FS_FREE_PTR 0x0008 +#define UV_FS_CLEANEDUP 0x0010 + + +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + uv_fs_req_init(loop, req, subtype, cb); \ + } \ + while (0) + +#define POST \ + do { \ + if (cb != NULL) { \ + uv__req_register(loop, req); \ + 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) + +#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 = ((uint64_t) ((time) * 10000000ULL)) + \ + 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; + +static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + +void uv_fs_init(void) { + _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 = 0, 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; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf)); + req->path = pos; + } + + 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__once_init(); + UV_REQ_INIT(req, 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; + req->fs.info.bufs = NULL; + memset(&req->fs, 0, sizeof(req->fs)); +} + + +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'\\')) { + /* \??\:\ */ + 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\\\ - make sure the final path looks like */ + /* \\\\ */ + 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 \??\:\ as symlink. */ + /* Junctions can also be used as mount points, like \??\Volume{}, */ + /* 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 & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { + case UV_FS_O_RDONLY: + access = FILE_GENERIC_READ; + break; + case UV_FS_O_WRONLY: + access = FILE_GENERIC_WRITE; + break; + case UV_FS_O_RDWR: + access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + break; + default: + goto einval; + } + + if (flags & UV_FS_O_APPEND) { + access &= ~FILE_WRITE_DATA; + access |= FILE_APPEND_DATA; + } + + /* + * 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. + * We still support exclusive sharing mode, since it is necessary + * for opening raw block devices, otherwise Windows will prevent + * any attempt to write past the master boot record. + */ + if (flags & UV_FS_O_EXLOCK) { + share = 0; + } else { + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + } + + switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { + case 0: + case UV_FS_O_EXCL: + disposition = OPEN_EXISTING; + break; + case UV_FS_O_CREAT: + disposition = OPEN_ALWAYS; + break; + case UV_FS_O_CREAT | UV_FS_O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL: + disposition = CREATE_NEW; + break; + case UV_FS_O_TRUNC: + case UV_FS_O_TRUNC | UV_FS_O_EXCL: + disposition = TRUNCATE_EXISTING; + break; + case UV_FS_O_CREAT | UV_FS_O_TRUNC: + disposition = CREATE_ALWAYS; + break; + default: + goto einval; + } + + attributes |= FILE_ATTRIBUTE_NORMAL; + if (flags & UV_FS_O_CREAT) { + if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { + attributes |= FILE_ATTRIBUTE_READONLY; + } + } + + if (flags & UV_FS_O_TEMPORARY ) { + attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; + access |= DELETE; + } + + if (flags & UV_FS_O_SHORT_LIVED) { + attributes |= FILE_ATTRIBUTE_TEMPORARY; + } + + switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) { + case 0: + break; + case UV_FS_O_SEQUENTIAL: + attributes |= FILE_FLAG_SEQUENTIAL_SCAN; + break; + case UV_FS_O_RANDOM: + attributes |= FILE_FLAG_RANDOM_ACCESS; + break; + default: + goto einval; + } + + if (flags & UV_FS_O_DIRECT) { + attributes |= FILE_FLAG_NO_BUFFERING; + } + + switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) { + case 0: + break; + case UV_FS_O_DSYNC: + case UV_FS_O_SYNC: + attributes |= FILE_FLAG_WRITE_THROUGH; + 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 & UV_FS_O_CREAT) && + !(flags & UV_FS_O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_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; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; + + VERIFY_FD(fd, req); + + zero_offset.QuadPart = 0; + restore_position = 0; + 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; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } + } 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 (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + + 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; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; + + VERIFY_FD(fd, req); + + zero_offset.QuadPart = 0; + restore_position = 0; + 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; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } + } 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 (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + + 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. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; + 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, + int do_lstat) { + 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; + + /* + * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism + * by which filesystem drivers can intercept and alter file system requests. + * + * The only reparse points we care about are symlinks and mount points, both + * of which are treated as POSIX symlinks. Further, we only care when + * invoked via lstat, which seeks information about the link instead of its + * target. Otherwise, reparse points must be treated as regular files. + */ + if (do_lstat && + (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + /* + * If reading the link fails, the reparse point is not a symlink and needs + * to be treated as a regular file. The higher level lstat function will + * detect this failure and retry without do_lstat if appropriate. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + return -1; + statbuf->st_mode |= S_IFLNK; + } + + if (statbuf->st_mode == 0) { + 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. + * + * 4096 is the minimum required to be compatible with newer Advanced Format + * drives (which have 4096 bytes per physical sector), and to be backwards + * compatible with older drives (which have 512 bytes per physical sector). + */ + statbuf->st_blksize = 4096; + + /* 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, do_lstat) != 0) { + DWORD error = GetLastError(); + if (do_lstat && + (error == ERROR_SYMLINK_NOT_SUPPORTED || + error == ERROR_NOT_A_REPARSE_POINT)) { + /* 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) != 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__copyfile(uv_fs_t* req) { + int flags; + int overwrite; + + flags = req->fs.info.file_flags; + overwrite = flags & UV_FS_COPYFILE_EXCL; + + if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + +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->fs.info.mode & 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(atime, &filetime_a); + TIME_T_TO_FILETIME(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; + WCHAR* new_pathw; + int flags; + int err; + + pathw = req->file.pathw; + new_pathw = req->fs.info.new_pathw; + + if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, pathw, new_pathw); + return; + } + if (!pCreateSymbolicLinkW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) + flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; + else + flags = uv__file_symlink_usermode_flag; + + if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + SET_REQ_RESULT(req, 0); + return; + } + + /* Something went wrong. We will test if it is because of user-mode + * symlinks. + */ + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER && + flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) { + /* This system does not support user-mode symlinks. We will clear the + * unsupported flag and retry. + */ + uv__file_symlink_usermode_flag = 0; + fs__symlink(req); + } else { + SET_REQ_WIN32_ERROR(req, err); + } +} + + +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 = NULL; + WCHAR* w_realpath_buf; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + w_realpath_ptr = w_realpath_buf; + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_buf); + 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_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_realpath_ptr += 4; + w_realpath_len -= 4; + } else { + uv__free(w_realpath_buf); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); + 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(COPYFILE, copyfile) + 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 == NULL) + return; + + 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) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } + + if (req->fs.info.bufs != req->fs.info.bufsml) + uv__free(req->fs.info.bufs); + + req->path = NULL; + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->fs.info.bufs = 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; + + INIT(UV_FS_OPEN); + 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; + POST; +} + + +int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_CLOSE); + req->file.fd = fd; + POST; +} + + +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) { + INIT(UV_FS_READ); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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; + POST; +} + + +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) { + INIT(UV_FS_WRITE); + + if (bufs == NULL || nbufs == 0) + return UV_EINVAL; + + 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; + POST; +} + + +int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_UNLINK); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_MKDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + POST; +} + + +int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_MKDTEMP); + err = fs__capture_path(req, tpl, NULL, TRUE); + if (err) + return uv_translate_sys_error(err); + + POST; +} + + +int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_RMDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_SCANDIR); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + POST; +} + + +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; + + INIT(UV_FS_LINK); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + 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) { + int err; + + INIT(UV_FS_SYMLINK); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.file_flags = flags; + POST; +} + + +int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_READLINK); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_REALPATH); + + if (!path) { + return UV_EINVAL; + } + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + 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) { + int err; + + INIT(UV_FS_CHOWN); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +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) { + INIT(UV_FS_FCHOWN); + POST; +} + + +int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_STAT); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LSTAT); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FSTAT); + req->file.fd = fd; + POST; +} + + +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; + + INIT(UV_FS_RENAME); + err = fs__capture_path(req, path, new_path, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + POST; +} + + +int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FSYNC); + req->file.fd = fd; + POST; +} + + +int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + INIT(UV_FS_FDATASYNC); + req->file.fd = fd; + POST; +} + + +int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, + int64_t offset, uv_fs_cb cb) { + INIT(UV_FS_FTRUNCATE); + req->file.fd = fd; + req->fs.info.offset = offset; + POST; +} + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_COPYFILE); + + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + + err = fs__capture_path(req, path, new_path, cb != NULL); + + if (err) + return uv_translate_sys_error(err); + + req->fs.info.file_flags = flags; + POST; +} + + +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) { + INIT(UV_FS_SENDFILE); + 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; + POST; +} + + +int uv_fs_access(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_ACCESS); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) + return uv_translate_sys_error(err); + + req->fs.info.mode = flags; + POST; +} + + +int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, + uv_fs_cb cb) { + int err; + + INIT(UV_FS_CHMOD); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + req->fs.info.mode = mode; + POST; +} + + +int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, + uv_fs_cb cb) { + INIT(UV_FS_FCHMOD); + req->file.fd = fd; + req->fs.info.mode = mode; + POST; +} + + +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; + + INIT(UV_FS_UTIME); + 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; + POST; +} + + +int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, + double mtime, uv_fs_cb cb) { + INIT(UV_FS_FUTIME); + req->file.fd = fd; + req->fs.time.atime = atime; + req->fs.time.mtime = mtime; + POST; +} diff --git a/3rd/libuv-1.19.2/src/win/getaddrinfo.c b/3rd/libuv-1.19.2/src/win/getaddrinfo.c new file mode 100644 index 00000000..282d919c --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/getaddrinfo.c @@ -0,0 +1,453 @@ +/* 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 + +#include "uv.h" +#include "internal.h" +#include "req-inl.h" + +/* EAI_* constants. */ +#include + +/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */ +#include + +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) + +#ifndef NDIS_IF_MAX_STRING_SIZE +#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE +#endif + +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 = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + 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 = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + NULL, + 0, + NULL, + NULL); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); + 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)) { + return UV_EINVAL; + } + + UV_REQ_INIT(req, UV_GETADDRINFO); + req->getaddrinfo_cb = getaddrinfo_cb; + req->addrinfo = NULL; + req->loop = loop; + req->retcode = 0; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); + if (nodesize == 0) { + err = GetLastError(); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + 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 (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (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 (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (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); +} + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + NET_LUID luid; + wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ + DWORD bufsize; + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = ConvertInterfaceIndexToLuid(ifindex, &luid); + + if (r != 0) + return uv_translate_sys_error(r); + + r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); + + if (r != 0) + return uv_translate_sys_error(r); + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + wname, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = snprintf(buffer, *size, "%d", ifindex); + + if (r < 0) + return uv_translate_sys_error(r); + + if (r >= (int) *size) { + *size = r + 1; + return UV_ENOBUFS; + } + + *size = r; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/win/getnameinfo.c b/3rd/libuv-1.19.2/src/win/getnameinfo.c new file mode 100644 index 00000000..9f10cd2a --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/getnameinfo.c @@ -0,0 +1,149 @@ +/* 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 +#include + +#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(req, UV_GETNAMEINFO); + uv__req_register(loop, req); + + req->getnameinfo_cb = getnameinfo_cb; + req->flags = flags; + 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/3rd/libuv-1.19.2/src/win/handle-inl.h b/3rd/libuv-1.19.2/src/win/handle-inl.h new file mode 100644 index 00000000..8d0334cc --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/src/win/handle.c b/3rd/libuv-1.19.2/src/win/handle.c new file mode 100644 index 00000000..39150702 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/handle.c @@ -0,0 +1,159 @@ +/* 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 +#include +#include + +#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)); +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return uv__get_osfhandle(fd); +} diff --git a/3rd/libuv-1.19.2/src/win/internal.h b/3rd/libuv-1.19.2/src/win/internal.h new file mode 100644 index 00000000..217fcdb5 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/internal.h @@ -0,0 +1,394 @@ +/* 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 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 + +/* 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(void); + +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_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(void); + + +/* + * 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(void); +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(void); + + +/* + * 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(void); + +uint64_t uv__hrtime(double scale); +int uv_current_pid(void); +__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); +int uv__getpwuid_r(uv_passwd_t* pwd); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); +int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); + + +/* + * 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(void); + + +/* + * Winsock utility functions + */ +void uv_winsock_init(void); + +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_; + +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(void); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(void); + +#endif /* UV_WIN_INTERNAL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/loop-watcher.c b/3rd/libuv-1.19.2/src/win/loop-watcher.c new file mode 100644 index 00000000..20e4509f --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/src/win/pipe.c b/3rd/libuv-1.19.2/src/win/pipe.c new file mode 100644 index 00000000..1a7c4dc1 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/pipe.c @@ -0,0 +1,2214 @@ +/* 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 +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include "stream-inl.h" +#include "req-inl.h" + +#include +#include + +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-%lu", 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(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_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 | WRITE_DAC, + 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, ¤t_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(req, UV_ACCEPT); + req->data = handle; + req->pipeHandle = INVALID_HANDLE_VALUE; + req->next_pending = NULL; + } + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + 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 | WRITE_DAC, + 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(req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + + /* Convert name to UTF16. */ + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); + handle->name = (WCHAR*)uv__malloc(nameSize); + if (!handle->name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + 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 | WRITE_DAC, + 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, FALSE, DUPLICATE_SAME_ACCESS)) { + handle->pipe.conn.readfile_thread = hThread; + } else { + hThread = NULL; + } + uv_mutex_unlock(m); + } +restart_readfile: + if (handle->flags & UV_HANDLE_READING) { + 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 */ + } + } + } + } else { + result = 1; /* successfully aborted read before it even started */ + } + 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(req, 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(ipc_header_req, 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_OPERATION_ABORTED) { + /* do nothing (equivalent to EINTR) */ + } + else 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); + } + } + + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, avail, &buf); + if (buf.base == NULL || 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; + + uv__once_init(); + /* 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_os_getppid(); + 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; + + uv__once_init(); + 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 + 1; + 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; + buffer[addrlen] = '\0'; + + err = 0; + +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; +} + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + EXPLICIT_ACCESS ea; + PSID everyone; + int error; + + if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (!AllocateAndInitializeSid(&sid_world, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &everyone)) { + error = GetLastError(); + goto done; + } + + if (GetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &old_dacl, + NULL, + &sd)) { + error = GetLastError(); + goto clean_sid; + } + + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); + if (mode & UV_READABLE) + ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + if (mode & UV_WRITABLE) + ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + ea.grfAccessPermissions |= SYNCHRONIZE; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPTSTR)everyone; + + if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { + error = GetLastError(); + goto clean_sd; + } + + if (SetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + new_dacl, + NULL)) { + error = GetLastError(); + goto clean_dacl; + } + + error = 0; + +clean_dacl: + LocalFree((HLOCAL) new_dacl); +clean_sd: + LocalFree((HLOCAL) sd); +clean_sid: + FreeSid(everyone); +done: + return uv_translate_sys_error(error); +} diff --git a/3rd/libuv-1.19.2/src/win/poll.c b/3rd/libuv-1.19.2/src/win/poll.c new file mode 100644 index 00000000..a648ba71 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/poll.c @@ -0,0 +1,644 @@ +/* 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 +#include + +#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(void) { + uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); + return &overlapped_dummy_; +} + + +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) { + 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 { + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ + 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; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } + } + 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_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } + } + 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 | UV_DISCONNECT)) == 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(&handle->poll_req_1, UV_POLL_REQ); + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + UV_REQ_INIT(&handle->poll_req_2, 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/3rd/libuv-1.19.2/src/win/process-stdio.c b/3rd/libuv-1.19.2/src/win/process-stdio.c new file mode 100644 index 00000000..032e3093 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/process-stdio.c @@ -0,0 +1,511 @@ +/* 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 +#include +#include +#include + +#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; + break; + + 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/3rd/libuv-1.19.2/src/win/process.c b/3rd/libuv-1.19.2/src/win/process.c new file mode 100644 index 00000000..75235222 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/process.c @@ -0,0 +1,1272 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include /* 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(&handle->exit_req, 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; + + /* If path is quoted, find quote end */ + if (*dir_start == L'"' || *dir_start == L'\'') { + dir_end = wcschr(dir_start + 1, *dir_start); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + } + /* Slice until the next ; or \0 is found */ + dir_end = wcschr(dir_end, 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); + + process_flags = CREATE_UNICODE_ENVIRONMENT; + + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Avoid creating console window if stdio is not inherited. */ + for (i = 0; i < options->stdio_count; i++) { + if (options->stdio[i].flags & UV_INHERIT_FD) + break; + if (i == options->stdio_count - 1) + process_flags |= CREATE_NO_WINDOW; + } + + /* Use SW_HIDE to avoid any potential process window. */ + startup.wShowWindow = SW_HIDE; + } else { + startup.wShowWindow = SW_SHOWDEFAULT; + } + + 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) { + if (signum < 0 || signum >= NSIG) { + return UV_EINVAL; + } + + 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; + + if (pid == 0) { + process_handle = GetCurrentProcess(); + } else { + 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/3rd/libuv-1.19.2/src/win/req-inl.h b/3rd/libuv-1.19.2/src/win/req-inl.h new file mode 100644 index 00000000..f2513b7d --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/req-inl.h @@ -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. + */ + +#ifndef UV_WIN_REQ_INL_H_ +#define UV_WIN_REQ_INL_H_ + +#include + +#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))) + +/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency + * between src/uv-common.h and src/win/internal.h. + */ +#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 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/3rd/libuv-1.19.2/src/win/req.c b/3rd/libuv-1.19.2/src/win/req.c new file mode 100644 index 00000000..111cc5e2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#include "uv.h" +#include "internal.h" diff --git a/3rd/libuv-1.19.2/src/win/signal.c b/3rd/libuv-1.19.2/src/win/signal.c new file mode 100644 index 00000000..a174da1f --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/signal.c @@ -0,0 +1,277 @@ +/* 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 +#include + +#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 CRITICAL_SECTION uv__signal_lock; + +static BOOL WINAPI uv__signal_control_handler(DWORD type); + +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); + +void uv_signals_init(void) { + InitializeCriticalSection(&uv__signal_lock); + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + abort(); +} + + +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; + + 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 (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) + continue; + + if (!previous) { + POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); + } + + dispatched = 1; + if (handle->flags & UV__SIGNAL_ONE_SHOT) + handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; + } + + 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; + } +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); + handle->pending_signum = 0; + handle->signum = 0; + handle->signal_cb = NULL; + + UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ); + handle->signal_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); + + 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) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { + /* Test for invalid signal values. */ + if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) + 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); + + handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + + 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__SIGNAL_ONE_SHOT) + uv_signal_stop(handle); + + 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/3rd/libuv-1.19.2/src/win/snprintf.c b/3rd/libuv-1.19.2/src/win/snprintf.c new file mode 100644 index 00000000..776c0e39 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/src/win/stream-inl.h b/3rd/libuv-1.19.2/src/win/stream-inl.h new file mode 100644 index 00000000..dba03747 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/stream-inl.h @@ -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. + */ + +#ifndef UV_WIN_STREAM_INL_H_ +#define UV_WIN_STREAM_INL_H_ + +#include + +#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; + handle->stream.conn.shutdown_req = NULL; +} + + +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->read_req, UV_READ); + handle->read_req.event_handle = NULL; + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + handle->read_req.data = handle; +} + + +#endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/stream.c b/3rd/libuv-1.19.2/src/win/stream.c new file mode 100644 index 00000000..13cbfdcb --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/stream.c @@ -0,0 +1,248 @@ +/* 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 + +#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(req, 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/3rd/libuv-1.19.2/src/win/tcp.c b/3rd/libuv-1.19.2/src/win/tcp.c new file mode 100644 index 00000000..fd6efbaf --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/tcp.c @@ -0,0 +1,1525 @@ +/* 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 +#include + +#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->tcp.conn.read_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); + if (handle->tcp.conn.read_buffer.base == NULL || + 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) { + 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(req, 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(req, 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; + struct sockaddr_storage converted; + BOOL success; + DWORD bytes; + int err; + + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return 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(req, 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, + (const struct sockaddr*) &converted, + 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(req, 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) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || 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; + struct sockaddr_storage saddr; + int saddr_len; + + /* 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); + } + + /* Support already active socket. */ + saddr_len = sizeof(saddr); + if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already bound. */ + handle->flags |= UV_HANDLE_BOUND; + saddr_len = sizeof(saddr); + if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already connected. */ + uv_connection_init((uv_stream_t*) handle); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + } + + 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/3rd/libuv-1.19.2/src/win/thread.c b/3rd/libuv-1.19.2/src/win/thread.c new file mode 100644 index 00000000..9eaad77c --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/thread.c @@ -0,0 +1,703 @@ +/* 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 +#include +#include + +#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; + MemoryBarrier(); /* For feature parity with pthread_join(). */ + 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; +} + + +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + return uv_mutex_init(mutex); +} + + +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 here since Win32 manual-reset events */ + /* maintain state when used with . This avoids the "lost wakeup" */ + /* bug. */ + uv_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to being */ + /* called or 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 . */ + 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 . */ + 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/3rd/libuv-1.19.2/src/win/timer.c b/3rd/libuv-1.19.2/src/win/timer.c new file mode 100644 index 00000000..7e006fed --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/timer.c @@ -0,0 +1,195 @@ +/* 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 +#include + +#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); + assert(new_time >= loop->time); + loop->time = new_time; +} + + +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/3rd/libuv-1.19.2/src/win/tty.c b/3rd/libuv-1.19.2/src/win/tty.c new file mode 100644 index 00000000..05a11e88 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/tty.c @@ -0,0 +1,2328 @@ +/* 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 +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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" + +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif + +#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 +#define MAX_CONSOLE_CHAR 8192 + +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); + + +/* Null uv_buf_t */ +static const uv_buf_t uv_null_buf_ = { 0, NULL }; + +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + + +/* + * 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; + +/* The console window size + * We keep this separate from uv_tty_virtual_*. We use those values to only + * handle signalling SIGWINCH + */ + +static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static int uv__tty_console_height = -1; +static int uv__tty_console_width = -1; + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime); + +/* We use a semaphore rather than a mutex or critical section because in some + cases (uv__cancel_read_console) we need take the lock in the main thread and + release it in another thread. Using a semaphore ensures that in such + scenario the main thread will still block when trying to acquire the lock. */ +static uv_sem_t uv_tty_output_lock; + +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; + +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); + +void uv_console_init(void) { + if (uv_sem_init(&uv_tty_output_lock, 1)) + abort(); + uv__tty_console_handle = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle != NULL) { + QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, + NULL, + WT_EXECUTELONGFUNCTION); + } +} + + +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; + + uv__once_init(); + 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. */ + uv_sem_wait(&uv_tty_output_lock); + + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + + /* Remember the original console text attributes. */ + uv_tty_capture_initial_style(&screen_buffer_info); + + uv_tty_update_virtual_window(&screen_buffer_info); + + uv_sem_post(&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; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = 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; + default: + return UV_EINVAL; + } + + /* 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; + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); + } + } else { + was_reading = 0; + } + + uv_sem_wait(&uv_tty_output_lock); + if (!SetConsoleMode(tty->handle, flags)) { + err = uv_translate_sys_error(GetLastError()); + uv_sem_post(&uv_tty_output_lock); + return err; + } + uv_sem_post(&uv_tty_output_lock); + + /* 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()); + } + + uv_sem_wait(&uv_tty_output_lock); + uv_tty_update_virtual_window(&info); + uv_sem_post(&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; + LONG status; + COORD pos; + BOOL read_console_success; + + 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; + + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + read_console_success = ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL); + + if (read_console_success) { + 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()); + } + + status = InterlockedExchange(&uv__read_console_status, COMPLETED); + + if (status == TRAP_REQUESTED) { + /* If we canceled the read by sending a VK_RETURN event, restore the + screen state to undo the visual effect of the VK_RETURN */ + if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer; + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by one + line. The right position to reset the cursor to is therefore one line + higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + uv_sem_post(&uv_tty_output_lock); + } + 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->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); + if (handle->tty.rd.read_line_buffer.base == NULL || + 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); + + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; + 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); + } + + 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--; + + /* Ignore other events that are not key 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) { + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); + if (buf.base == NULL || 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) { + /* 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 { + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* 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); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &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); + /* Make sure no attempt is made to insert it again until it's handled. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + return 0; + } + + uv_tty_queue_read(loop, handle); + + return 0; +} + + +int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ + /* Write some bullshit event to force the console wait to return. */ + memset(&record, 0, sizeof record); + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { + return GetLastError(); + } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + /* Hold the output lock during the cancellation, to ensure that further + writes don't interfere with the screen state. It will be the ReadConsole + thread's responsibility to release the lock. */ + uv_sem_wait(&uv_tty_output_lock); + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + uv_sem_post(&uv_tty_output_lock); + return 0; + } + + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); + } + + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); + + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; +} + + +static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { + 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; + } +} + + +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[MAX_CONSOLE_CHAR]; + WCHAR* utf16_buffer; + DWORD utf16_buf_used = 0; + unsigned int i, len, max_len, pos; + int allocate = 0; + +#define FLUSH_TEXT() \ + do { \ + pos = 0; \ + do { \ + len = utf16_buf_used - pos; \ + if (len > MAX_CONSOLE_CHAR) \ + len = MAX_CONSOLE_CHAR; \ + uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \ + pos += len; \ + } while (pos < utf16_buf_used); \ + if (allocate) { \ + uv__free(utf16_buffer); \ + allocate = 0; \ + utf16_buffer = utf16_buf; \ + } \ + 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; + + utf16_buffer = utf16_buf; + + uv_sem_wait(&uv_tty_output_lock); + + for (i = 0; i < nbufs; i++) { + uv_buf_t buf = bufs[i]; + unsigned int j; + + if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + max_len = (utf16_buf_used + 1) * sizeof(WCHAR); + allocate = max_len > MAX_CONSOLE_CHAR; + if (allocate) + utf16_buffer = uv__malloc(max_len); + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buffer, + utf16_buf_used)) { + if (allocate) + uv__free(utf16_buffer); + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + + continue; + } + + 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; + + uv_sem_post(&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(req, 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 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; +} + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + MSG msg; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return 0; + + uv__tty_console_width = sb_info.dwSize.X; + uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (pSetWinEventHook == NULL) + return 0; + + if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, + EVENT_CONSOLE_LAYOUT, + NULL, + uv__tty_console_resize_event, + 0, + 0, + WINEVENT_OUTOFCONTEXT)) + return 0; + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + int width, height; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return; + + width = sb_info.dwSize.X; + height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (width != uv__tty_console_width || height != uv__tty_console_height) { + uv__tty_console_width = width; + uv__tty_console_height = height; + uv__signal_dispatch(SIGWINCH); + } +} diff --git a/3rd/libuv-1.19.2/src/win/udp.c b/3rd/libuv-1.19.2/src/win/udp.c new file mode 100644 index 00000000..cd1d0e07 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/udp.c @@ -0,0 +1,965 @@ +/* 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 +#include + +#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(&handle->recv_req, 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->recv_buffer = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + if (handle->recv_buffer.base == NULL || 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(req, 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? */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + if (buf.base == NULL || 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 + return UV_EINVAL; + 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) { + DWORD bytes; + const struct sockaddr* bind_addr; + struct sockaddr_storage converted; + int err; + + assert(nbufs > 0); + + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return err; + + /* Already sending a message.*/ + if (handle->send_queue_count != 0) + return UV_EAGAIN; + + 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 + return UV_EINVAL; + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + (const struct sockaddr*) &converted, + addrlen, + NULL, + NULL); + + if (err) + return uv_translate_sys_error(WSAGetLastError()); + + return bytes; +} diff --git a/3rd/libuv-1.19.2/src/win/util.c b/3rd/libuv-1.19.2/src/win/util.c new file mode 100644 index 00000000..3100bc23 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/util.c @@ -0,0 +1,1581 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include + + +/* + * 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 + +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif + +/* + Max hostname length. The Windows gethostname() documentation states that 256 + bytes will always be large enough to hold the null-terminated hostname. +*/ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +/* Maximum environment variable size, including the terminating null */ +#define MAX_ENV_VAR_LENGTH 32767 + +/* 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(void) { + 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_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, + (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; + 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; +} + + +uv_pid_t uv_os_getpid(void) { + return GetCurrentProcessId(); +} + + +uv_pid_t uv_os_getppid(void) { + 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(void) { + 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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 = MultiByteToWideChar(CP_UTF8, 0, title, -1, 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(void) { + WCHAR title_w[MAX_TITLE_LENGTH]; + + if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { + return -1; + } + + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) + return -1; + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + 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); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + 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; + + uv__convert_utf16_to_utf8(cpu_brand, + cpu_brand_size / sizeof(WCHAR), + &(cpu_info->model)); + } + + 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; + PROCESS_MEMORY_COUNTERS memCounters; + IO_COUNTERS ioCounters; + 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()); + } + + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + 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; + + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + + uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + + return 0; +} + + +int uv_os_homedir(char* buffer, size_t* size) { + uv_passwd_t pwd; + 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 { + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; + } + + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); + + if (r != 0) { + return r; + } + + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); + return UV_ENOBUFS; + } + + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); + + return 0; +} + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + 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 (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + uv__free(pwd->username); + uv__free(pwd->homedir); + pwd->username = NULL; + pwd->homedir = NULL; +} + + +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + *utf8 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf8)[bufsize] = '\0'; + return 0; +} + + +/* + * Converts a UTF-8 string into a UTF-16 one. The resulting string is + * null-terminated. + * + * If utf8 is null terminated, utf8len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { + int bufsize; + + if (utf8 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so + * we do it ourselves always, just in case. */ + *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1)); + + if (*utf16 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-16 */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); + + if (bufsize == 0) { + uv__free(*utf16); + *utf16 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf16)[bufsize] = '\0'; + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = ARRAY_SIZE(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = ARRAY_SIZE(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + wchar_t var[MAX_ENV_VAR_LENGTH]; + wchar_t* name_w; + DWORD bufsize; + size_t len; + int r; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); + uv__free(name_w); + assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ + + if (len == 0) { + r = GetLastError(); + + if (r == ERROR_ENVVAR_NOT_FOUND) + return UV_ENOENT; + + return uv_translate_sys_error(r); + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + var, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + wchar_t* name_w; + wchar_t* value_w; + int r; + + if (name == NULL || value == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = uv__convert_utf8_to_utf16(value, -1, &value_w); + + if (r != 0) { + uv__free(name_w); + return r; + } + + r = SetEnvironmentVariableW(name_w, value_w); + uv__free(name_w); + uv__free(value_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + wchar_t* name_w; + int r; + + if (name == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = SetEnvironmentVariableW(name_w, NULL); + uv__free(name_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + +int uv_os_gethostname(char* buffer, size_t* size) { + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + uv__once_init(); /* Initialize winsock */ + + if (gethostname(buf, sizeof(buf)) != 0) + return uv_translate_sys_error(WSAGetLastError()); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} diff --git a/3rd/libuv-1.19.2/src/win/winapi.c b/3rd/libuv-1.19.2/src/win/winapi.c new file mode 100644 index 00000000..4ccdf0a5 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winapi.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 + +#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; + + +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +/* User32.dll function pointer */ +sSetWinEventHook pSetWinEventHook; + + +void uv_winapi_init(void) { + HMODULE ntdll_module; + HMODULE kernel32_module; + HMODULE powrprof_module; + HMODULE user32_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"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + + user32_module = LoadLibraryA("user32.dll"); + if (user32_module != NULL) { + pSetWinEventHook = (sSetWinEventHook) + GetProcAddress(user32_module, "SetWinEventHook"); + } + +} diff --git a/3rd/libuv-1.19.2/src/win/winapi.h b/3rd/libuv-1.19.2/src/win/winapi.h new file mode 100644 index 00000000..cc54b79b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winapi.h @@ -0,0 +1,4778 @@ +/* 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 + + +/* + * 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 + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002 +#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; + }; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + 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_ELEVATION_REQUIRED +# define ERROR_ELEVATION_REQUIRED 740 +#endif + +#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); + +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + +/* from Winuser.h */ +typedef VOID (CALLBACK* WINEVENTPROC) + (HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD idEventThread, + DWORD dwmsEventTime); + +typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) + (UINT eventMin, + UINT eventMax, + HMODULE hmodWinEventProc, + WINEVENTPROC lpfnWinEventProc, + DWORD idProcess, + DWORD idThread, + UINT 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; + + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + +/* User32.dll function pointer */ +extern sSetWinEventHook pSetWinEventHook; + +#endif /* UV_WIN_WINAPI_H_ */ diff --git a/3rd/libuv-1.19.2/src/win/winsock.c b/3rd/libuv-1.19.2/src/win/winsock.c new file mode 100644 index 00000000..84188954 --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winsock.c @@ -0,0 +1,591 @@ +/* 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 +#include + +#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(void) { + 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; + } +} + +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage) { + struct sockaddr_in* dest4; + struct sockaddr_in6* dest6; + + if (addr == NULL) + return UV_EINVAL; + + switch (addr->sa_family) { + case AF_INET: + dest4 = (struct sockaddr_in*) storage; + memcpy(dest4, addr, sizeof(*dest4)); + if (dest4->sin_addr.s_addr == 0) + dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return 0; + case AF_INET6: + dest6 = (struct sockaddr_in6*) storage; + memcpy(dest6, addr, sizeof(*dest6)); + if (memcmp(&dest6->sin6_addr, + &uv_addr_ip6_any_.sin6_addr, + sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) { + struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT; + dest6->sin6_addr = init_sin6_addr; + } + return 0; + default: + return UV_EINVAL; + } +} diff --git a/3rd/libuv-1.19.2/src/win/winsock.h b/3rd/libuv-1.19.2/src/win/winsock.h new file mode 100644 index 00000000..7ecb755b --- /dev/null +++ b/3rd/libuv-1.19.2/src/win/winsock.h @@ -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. + */ + +#ifndef UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include +#include + +#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 + +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage); + +#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/3rd/libuv-1.19.2/test/benchmark-async-pummel.c b/3rd/libuv-1.19.2/test/benchmark-async-pummel.c new file mode 100644 index 00000000..cca3de10 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-async.c b/3rd/libuv-1.19.2/test/benchmark-async.c new file mode 100644 index 00000000..e44165f2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-fs-stat.c b/3rd/libuv-1.19.2/test/benchmark-fs-stat.c new file mode 100644 index 00000000..32d25895 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c b/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c new file mode 100644 index 00000000..1dbc23dd --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/benchmark-list.h b/3rd/libuv-1.19.2/test/benchmark-list.h new file mode 100644 index 00000000..1e843071 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-loop-count.c b/3rd/libuv-1.19.2/test/benchmark-loop-count.c new file mode 100644 index 00000000..970a94c2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-million-async.c b/3rd/libuv-1.19.2/test/benchmark-million-async.c new file mode 100644 index 00000000..5395ed54 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-million-timers.c b/3rd/libuv-1.19.2/test/benchmark-million-timers.c new file mode 100644 index 00000000..60a308be --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-multi-accept.c b/3rd/libuv-1.19.2/test/benchmark-multi-accept.c new file mode 100644 index 00000000..2f32c0ca --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c b/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c new file mode 100644 index 00000000..646a7df9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +/* 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/3rd/libuv-1.19.2/test/benchmark-pound.c b/3rd/libuv-1.19.2/test/benchmark-pound.c new file mode 100644 index 00000000..79f36345 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-pump.c b/3rd/libuv-1.19.2/test/benchmark-pump.c new file mode 100644 index 00000000..8685258e --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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(void); + +static uv_req_t* req_alloc(void); +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/3rd/libuv-1.19.2/test/benchmark-sizes.c b/3rd/libuv-1.19.2/test/benchmark-sizes.c new file mode 100644 index 00000000..9bf42f91 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-spawn.c b/3rd/libuv-1.19.2/test/benchmark-spawn.c new file mode 100644 index 00000000..ed9ad608 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c b/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c new file mode 100644 index 00000000..96921b70 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-thread.c b/3rd/libuv-1.19.2/test/benchmark-thread.c new file mode 100644 index 00000000..b37a7fd6 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c b/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c new file mode 100644 index 00000000..68a2373d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/blackhole-server.c b/3rd/libuv-1.19.2/test/blackhole-server.c new file mode 100644 index 00000000..ad878b35 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/dns-server.c b/3rd/libuv-1.19.2/test/dns-server.c new file mode 100644 index 00000000..80052c70 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/echo-server.c b/3rd/libuv-1.19.2/test/echo-server.c new file mode 100644 index 00000000..bfed6767 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/fixtures/empty_file b/3rd/libuv-1.19.2/test/fixtures/empty_file new file mode 100644 index 00000000..e69de29b diff --git a/3rd/libuv-1.19.2/test/fixtures/load_error.node b/3rd/libuv-1.19.2/test/fixtures/load_error.node new file mode 100644 index 00000000..323fae03 --- /dev/null +++ b/3rd/libuv-1.19.2/test/fixtures/load_error.node @@ -0,0 +1 @@ +foobar diff --git a/3rd/libuv-1.19.2/test/run-benchmarks.c b/3rd/libuv-1.19.2/test/run-benchmarks.c new file mode 100644 index 00000000..6e42623d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +#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/3rd/libuv-1.19.2/test/run-tests.c b/3rd/libuv-1.19.2/test/run-tests.c new file mode 100644 index 00000000..da4ac82e --- /dev/null +++ b/3rd/libuv-1.19.2/test/run-tests.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 +#include +#include + +#ifdef _WIN32 +# include +#else +# include +#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_helper_closed_handle(void); +int ipc_send_recv_helper(void); +int ipc_helper_bind_twice(void); +int stdio_over_pipes_helper(void); +int spawn_stdin_stdout(void); +int spawn_tcp_server_helper(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]); + case 4: return maybe_run_test(argc, argv); + 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_closed_handle") == 0) { + return ipc_helper_closed_handle(); + } + + 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_tcp_server_helper") == 0) { + return spawn_tcp_server_helper(); + } + + 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(); + } + +#ifndef _WIN32 + if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) { + uv_uid_t uid = atoi(argv[2]); + uv_gid_t gid = atoi(argv[3]); + + ASSERT(uid == getuid()); + ASSERT(gid == getgid()); + + return 1; + } +#endif /* !_WIN32 */ + + return run_test(argv[1], 0, 1); +} diff --git a/3rd/libuv-1.19.2/test/runner-unix.c b/3rd/libuv-1.19.2/test/runner-unix.c new file mode 100644 index 00000000..3167ed44 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* uintptr_t */ + +#include +#include /* readlink, usleep */ +#include /* strdup */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* Do platform-specific initialization. */ +int platform_init(int argc, char **argv) { + /* 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; + int stdout_fd; + const char* arg; + char* args[16]; + int n; + pid_t pid; + + stdout_file = tmpfile(); + stdout_fd = fileno(stdout_file); + 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(stdout_fd, STDOUT_FILENO); + dup2(stdout_fd, 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 defined(__MVS__) + if (pthread_attr_setstacksize(&attr, 1024 * 1024)) +#else + if (pthread_attr_setstacksize(&attr, 256 * 1024)) +#endif + 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, FILE* stream) { + 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) + print_lines(buf, strlen(buf), stream); + + 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) { +#if defined(__MVS__) + fprintf(stderr, "\047[2K\r"); +#else + fprintf(stderr, "\033[2K\r"); +#endif +} + + +/* Pause the calling thread for a number of milliseconds. */ +void uv_sleep(int msec) { + int sec; + int usec; + + sec = msec / 1000; + usec = (msec % 1000) * 1000; + if (sec > 0) + sleep(sec); + if (usec > 0) + usleep(usec); +} diff --git a/3rd/libuv-1.19.2/test/runner-unix.h b/3rd/libuv-1.19.2/test/runner-unix.h new file mode 100644 index 00000000..e21847f9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* 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/3rd/libuv-1.19.2/test/runner-win.c b/3rd/libuv-1.19.2/test/runner-win.c new file mode 100644 index 00000000..d86fda3c --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner-win.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 +#include +#include +#include +#include +#if !defined(__MINGW32__) +# include +#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) { + /* 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, FILE* stream) { + char buf[1024]; + int fd, r; + FILE* f; + + fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); + if (fd == -1) + return -1; + f = _fdopen(fd, "rt"); + if (f == NULL) { + _close(fd); + return -1; + } + + r = fseek(f, 0, SEEK_SET); + if (r < 0) + return -1; + + while (fgets(buf, sizeof(buf), f) != NULL) + print_lines(buf, strlen(buf), stream); + + if (ferror(f)) + return -1; + + fclose(f); + 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); +} + + +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/3rd/libuv-1.19.2/test/runner-win.h b/3rd/libuv-1.19.2/test/runner-win.h new file mode 100644 index 00000000..8cc4c16e --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/runner.c b/3rd/libuv-1.19.2/test/runner.c new file mode 100644 index 00000000..f017902a --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner.c @@ -0,0 +1,434 @@ +/* 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 +#include + +#include "runner.h" +#include "task.h" +#include "uv.h" + +char executable_path[sizeof(executable_path)]; + + +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); +} + + +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 ""; + + 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 actual; + int total; + int passed; + int failed; + int skipped; + int current; + int test_result; + int skip; + task_entry_t* task; + + /* Count the number of tests. */ + actual = 0; + total = 0; + for (task = TASKS; task->main; task++, actual++) { + if (!task->is_helper) { + total++; + } + } + + /* Keep platform_output first. */ + skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output")); + qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task); + + fprintf(stderr, "1..%d\n", total); + fflush(stderr); + + /* Run all tests. */ + passed = 0; + failed = 0; + skipped = 0; + current = 1; + for (task = TASKS; task->main; task++) { + if (task->is_helper) { + continue; + } + + test_result = run_test(task->task_name, benchmark_output, current); + switch (test_result) { + case TEST_OK: passed++; break; + case TEST_SKIP: skipped++; break; + default: failed++; + } + current++; + } + + 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]; + int reason_length; + + switch (status) { + case TEST_OK: + result = "ok"; + directive = ""; + break; + case TEST_SKIP: + result = "ok"; + directive = " # SKIP "; + break; + default: + result = "not ok"; + directive = ""; + } + + if (status == TEST_SKIP && process_output_size(process) > 0) { + process_read_last_line(process, reason, sizeof reason); + reason_length = strlen(reason); + if (reason_length > 0 && reason[reason_length - 1] == '\n') + reason[reason_length - 1] = '\0'; + } 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] = ""; + 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"); + } + + log_tap_result(test_count, test, status, &processes[i]); + + /* Show error and output from processes if the test failed. */ + if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { + if (strlen(errmsg) > 0) + fprintf(stderr, "# %s\n", errmsg); + fprintf(stderr, "# "); + 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], stderr); + break; + } + } + + /* 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], 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 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); + } + } +} + + +void print_lines(const char* buffer, size_t size, FILE* stream) { + const char* start; + const char* end; + + start = buffer; + while ((end = memchr(start, '\n', &buffer[size] - start))) { + fprintf(stream, "# %.*s\n", (int) (end - start), start); + fflush(stream); + start = end + 1; + } + + if (start < &buffer[size]) { + fprintf(stream, "# %s\n", start); + fflush(stream); + } +} diff --git a/3rd/libuv-1.19.2/test/runner.h b/3rd/libuv-1.19.2/test/runner.h new file mode 100644 index 00000000..555f2f8e --- /dev/null +++ b/3rd/libuv-1.19.2/test/runner.h @@ -0,0 +1,177 @@ +/* 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 /* PATH_MAX */ +#include /* 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); + +/* Print lines in |buffer| as TAP diagnostics to |stream|. */ +void print_lines(const char* buffer, size_t size, FILE* stream); + +/* + * Stuff that should be implemented by test-runner-.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 `stream`. */ +int process_copy_output(process_info_t* p, FILE* stream); + +/* 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); + +#endif /* RUNNER_H_ */ diff --git a/3rd/libuv-1.19.2/test/task.h b/3rd/libuv-1.19.2/test/task.h new file mode 100644 index 00000000..af99d92f --- /dev/null +++ b/3rd/libuv-1.19.2/test/task.h @@ -0,0 +1,232 @@ +/* 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 +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#endif + +#if !defined(_WIN32) +# include +# include /* 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 +# 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()); \ + ASSERT(0 == uv_loop_close(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_SKIP +}; + +#define RETURN_OK() \ + do { \ + return TEST_OK; \ + } 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 0; /* Assume no 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; +} + +#if defined(__CYGWIN__) || defined(__MSYS__) +# define NO_FS_EVENTS "Filesystem watching not supported on this platform." +#endif + +#if defined(__MSYS__) +# define NO_SEND_HANDLE_ON_PIPE \ + "MSYS2 runtime does not support sending handles on pipes." +#elif defined(__CYGWIN__) +# define NO_SEND_HANDLE_ON_PIPE \ + "Cygwin runtime does not support sending handles on pipes." +#endif + +#if defined(__MSYS__) +# define NO_SELF_CONNECT \ + "MSYS2 runtime hangs on listen+connect in same process." +#elif defined(__CYGWIN__) +# define NO_SELF_CONNECT \ + "Cygwin runtime hangs on listen+connect in same process." +#endif + +#endif /* TASK_H_ */ diff --git a/3rd/libuv-1.19.2/test/test-active.c b/3rd/libuv-1.19.2/test/test-active.c new file mode 100644 index 00000000..b17bd176 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-async-null-cb.c b/3rd/libuv-1.19.2/test/test-async-null-cb.c new file mode 100644 index 00000000..52652d91 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-async-null-cb.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 + +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) { + /* + * Fill async_handle with garbage values. + * uv_async_init() should properly initialize struct fields regardless of + * initial values. + * This is added to verify paddings between fields do not affect behavior. + */ + memset(&async_handle, 0xff, sizeof(async_handle)); + + 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/3rd/libuv-1.19.2/test/test-async.c b/3rd/libuv-1.19.2/test/test-async.c new file mode 100644 index 00000000..6f5351bf --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-barrier.c b/3rd/libuv-1.19.2/test/test-barrier.c new file mode 100644 index 00000000..dfd2dbde --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-callback-order.c b/3rd/libuv-1.19.2/test/test-callback-order.c new file mode 100644 index 00000000..8bc2c4f7 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-callback-stack.c b/3rd/libuv-1.19.2/test/test-callback-stack.c new file mode 100644 index 00000000..8855c084 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-close-fd.c b/3rd/libuv-1.19.2/test/test-close-fd.c new file mode 100644 index 00000000..93a7bd7c --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-close-order.c b/3rd/libuv-1.19.2/test/test-close-order.c new file mode 100644 index 00000000..2b24f6d6 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-condvar.c b/3rd/libuv-1.19.2/test/test-condvar.c new file mode 100644 index 00000000..d956efef --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-condvar.c @@ -0,0 +1,245 @@ +/* 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 +#include + +typedef struct worker_config { + uv_mutex_t mutex; + uv_cond_t cond; + int signal_delay; + int wait_delay; + int use_broadcast; + volatile int posted_1; + volatile int posted_2; + void (*signal_cond)(struct worker_config* c, volatile int* flag); + int (*wait_cond)(struct worker_config* c, const volatile int* flag); +} worker_config; + + +static void worker(void* arg) { + worker_config* c = arg; + c->signal_cond(c, &c->posted_1); + c->wait_cond(c, &c->posted_2); +} + +static void noop_worker(void* arg) { + return; +} + +static void condvar_signal(worker_config* c, volatile int* flag) { + if (c->signal_delay) + uv_sleep(c->signal_delay); + + uv_mutex_lock(&c->mutex); + ASSERT(*flag == 0); + *flag = 1; + if (c->use_broadcast) + uv_cond_broadcast(&c->cond); + else + uv_cond_signal(&c->cond); + uv_mutex_unlock(&c->mutex); +} + + +static int condvar_wait(worker_config* c, const volatile int* flag) { + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + uv_cond_wait(&c->cond, &c->mutex); + } + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); + + return 0; +} + + +TEST_IMPL(condvar_1) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.wait_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + 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.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + + +static int condvar_timedwait(worker_config* c, const volatile int* flag) { + int r; + + r = 0; + + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0 || r == UV_ETIMEDOUT); + if (r == UV_ETIMEDOUT) + break; + } + uv_mutex_unlock(&c->mutex); + + return r; +} + +/* Test that uv_cond_timedwait will return early when cond is signaled. */ +TEST_IMPL(condvar_3) { + uv_thread_t thread; + worker_config wc; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + wc.signal_cond(&wc, &wc.posted_2); + + 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; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); + + 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; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} + +/* Test that uv_cond_timedwait will time out when cond is not signaled. */ +TEST_IMPL(condvar_6) { + uv_thread_t thread; + worker_config wc; + int r; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, noop_worker, &wc)); + + /* This can only return having timed out, because otherwise we + * loop forever in condvar_timedwait. */ + r = wc.wait_cond(&wc, &wc.posted_1); + ASSERT(r == UV_ETIMEDOUT); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-connect-unspecified.c b/3rd/libuv-1.19.2/test/test-connect-unspecified.c new file mode 100644 index 00000000..04e1c8a5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-connect-unspecified.c @@ -0,0 +1,61 @@ +/* Copyright 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. +*/ + +#include "uv.h" +#include "task.h" + +static void connect_4(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +static void connect_6(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +TEST_IMPL(connect_unspecified) { + uv_loop_t* loop; + uv_tcp_t socket4; + struct sockaddr_in addr4; + uv_connect_t connect4; + uv_tcp_t socket6; + struct sockaddr_in6 addr6; + uv_connect_t connect6; + + loop = uv_default_loop(); + + ASSERT(uv_tcp_init(loop, &socket4) == 0); + ASSERT(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4) == 0); + ASSERT(uv_tcp_connect(&connect4, + &socket4, + (const struct sockaddr*) &addr4, + connect_4) == 0); + + ASSERT(uv_tcp_init(loop, &socket6) == 0); + ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); + ASSERT(uv_tcp_connect(&connect6, + &socket6, + (const struct sockaddr*) &addr6, + connect_6) == 0); + + ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-connection-fail.c b/3rd/libuv-1.19.2/test/test-connection-fail.c new file mode 100644 index 00000000..328bff46 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c b/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c new file mode 100644 index 00000000..1e95043c --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/test-default-loop-close.c b/3rd/libuv-1.19.2/test/test-default-loop-close.c new file mode 100644 index 00000000..fd11cfa8 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-delayed-accept.c b/3rd/libuv-1.19.2/test/test-delayed-accept.c new file mode 100644 index 00000000..4a799890 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-dlerror.c b/3rd/libuv-1.19.2/test/test-dlerror.c new file mode 100644 index 00000000..8f7697b5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-dlerror.c @@ -0,0 +1,57 @@ +/* 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 + + +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, path) != 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, path) != NULL); + ASSERT(strstr(msg, dlerror_no_error) == NULL); + + uv_dlclose(&lib); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-eintr-handling.c b/3rd/libuv-1.19.2/test/test-eintr-handling.c new file mode 100644 index 00000000..1aaf623b --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-eintr-handling.c @@ -0,0 +1,94 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 + +TEST_IMPL(eintr_handling) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + iov = uv_buf_init(buf, sizeof(buf)); + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); + + ASSERT(nread == sizeof(test_buf)); + ASSERT(0 == strcmp(buf, test_buf)); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-embed.c b/3rd/libuv-1.19.2/test/test-embed.c new file mode 100644 index 00000000..c6ddceb1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-embed.c @@ -0,0 +1,139 @@ +/* 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 +#include +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + 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 +# include +# include +#endif + +#if defined(HAVE_EPOLL) +# include +#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/3rd/libuv-1.19.2/test/test-emfile.c b/3rd/libuv-1.19.2/test/test-emfile.c new file mode 100644 index 00000000..8e44ac5c --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-emfile.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. + */ + +#if !defined(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +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) { +#if defined(_AIX) || defined(__MVS__) + /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket + * which causes uv__emfile_trick to not work as intended and this test + * to fail. + */ + RETURN_SKIP("uv__emfile_trick does not work on this OS"); +#endif + 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/3rd/libuv-1.19.2/test/test-env-vars.c b/3rd/libuv-1.19.2/test/test-env-vars.c new file mode 100644 index 00000000..641050e6 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-env-vars.c @@ -0,0 +1,90 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define BUF_SIZE 10 + +TEST_IMPL(env_vars) { + const char* name = "UV_TEST_FOO"; + char buf[BUF_SIZE]; + size_t size; + int r; + + /* Reject invalid inputs when setting an environment variable */ + r = uv_os_setenv(NULL, "foo"); + ASSERT(r == UV_EINVAL); + r = uv_os_setenv(name, NULL); + ASSERT(r == UV_EINVAL); + r = uv_os_setenv(NULL, NULL); + ASSERT(r == UV_EINVAL); + + /* Reject invalid inputs when retrieving an environment variable */ + size = BUF_SIZE; + r = uv_os_getenv(NULL, buf, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_getenv(name, NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_getenv(name, buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_EINVAL); + + /* Reject invalid inputs when deleting an environment variable */ + r = uv_os_unsetenv(NULL); + ASSERT(r == UV_EINVAL); + + /* Successfully set an environment variable */ + r = uv_os_setenv(name, "123456789"); + ASSERT(r == 0); + + /* Successfully read an environment variable */ + size = BUF_SIZE; + buf[0] = '\0'; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == 0); + ASSERT(strcmp(buf, "123456789") == 0); + ASSERT(size == BUF_SIZE - 1); + + /* Return UV_ENOBUFS if the buffer cannot hold the environment variable */ + size = BUF_SIZE - 1; + buf[0] = '\0'; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_ENOBUFS); + ASSERT(size == BUF_SIZE); + + /* Successfully delete an environment variable */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + /* Return UV_ENOENT retrieving an environment variable that does not exist */ + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_ENOENT); + + /* Successfully delete an environment variable that does not exist */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-error.c b/3rd/libuv-1.19.2/test/test-error.c new file mode 100644 index 00000000..a2d559a4 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-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" +#if defined(_WIN32) +# include "../src/win/winapi.h" +#endif + +#include +#include +#include + + +/* + * 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; +} + + +TEST_IMPL(sys_error) { +#if defined(_WIN32) + ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); + ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); + ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); +#else + ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM); + ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE); + ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL); +#endif + ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL); + ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE); + ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES); + ASSERT(uv_translate_sys_error(0) == 0); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fail-always.c b/3rd/libuv-1.19.2/test/test-fail-always.c new file mode 100644 index 00000000..0008459e --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-fork.c b/3rd/libuv-1.19.2/test/test-fork.c new file mode 100644 index 00000000..39b59c8f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fork.c @@ -0,0 +1,681 @@ +/* Copyright 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. + */ + +/* These tests are Unix only. */ +#ifndef _WIN32 + +#include +#include +#include +#include + +#include "uv.h" +#include "task.h" + +static int timer_cb_called; +static int socket_cb_called; + +static void timer_cb(uv_timer_t* timer) { + timer_cb_called++; + uv_close((uv_handle_t*) timer, NULL); +} + + +static int socket_cb_read_fd; +static int socket_cb_read_size; +static char socket_cb_read_buf[1024]; + + +static void socket_cb(uv_poll_t* poll, int status, int events) { + ssize_t cnt; + socket_cb_called++; + ASSERT(0 == status); + printf("Socket cb got events %d\n", events); + ASSERT(UV_READABLE == (events & UV_READABLE)); + if (socket_cb_read_fd) { + cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size); + ASSERT(cnt == socket_cb_read_size); + } + uv_close((uv_handle_t*) poll, NULL); +} + + +static void run_timer_loop_once(void) { + uv_loop_t* loop; + uv_timer_t timer_handle; + + loop = uv_default_loop(); + + timer_cb_called = 0; /* Reset for the child. */ + + 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); +} + + +static void assert_wait_child(pid_t child_pid) { + pid_t waited_pid; + int child_stat; + + waited_pid = waitpid(child_pid, &child_stat, 0); + printf("Waited pid is %d with status %d\n", waited_pid, child_stat); + if (waited_pid == -1) { + perror("Failed to wait"); + } + ASSERT(child_pid == waited_pid); + ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ + ASSERT(!WIFSIGNALED(child_stat)); + ASSERT(0 == WEXITSTATUS(child_stat)); +} + + +TEST_IMPL(fork_timer) { + /* Timers continue to work after we fork. */ + + /* + * Establish the loop before we fork to make sure that it + * has state to get reset after the fork. + */ + pid_t child_pid; + + run_timer_loop_once(); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + run_timer_loop_once(); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair) { + /* A socket opened in the parent and accept'd in the + child works after a fork. */ + pid_t child_pid; + int socket_fds[2]; + uv_poll_t poll_handle; + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + + /* Create the server watcher in the parent, use it in the child. */ + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(0 == socket_cb_called); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + printf("Going to run the loop in the child\n"); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == socket_cb_called); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair_started) { + /* A socket opened in the parent and accept'd in the + child works after a fork, even if the watcher was already + started, and then stopped in the parent. */ + pid_t child_pid; + int socket_fds[2]; + int sync_pipe[2]; + char sync_buf[1]; + uv_poll_t poll_handle; + + ASSERT(0 == pipe(sync_pipe)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + + /* Create and start the server watcher in the parent, use it in the child. */ + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + + /* Run the loop AFTER the poll watcher is registered to make sure it + gets passed to the kernel. Use NOWAIT and expect a non-zero + return to prove the poll watcher is active. + */ + ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(0 == uv_poll_stop(&poll_handle)); + uv_close((uv_handle_t*)&poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == socket_cb_called); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */ + ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == socket_cb_called); + + assert_wait_child(child_pid); + } else { + /* child */ + printf("Child is %d\n", getpid()); + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(0 == socket_cb_called); + + printf("Going to run the loop in the child\n"); + socket_cb_read_fd = socket_fds[0]; + socket_cb_read_size = 3; + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == socket_cb_called); + printf("Buf %s\n", socket_cb_read_buf); + ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static int fork_signal_cb_called; + +void fork_signal_to_child_cb(uv_signal_t* handle, int signum) +{ + fork_signal_cb_called = signum; + uv_close((uv_handle_t*)handle, NULL); +} + + +TEST_IMPL(fork_signal_to_child) { + /* A signal handler installed before forking + is run only in the child when the child is signalled. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == pipe(sync_pipe)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + ASSERT(0 == kill(child_pid, SIGUSR1)); + /* Run the loop, make sure we don't get the signal. */ + printf("Running loop in parent\n"); + uv_unref((uv_handle_t*)&signal_handle); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT(0 == fork_signal_cb_called); + printf("Waiting for child in parent\n"); + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + /* Get the signal. */ + ASSERT(0 != uv_loop_alive(uv_default_loop())); + printf("Running loop in child\n"); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT(SIGUSR1 == fork_signal_cb_called); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_signal_to_child_closed) { + /* A signal handler installed before forking + doesn't get received anywhere when the child is signalled, + but isnt running the loop. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + int sync_pipe2[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == pipe(sync_pipe)); + ASSERT(0 == pipe(sync_pipe2)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + printf("Wating on child in parent\n"); + ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + printf("Parent killing child\n"); + ASSERT(0 == kill(child_pid, SIGUSR1)); + /* Run the loop, make sure we don't get the signal. */ + printf("Running loop in parent\n"); + uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit; + we *shouldn't* get any signals */ + run_timer_loop_once(); /* but while we share a pipe, we do, so + have something active. */ + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + printf("Signal in parent %d\n", fork_signal_cb_called); + ASSERT(0 == fork_signal_cb_called); + ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */ + printf("Waiting for child in parent\n"); + assert_wait_child(child_pid); + } else { + /* child */ + /* Our signal handler should still be installed. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + printf("Checking loop in child\n"); + ASSERT(0 != uv_loop_alive(uv_default_loop())); + printf("Alerting parent in child\n"); + ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + /* Don't run the loop. Wait for the parent to call us */ + printf("Waiting on parent in child\n"); + /* Wait for parent. read may fail if the parent tripped an ASSERT + and exited, so this isn't in an ASSERT. + */ + read(sync_pipe2[0], sync_buf, 1); + ASSERT(0 == fork_signal_cb_called); + printf("Exiting child \n"); + /* Note that we're deliberately not running the loop + * in the child, and also not closing the loop's handles, + * so the child default loop can't be cleanly closed. + * We need to explicitly exit to avoid an automatic failure + * in that case. + */ + exit(0); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +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 int timer_cb_touch_called; + +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 int fs_event_cb_called; + +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(status == 0); +#if defined(__APPLE__) || defined(__linux__) + ASSERT(strcmp(filename, "watch_file") == 0); +#else + ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); +#endif + uv_close((uv_handle_t*)handle, NULL); +} + + +static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) { + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + + /* Setup */ + remove("watch_file"); + create_file("watch_file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + /* watching a dir is the only way to get fsevents involved on apple + platforms */ + r = uv_fs_event_start(&fs_event, + fs_event_cb_file_current_dir, + file_or_dir == 1 ? "." : "watch_file", + 0); + ASSERT(r == 0); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */ +} + + +#define FS_TEST_FILE 0 +#define FS_TEST_DIR 1 + +static int _do_fork_fs_events_child(int file_or_dir) { + /* basic fsevents work in the child after a fork */ + pid_t child_pid; + uv_loop_t loop; + + /* Watch in the parent, prime the loop and/or threads. */ + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + /* Ee can watch in a new loop, but dirs only work + if we're on linux. */ +#if defined(__APPLE__) + file_or_dir = FS_TEST_FILE; +#endif + printf("Running child\n"); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_watch_file_current_dir(&loop, file_or_dir); + ASSERT(0 == uv_loop_close(&loop)); + printf("Child second watch default loop\n"); + /* Ee can watch in the default loop. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + /* On some platforms (OS X), if we don't update the time now, + * the timer cb fires before the event loop enters uv__io_poll, + * instead of after, meaning we don't see the change! This may be + * a general race. + */ + uv_update_time(uv_default_loop()); + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + + /* We can close the parent loop successfully too. This is + especially important on Apple platforms where if we're not + careful trying to touch the CFRunLoop, even just to shut it + down, that we allocated in the FS_TEST_DIR case would crash. */ + ASSERT(0 == uv_loop_close(uv_default_loop())); + + printf("Exiting child \n"); + } + + MAKE_VALGRIND_HAPPY(); + return 0; + +} + + +TEST_IMPL(fork_fs_events_child) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + return _do_fork_fs_events_child(FS_TEST_FILE); +} + + +TEST_IMPL(fork_fs_events_child_dir) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__APPLE__) || defined (__linux__) + return _do_fork_fs_events_child(FS_TEST_DIR); +#else + /* You can't spin up a cfrunloop thread on an apple platform + and then fork. See + http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale + */ + return 0; +#endif +} + + +TEST_IMPL(fork_fs_events_file_parent_child) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__sun) || defined(_AIX) || defined(__MVS__) + /* It's not possible to implement this without additional + * bookkeeping on SunOS. For AIX it is possible, but has to be + * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 + * TODO: On z/OS, we need to open another message queue and subscribe to the + * same events as the parent. + */ + return 0; +#else + /* Establishing a started fs events watcher in the parent should + still work in the child. */ + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + pid_t child_pid; + uv_loop_t* loop; + + 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); + + child_pid = fork(); + ASSERT(child_pid != -1); + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + printf("Running child\n"); + ASSERT(0 == uv_loop_fork(loop)); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + printf("Running loop in child \n"); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */ + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + + +static int work_cb_count; +static int after_work_cb_count; + + +static void work_cb(uv_work_t* req) { + work_cb_count++; +} + + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT(status == 0); + after_work_cb_count++; +} + + +static void assert_run_work(uv_loop_t* const loop) { + uv_work_t work_req; + int r; + + ASSERT(work_cb_count == 0); + ASSERT(after_work_cb_count == 0); + printf("Queue in %d\n", getpid()); + r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); + ASSERT(r == 0); + printf("Running in %d\n", getpid()); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(work_cb_count == 1); + ASSERT(after_work_cb_count == 1); + + /* cleanup */ + work_cb_count = 0; + after_work_cb_count = 0; +} + + +#ifndef __MVS__ +TEST_IMPL(fork_threadpool_queue_work_simple) { + /* The threadpool works in a child process. */ + + pid_t child_pid; + uv_loop_t loop; + + /* Prime the pool and default loop. */ + assert_run_work(uv_default_loop()); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + /* We can still run work. */ + assert_run_work(uv_default_loop()); + assert_wait_child(child_pid); + } else { + /* child */ + /* We can work in a new loop. */ + printf("Running child in %d\n", getpid()); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_run_work(&loop); + uv_loop_close(&loop); + printf("Child second watch default loop\n"); + /* We can work in the default loop. */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + assert_run_work(uv_default_loop()); + printf("Exiting child \n"); + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* !__MVS__ */ + + +#endif /* !_WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-fs-copyfile.c b/3rd/libuv-1.19.2/test/test-fs-copyfile.c new file mode 100644 index 00000000..4b1fdc5e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-copyfile.c @@ -0,0 +1,173 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" + +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#include /* unlink, etc. */ +#else +# include +# include +# define unlink _unlink +#endif + +static const char fixture[] = "test/fixtures/load_error.node"; +static const char dst[] = "test_file_dst"; +static int result_check_count; + + +static void fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} + +static void handle_result(uv_fs_t* req) { + uv_fs_t stat_req; + uint64_t size; + uint64_t mode; + int r; + + ASSERT(req->fs_type == UV_FS_COPYFILE); + ASSERT(req->result == 0); + + /* Verify that the file size and mode are the same. */ + r = uv_fs_stat(NULL, &stat_req, req->path, NULL); + ASSERT(r == 0); + size = stat_req.statbuf.st_size; + mode = stat_req.statbuf.st_mode; + uv_fs_req_cleanup(&stat_req); + r = uv_fs_stat(NULL, &stat_req, dst, NULL); + ASSERT(r == 0); + ASSERT(stat_req.statbuf.st_size == size); + ASSERT(stat_req.statbuf.st_mode == mode); + uv_fs_req_cleanup(&stat_req); + uv_fs_req_cleanup(req); + result_check_count++; +} + + +static void touch_file(const char* name, unsigned int size) { + uv_file file; + uv_fs_t req; + uv_buf_t buf; + int r; + unsigned int i; + + r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, + S_IWUSR | S_IRUSR, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r >= 0); + file = r; + + buf = uv_buf_init("a", 1); + + /* Inefficient but simple. */ + for (i = 0; i < size; i++) { + r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r >= 0); + } + + r = uv_fs_close(NULL, &req, file, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r == 0); +} + + +TEST_IMPL(fs_copyfile) { + const char src[] = "test_file_src"; + uv_loop_t* loop; + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + /* Fails with EINVAL if bad flags are passed. */ + r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&req); + + /* Fails with ENOENT if source does not exist. */ + unlink(src); + unlink(dst); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(req.result == UV_ENOENT); + ASSERT(r == UV_ENOENT); + uv_fs_req_cleanup(&req); + /* The destination should not exist. */ + r = uv_fs_stat(NULL, &req, dst, NULL); + ASSERT(r != 0); + uv_fs_req_cleanup(&req); + + /* Copies file synchronously. Creates new file. */ + unlink(dst); + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies a file of size zero. */ + unlink(dst); + touch_file(src, 0); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies file synchronously. Overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Fails to overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); + ASSERT(r == UV_EEXIST); + uv_fs_req_cleanup(&req); + + /* Truncates when an existing destination is larger than the source file. */ + touch_file(src, 1); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies a larger file. */ + unlink(dst); + touch_file(src, 4096 * 2); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + unlink(src); + + /* Copies file asynchronously */ + unlink(dst); + r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); + ASSERT(r == 0); + ASSERT(result_check_count == 5); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 6); + + /* If the flags are invalid, the loop should not be kept open */ + unlink(dst); + r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + unlink(dst); /* Cleanup */ + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fs-event.c b/3rd/libuv-1.19.2/test/test-fs-event.c new file mode 100644 index 00000000..39d73300 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-event.c @@ -0,0 +1,1051 @@ +/* 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 +#include + +#ifndef HAVE_KQUEUE +# if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# define HAVE_KQUEUE 1 +# endif +#endif + +#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */ +# define CREATE_TIMEOUT 100 +#else +# define CREATE_TIMEOUT 1 +#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 int timer_cb_exact_called; + +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 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, + CREATE_TIMEOUT, + 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 || events == 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) { +#ifdef _WIN32 + /* Each file created (or deleted) will cause this callback to be called twice + * under Windows: once with the name of the file, and second time with the + * name of the directory. We will ignore the callback for the directory + * itself. */ + if (filename && strcmp(filename, file_prefix_in_subdir) == 0) + return; +#endif + fs_event_cb_called++; + ASSERT(handle == &fs_event); + ASSERT(status == 0); + ASSERT(events == UV_CHANGE || events == 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_exact(uv_timer_t* handle) { + int r; + + if (timer_cb_exact_called == 0) { + touch_file("watch_dir/file.js"); + } else { + uv_close((uv_handle_t*)handle, NULL); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, NULL); + } + + ++timer_cb_exact_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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); +#endif + + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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_exact_path) { + /* + This test watches a file named "file.jsx" and modifies a file named + "file.js". The test verifies that no events occur for file.jsx. + */ + +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + create_dir("watch_dir"); + create_file("watch_dir/file.js"); + create_file("watch_dir/file.jsx"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_exact, 100, 100); + ASSERT(r == 0); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_cb_exact_called == 2); + + /* Cleanup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_watch_file_twice) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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, 100, 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; +} + +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_file_root_dir) { + uv_loop_t* loop; + int r; + + const char* sys_drive = getenv("SystemDrive"); + char path[] = "\\\\?\\X:\\bootsect.bak"; + + ASSERT(sys_drive != NULL); + strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fail_cb, path, 0); + if (r == UV_ENOENT) + RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &fs_event, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + +TEST_IMPL(fs_event_no_callback_after_close) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + 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 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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; +} + +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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); +#endif + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + fs_event_unlink_files(NULL); + 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_close, "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); + + uv_close((uv_handle_t*)&timer, close_cb); + + uv_run(loop, UV_RUN_ONCE); + + ASSERT(close_cb_called == 2); + ASSERT(fs_event_cb_called == 3); + + /* Clean up */ + fs_event_unlink_files(NULL); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_event_start_and_close) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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(buf[len] == '\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__) */ + +TEST_IMPL(fs_event_watch_invalid_path) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0); + ASSERT(r != 0); + ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-fs-poll.c b/3rd/libuv-1.19.2/test/test-fs-poll.c new file mode 100644 index 00000000..737d50df --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs-poll.c @@ -0,0 +1,187 @@ +/* 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 + +#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(buf[len] == '\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/3rd/libuv-1.19.2/test/test-fs.c b/3rd/libuv-1.19.2/test/test-fs.c new file mode 100644 index 00000000..3318b866 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-fs.c @@ -0,0 +1,3174 @@ +/* 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 +#include /* memset */ +#include +#include + +/* FIXME we shouldn't need to branch in this file */ +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#include /* unlink, rmdir, etc. */ +#else +# include +# include +# include +# ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +# endif +# 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; + +#ifdef _WIN32 +/* + * This tag and guid have no special meaning, and don't conflict with + * reserved ids. +*/ +static unsigned REPARSE_TAG = 0x9913; +static GUID REPARSE_GUID = { + 0x1bf6205f, 0x46ae, 0x4527, + 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }; +#endif + +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; +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) + /* + * 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); +#if defined(_WIN32) || defined(__MSYS__) + /* 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 +# if defined(__CYGWIN__) + /* On Cygwin, uid 0 is invalid (no root). */ + ASSERT(req->result == UV_EINVAL); +# else + ASSERT(req->result == UV_EPERM); +# endif +#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 fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} + +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 non_existent_scandir_cb(uv_fs_t* req) { + uv_dirent_t dent; + + ASSERT(req == &scandir_req); + ASSERT(req->fs_type == UV_FS_SCANDIR); + ASSERT(req->result == UV_ENOENT); + ASSERT(req->ptr == NULL); + ASSERT(UV_ENOENT == 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; +#elif defined(__MSYS__) + /* MSYS2's approximation of symlinks with copies does not work for broken + links. */ + if (r == UV_ENOENT) + 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 + (s->st_atim.tv_nsec / 1000000000.0) == atime); + ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == 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(__ANDROID__) + ASSERT(s->st_atim.tv_sec == t.st_atime); + ASSERT(s->st_atim.tv_nsec == t.st_atimensec); + ASSERT(s->st_mtim.tv_sec == t.st_mtime); + ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec); + ASSERT(s->st_ctim.tv_sec == t.st_ctime); + ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec); +#elif defined(__sun) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + 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(__FreeBSD__) || \ + 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); + +#ifndef __MVS__ + /* chown to root (fail) */ + chown_cb_count = 0; + r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(chown_cb_count == 1); +#endif + + /* 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); + +#if defined(__MSYS__) + RETURN_SKIP("symlink reading is not supported on MSYS2"); +#endif + + 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; +} + + +int test_symlink_dir_impl(int type) { + 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", type, NULL); + if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("this version of Windows doesn't support unprivileged " + "creation of directory symlinks"); + } + 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); +#if defined(__MSYS__) + RETURN_SKIP("symlink reading is not supported on MSYS2"); +#endif + 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_symlink_dir) { + return test_symlink_dir_impl(UV_FS_SYMLINK_DIR); +} + +TEST_IMPL(fs_symlink_junction) { + return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION); +} + +#ifdef _WIN32 +TEST_IMPL(fs_non_symlink_reparse_point) { + uv_fs_t req; + int r; + HANDLE file_handle; + REPARSE_GUID_DATA_BUFFER reparse_buffer; + DWORD bytes_returned; + uv_dirent_t dent; + + /* set-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + + file_handle = CreateFile("test_dir/test_file", + GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + ASSERT(file_handle != INVALID_HANDLE_VALUE); + + memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); + reparse_buffer.ReparseTag = REPARSE_TAG; + reparse_buffer.ReparseDataLength = 0; + reparse_buffer.ReparseGuid = REPARSE_GUID; + + r = DeviceIoControl(file_handle, + FSCTL_SET_REPARSE_POINT, + &reparse_buffer, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, + NULL, + 0, + &bytes_returned, + NULL); + ASSERT(r != 0); + + CloseHandle(file_handle); + + r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED); + uv_fs_req_cleanup(&req); + +/* + Placeholder tests for exercising the behavior fixed in issue #995. + To run, update the path with the IP address of a Mac with the hard drive + shared via SMB as "Macintosh HD". + + r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + +/* + uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse + points when a minifilter driver is registered which intercepts + associated filesystem requests. Installing a driver is beyond + the scope of this test. + + r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + + r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); + ASSERT(r == 1); + ASSERT(scandir_req.result == 1); + ASSERT(scandir_req.ptr); + while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { + ASSERT(strcmp(dent.name, "test_file") == 0); + /* uv_fs_scandir incorrectly identifies non-symlink reparse points + as links because it doesn't open the file and verify the reparse + point tag. The PowerShell Get-ChildItem command shares this + behavior, so it's reasonable to leave it as is. */ + ASSERT(dent.type == UV_DIRENT_LINK); + } + uv_fs_req_cleanup(&scandir_req); + ASSERT(!scandir_req.ptr); + + /* clean-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +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 */ + + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + + 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; + + 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) { +#if defined(_AIX) && !defined(_AIX71) + RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); +#else + 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 */ + + /* + * Test sub-second timestamps only on Windows (assuming NTFS). Some other + * platforms support sub-second timestamps, but that support is filesystem- + * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + + 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); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(r == UV_ENOSYS); + RETURN_SKIP("futime not supported on Cygwin"); +#else + ASSERT(r == 0); + ASSERT(req.result == 0); +#endif + 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; +#endif +} + + +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_non_existent_dir) { + const char* path; + uv_fs_t req; + uv_dirent_t dent; + int r; + + path = "./non_existent_dir/"; + loop = uv_default_loop(); + + uv_fs_rmdir(NULL, &req, path, 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 == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + ASSERT(req.ptr == NULL); + ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent)); + uv_fs_req_cleanup(&req); + + r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_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_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) { +#if defined(__CYGWIN__) || defined(__MSYS__) + RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!"); +#endif + 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((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); + + 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, &read_req, 0, NULL, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL); + /* Validate some memory management on failed input validation before sending + fs work to the thread pool. */ + ASSERT(r == UV_EINVAL); + ASSERT(write_req.path == NULL); + ASSERT(write_req.ptr == NULL); +#ifdef _WIN32 + ASSERT(write_req.file.pathw == NULL); + ASSERT(write_req.fs.info.new_pathw == NULL); + ASSERT(write_req.fs.info.bufs == NULL); +#else + ASSERT(write_req.new_path == NULL); + ASSERT(write_req.bufs == NULL); +#endif + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&write_req); + + /* If the arguments are invalid, the loop should not be kept open */ + loop = uv_default_loop(); + + r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(NULL, 0); + r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb); + ASSERT(r == UV_EINVAL); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&write_req); + + return 0; +} + + +TEST_IMPL(get_osfhandle_valid_handle) { + int r; + uv_os_fd_t fd; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + 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); + + fd = uv_get_osfhandle(open_req1.result); +#ifdef _WIN32 + ASSERT(fd != INVALID_HANDLE_VALUE); +#else + ASSERT(fd >= 0); +#endif + + 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_file_pos_after_op_with_offset) { + int r; + + /* Setup. */ + unlink("test_file"); + loop = uv_default_loop(); + + r = uv_fs_open(loop, + &open_req1, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r > 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, 0, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + uv_fs_req_cleanup(&write_req); + + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(strcmp(buf, test_buf) == 0); + ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_null_req) { + /* Verify that all fs functions return UV_EINVAL when the request is NULL. */ + int r; + + r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_close(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + 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); + + r = uv_fs_unlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rmdir(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_link(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_readlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_realpath(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_stat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_lstat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fstat(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fsync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fdatasync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_access(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + /* This should be a no-op. */ + uv_fs_req_cleanup(NULL); + + return 0; +} + +#ifdef _WIN32 +TEST_IMPL(fs_exclusive_sharing_mode) { + int r; + + /* Setup. */ + unlink("test_file"); + + ASSERT(UV_FS_O_EXLOCK > 0); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r < 0); + ASSERT(open_req2.result < 0); + uv_fs_req_cleanup(&open_req2); + + 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_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req2.result >= 0); + uv_fs_req_cleanup(&open_req2); + + r = uv_fs_close(NULL, &close_req, open_req2.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; +} +#endif diff --git a/3rd/libuv-1.19.2/test/test-get-currentexe.c b/3rd/libuv-1.19.2/test/test-get-currentexe.c new file mode 100644 index 00000000..0e9d6965 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#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/3rd/libuv-1.19.2/test/test-get-loadavg.c b/3rd/libuv-1.19.2/test/test-get-loadavg.c new file mode 100644 index 00000000..4762e475 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-get-memory.c b/3rd/libuv-1.19.2/test/test-get-memory.c new file mode 100644 index 00000000..2396939b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-get-passwd.c b/3rd/libuv-1.19.2/test/test-get-passwd.c new file mode 100644 index 00000000..8e16fb83 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-get-passwd.c @@ -0,0 +1,86 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +TEST_IMPL(get_passwd) { + uv_passwd_t pwd; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + len = strlen(pwd.username); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.shell == NULL); +#else + len = strlen(pwd.shell); + ASSERT(len > 0); +#endif + + len = strlen(pwd.homedir); + ASSERT(len > 0); + +#ifdef _WIN32 + if (len == 3 && pwd.homedir[1] == ':') + ASSERT(pwd.homedir[2] == '\\'); + else + ASSERT(pwd.homedir[len - 1] != '\\'); +#else + if (len == 1) + ASSERT(pwd.homedir[0] == '/'); + else + ASSERT(pwd.homedir[len - 1] != '/'); +#endif + +#ifdef _WIN32 + ASSERT(pwd.uid == -1); + ASSERT(pwd.gid == -1); +#else + ASSERT(pwd.uid >= 0); + ASSERT(pwd.gid >= 0); +#endif + + /* Test uv_os_free_passwd() */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test a double free */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test invalid input */ + r = uv_os_get_passwd(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-getaddrinfo.c b/3rd/libuv-1.19.2/test/test-getaddrinfo.c new file mode 100644 index 00000000..03dc1269 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-getaddrinfo.c @@ -0,0 +1,191 @@ +/* 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 + +#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; + + ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), + &req, + (uv_getaddrinfo_cb) abort, + NULL, + NULL, + NULL)); + + /* 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/3rd/libuv-1.19.2/test/test-gethostname.c b/3rd/libuv-1.19.2/test/test-gethostname.c new file mode 100644 index 00000000..5229804b --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-gethostname.c @@ -0,0 +1,62 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +TEST_IMPL(gethostname) { + char buf[MAXHOSTNAMELEN + 1]; + size_t size; + size_t enobufs_size; + int r; + + /* Reject invalid inputs */ + size = 1; + r = uv_os_gethostname(NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_gethostname(buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_gethostname(buf, &size); + ASSERT(r == UV_EINVAL); + + /* Return UV_ENOBUFS if the buffer cannot hold the hostname */ + enobufs_size = 1; + buf[0] = '\0'; + r = uv_os_gethostname(buf, &enobufs_size); + ASSERT(r == UV_ENOBUFS); + ASSERT(buf[0] == '\0'); + ASSERT(enobufs_size > 1); + + /* Successfully get the hostname */ + size = MAXHOSTNAMELEN + 1; + r = uv_os_gethostname(buf, &size); + ASSERT(r == 0); + ASSERT(size > 1 && size == strlen(buf)); + ASSERT(size + 1 == enobufs_size); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-getnameinfo.c b/3rd/libuv-1.19.2/test/test-getnameinfo.c new file mode 100644 index 00000000..b1391616 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/test-getsockname.c b/3rd/libuv-1.19.2/test/test-getsockname.c new file mode 100644 index 00000000..565c17fe --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-getters-setters.c b/3rd/libuv-1.19.2/test/test-getters-setters.c new file mode 100644 index 00000000..60a1b926 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-getters-setters.c @@ -0,0 +1,88 @@ +#include "uv.h" +#include "task.h" +#include +#include + +int cookie1; +int cookie2; +int cookie3; + + +TEST_IMPL(handle_type_name) { + ASSERT(strcmp(uv_handle_type_name(UV_NAMED_PIPE), "pipe") == 0); + ASSERT(strcmp(uv_handle_type_name(UV_UDP), "udp") == 0); + ASSERT(strcmp(uv_handle_type_name(UV_FILE), "file") == 0); + ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX) == NULL); + ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX + 1) == NULL); + ASSERT(uv_handle_type_name(UV_UNKNOWN_HANDLE) == NULL); + return 0; +} + + +TEST_IMPL(req_type_name) { + ASSERT(strcmp(uv_req_type_name(UV_REQ), "req") == 0); + ASSERT(strcmp(uv_req_type_name(UV_UDP_SEND), "udp_send") == 0); + ASSERT(strcmp(uv_req_type_name(UV_WORK), "work") == 0); + ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX) == NULL); + ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX + 1) == NULL); + ASSERT(uv_req_type_name(UV_UNKNOWN_REQ) == NULL); + return 0; +} + + +TEST_IMPL(getters_setters) { + uv_loop_t* loop; + uv_pipe_t* pipe; + uv_fs_t* fs; + int r; + + loop = malloc(uv_loop_size()); + ASSERT(loop != NULL); + r = uv_loop_init(loop); + ASSERT(r == 0); + + uv_loop_set_data(loop, &cookie1); + ASSERT(loop->data == &cookie1); + ASSERT(uv_loop_get_data(loop) == &cookie1); + + pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); + r = uv_pipe_init(loop, pipe, 0); + ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); + + ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); + pipe->data = &cookie2; + ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie2); + uv_handle_set_data((uv_handle_t*)pipe, &cookie1); + ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie1); + ASSERT(pipe->data == &cookie1); + + ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 0); + pipe->write_queue_size++; + ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 1); + pipe->write_queue_size--; + uv_close((uv_handle_t*)pipe, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + fs = malloc(uv_req_size(UV_FS)); + uv_fs_stat(loop, fs, ".", NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(uv_fs_get_type(fs) == UV_FS_STAT); + ASSERT(uv_fs_get_result(fs) == 0); + ASSERT(uv_fs_get_ptr(fs) == uv_fs_get_statbuf(fs)); + ASSERT(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); + ASSERT(strcmp(uv_fs_get_path(fs), ".") == 0); + uv_fs_req_cleanup(fs); + + r = uv_loop_close(loop); + ASSERT(r == 0); + + free(pipe); + free(fs); + free(loop); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-handle-fileno.c b/3rd/libuv-1.19.2/test/test-handle-fileno.c new file mode 100644 index 00000000..3fe933ad --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-homedir.c b/3rd/libuv-1.19.2/test/test-homedir.c new file mode 100644 index 00000000..856534a4 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-homedir.c @@ -0,0 +1,72 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(homedir) { + char homedir[PATHMAX]; + size_t len; + 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'); + +#ifdef _WIN32 + if (len == 3 && homedir[1] == ':') + ASSERT(homedir[2] == '\\'); + else + ASSERT(homedir[len - 1] != '\\'); +#else + if (len == 1) + ASSERT(homedir[0] == '/'); + else + ASSERT(homedir[len - 1] != '/'); +#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/3rd/libuv-1.19.2/test/test-hrtime.c b/3rd/libuv-1.19.2/test/test-hrtime.c new file mode 100644 index 00000000..72a4d4b1 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-idle.c b/3rd/libuv-1.19.2/test/test-idle.c new file mode 100644 index 00000000..f49d1964 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-ip4-addr.c b/3rd/libuv-1.19.2/test/test-ip4-addr.c new file mode 100644 index 00000000..3d6e0cf2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-ip6-addr.c b/3rd/libuv-1.19.2/test/test-ip6-addr.c new file mode 100644 index 00000000..25570dca --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ip6-addr.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 +#include + +#ifdef __linux__ +# include +# include +#endif + + +TEST_IMPL(ip6_addr_link_local) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + 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]; + size_t scoped_addr_len; + char interface_id[UV_IF_NAMESIZE]; + size_t interface_id_len; + int count; + int ix; + int r; + + 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; + + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr, &scoped_addr_len)); +#ifndef _WIN32 + /* This assert fails on Windows, as Windows semantics are different. */ + ASSERT(0 == strcmp(device_name, scoped_addr)); +#endif + + interface_id_len = sizeof(interface_id); + r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); + ASSERT(0 == r); +#ifdef _WIN32 + /* On Windows, the interface identifier is the numeric string of the index. */ + ASSERT(strtol(interface_id, NULL, 10) == iface_index); +#else + /* On Unix/Linux, the interface identifier is the interface device name. */ + ASSERT(0 == strcmp(device_name, interface_id)); +#endif + + snprintf(scoped_addr, + sizeof(scoped_addr), + "%s%%%s", + string_address, + interface_id); + + 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); + + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); + + 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/3rd/libuv-1.19.2/test/test-ipc-send-recv.c b/3rd/libuv-1.19.2/test/test-ipc-send-recv.c new file mode 100644 index 00000000..917744cb --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ipc-send-recv.c @@ -0,0 +1,428 @@ +/* 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 +#include + +/* 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_count; +static int recv_cb_count; +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; + + pipe = (uv_pipe_t*) handle; + ASSERT(pipe == &ctx.channel); + + do { + if (++recv_cb_count == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } + + /* 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_count == 2); + } else { + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + 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); + } + } while (uv_pipe_pending_count(pipe) > 0); + + /* Close after two writes received */ + if (recv_cb_count == 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_count == 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + return run_ipc_send_recv_pipe(0); +} + +TEST_IMPL(ipc_send_recv_pipe_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + return run_ipc_send_recv_tcp(0); +} + +TEST_IMPL(ipc_send_recv_tcp_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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; + } + + pipe = (uv_pipe_t*) handle; + do { + if (++read_cb_count == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } + + ASSERT(pipe == &ctx2.channel); + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + 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); + } while (uv_pipe_pending_count(pipe) > 0); +} + +static void send_recv_start(void) { + 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/3rd/libuv-1.19.2/test/test-ipc.c b/3rd/libuv-1.19.2/test/test-ipc.c new file mode 100644 index 00000000..88d63d4d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ipc.c @@ -0,0 +1,887 @@ +/* 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 +#include + +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; +static int closed_handle_data_read; + +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 +#define LARGE_SIZE 1000000 + + +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); +} + + +#ifndef _WIN32 +static void on_read_closed_handle(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + if (nread == 0 || nread == UV_EOF) { + free(buf->base); + return; + } + + if (nread < 0) { + printf("error recving on channel: %s\n", uv_strerror(nread)); + abort(); + } + + closed_handle_data_read += nread; + free(buf->base); +} +#endif + + +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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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; +} + +#ifndef _WIN32 +TEST_IMPL(ipc_closed_handle) { + int r; + r = run_ipc_test("ipc_helper_closed_handle", on_read_closed_handle); + ASSERT(r == 0); + return 0; +} +#endif + + +#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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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 closed_handle_large_write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + ASSERT(closed_handle_data_read = LARGE_SIZE); +} + + +static void closed_handle_write_cb(uv_write_t* req, int status) { + ASSERT(status == UV_EBADF); +} + + +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_closed_handle(void) { + int r; + struct sockaddr_in addr; + uv_write_t write_req; + uv_write_t write_req2; + uv_buf_t buf; + char buffer[LARGE_SIZE]; + + 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)); + + memset(buffer, '.', LARGE_SIZE); + buf = uv_buf_init(buffer, LARGE_SIZE); + + 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_write(&write_req, + (uv_stream_t*)&channel, + &buf, + 1, + closed_handle_large_write_cb); + ASSERT(r == 0); + + r = uv_write2(&write_req2, + (uv_stream_t*)&channel, + &buf, + 1, + (uv_stream_t*)&tcp_server, + closed_handle_write_cb); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&tcp_server, NULL); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + 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/3rd/libuv-1.19.2/test/test-list.h b/3rd/libuv-1.19.2/test/test-list.h new file mode 100644 index 00000000..ff0a31d1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-list.h @@ -0,0 +1,905 @@ +/* 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" + +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_instant_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 (condvar_6) +TEST_DECLARE (semaphore_1) +TEST_DECLARE (semaphore_2) +TEST_DECLARE (semaphore_3) +TEST_DECLARE (tty) +#ifdef _WIN32 +TEST_DECLARE (tty_raw) +TEST_DECLARE (tty_empty_write) +TEST_DECLARE (tty_large_write) +#endif +TEST_DECLARE (tty_file) +TEST_DECLARE (tty_pty) +TEST_DECLARE (stdio_over_pipes) +TEST_DECLARE (ip6_pton) +TEST_DECLARE (connect_unspecified) +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) +#ifndef _WIN32 +TEST_DECLARE (ipc_closed_handle) +#endif +TEST_DECLARE (tcp_alloc_cb_fail) +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_open_bound) +TEST_DECLARE (tcp_open_connected) +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_alloc_cb_fail) +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_hang_loop) +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 (env_vars) +TEST_DECLARE (error_message) +TEST_DECLARE (sys_error) +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 (timer_early_check) +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 (pipe_set_chmod) +TEST_DECLARE (process_ref) +TEST_DECLARE (has_ref) +TEST_DECLARE (active) +TEST_DECLARE (embed) +TEST_DECLARE (async) +TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) +TEST_DECLARE (get_currentexe) +TEST_DECLARE (process_title) +TEST_DECLARE (process_title_threadsafe) +TEST_DECLARE (cwd_and_chdir) +TEST_DECLARE (get_memory) +TEST_DECLARE (get_passwd) +TEST_DECLARE (handle_fileno) +TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) +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 (gethostname) +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 (spawn_quoted_path) +TEST_DECLARE (spawn_tcp_server) +TEST_DECLARE (fs_poll) +TEST_DECLARE (fs_poll_getpath) +TEST_DECLARE (kill) +TEST_DECLARE (kill_invalid_signum) +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_copyfile) +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) +#ifdef _WIN32 +TEST_DECLARE (fs_symlink_junction) +TEST_DECLARE (fs_non_symlink_reparse_point) +#endif +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_exact_path) +TEST_DECLARE (fs_event_watch_file_twice) +TEST_DECLARE (fs_event_watch_file_current_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_file_root_dir) +#endif +TEST_DECLARE (fs_event_watch_invalid_path) +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_non_existent_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 (get_osfhandle_valid_handle) +TEST_DECLARE (fs_write_alotof_bufs) +TEST_DECLARE (fs_write_alotof_bufs_with_offset) +TEST_DECLARE (fs_file_pos_after_op_with_offset) +TEST_DECLARE (fs_null_req) +#ifdef _WIN32 +TEST_DECLARE (fs_exclusive_sharing_mode) +#endif +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_stack_size) +TEST_DECLARE (thread_mutex) +TEST_DECLARE (thread_mutex_recursive) +TEST_DECLARE (thread_rwlock) +TEST_DECLARE (thread_rwlock_trylock) +TEST_DECLARE (thread_create) +TEST_DECLARE (thread_equal) +TEST_DECLARE (dlerror) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) +TEST_DECLARE (poll_oob) +#endif +TEST_DECLARE (poll_duplex) +TEST_DECLARE (poll_unidirectional) +TEST_DECLARE (poll_close) +TEST_DECLARE (poll_bad_fdtype) +#ifdef __linux__ +TEST_DECLARE (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE +TEST_DECLARE (poll_nested_kqueue) +#endif + +TEST_DECLARE (ip4_addr) +TEST_DECLARE (ip6_addr_link_local) + +TEST_DECLARE (poll_close_doesnt_corrupt_stack) +TEST_DECLARE (poll_closesocket) +#ifdef _WIN32 +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) +TEST_DECLARE (win32_signum_number) +#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 (we_get_signal_one_shot) +TEST_DECLARE (we_get_signals_mixed) +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) + +TEST_DECLARE (handle_type_name) +TEST_DECLARE (req_type_name) +TEST_DECLARE (getters_setters) + +#ifndef _WIN32 +TEST_DECLARE (fork_timer) +TEST_DECLARE (fork_socketpair) +TEST_DECLARE (fork_socketpair_started) +TEST_DECLARE (fork_signal_to_child) +TEST_DECLARE (fork_signal_to_child_closed) +TEST_DECLARE (fork_fs_events_child) +TEST_DECLARE (fork_fs_events_child_dir) +TEST_DECLARE (fork_fs_events_file_parent_child) +#ifndef __MVS__ +TEST_DECLARE (fork_threadpool_queue_work_simple) +#endif +#endif + +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_instant_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 (condvar_6) + 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 (pipe_set_chmod) + TEST_ENTRY (tty) +#ifdef _WIN32 + TEST_ENTRY (tty_raw) + TEST_ENTRY (tty_empty_write) + TEST_ENTRY (tty_large_write) +#endif + TEST_ENTRY (tty_file) + TEST_ENTRY (tty_pty) + TEST_ENTRY (stdio_over_pipes) + TEST_ENTRY (ip6_pton) + TEST_ENTRY (connect_unspecified) + 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) +#ifndef _WIN32 + TEST_ENTRY (ipc_closed_handle) +#endif + + TEST_ENTRY (tcp_alloc_cb_fail) + + 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 + +#ifdef __MVS__ + TEST_ENTRY_CUSTOM (tcp_writealot, 0, 0, 20000) +#else + TEST_ENTRY (tcp_writealot) +#endif + 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_open_bound) + TEST_ENTRY (tcp_open_connected) + TEST_HELPER (tcp_open_connected, tcp4_echo_server) + + 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_alloc_cb_fail) + 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_hang_loop) + 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 (env_vars) + + TEST_ENTRY (error_message) + TEST_ENTRY (sys_error) + + 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 (timer_early_check) + + 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 (eintr_handling) + + TEST_ENTRY (get_currentexe) + + TEST_ENTRY (process_title) + TEST_ENTRY (process_title_threadsafe) + + TEST_ENTRY (cwd_and_chdir) + + TEST_ENTRY (get_memory) + + TEST_ENTRY (get_passwd) + + TEST_ENTRY (get_loadavg) + + TEST_ENTRY (handle_fileno) + + TEST_ENTRY (homedir) + + TEST_ENTRY (tmpdir) + + 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 (gethostname) + + 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 (poll_bad_fdtype) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) + TEST_ENTRY (poll_oob) +#endif + +#ifdef __linux__ + TEST_ENTRY (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE + TEST_ENTRY (poll_nested_kqueue) +#endif + + 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 (spawn_quoted_path) + TEST_ENTRY (spawn_tcp_server) + TEST_ENTRY (fs_poll) + TEST_ENTRY (fs_poll_getpath) + TEST_ENTRY (kill) + TEST_ENTRY (kill_invalid_signum) + + TEST_ENTRY (poll_close_doesnt_corrupt_stack) + TEST_ENTRY (poll_closesocket) +#ifdef _WIN32 + 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) + TEST_ENTRY (win32_signum_number) +#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 (we_get_signal_one_shot) + TEST_ENTRY (we_get_signals_mixed) + 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_copyfile) + 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) +#ifdef _WIN32 + TEST_ENTRY (fs_symlink_junction) + TEST_ENTRY (fs_non_symlink_reparse_point) +#endif + 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_exact_path) + TEST_ENTRY (fs_event_watch_file_twice) + TEST_ENTRY (fs_event_watch_file_current_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_file_root_dir) +#endif + TEST_ENTRY (fs_event_watch_invalid_path) + 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_non_existent_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 (fs_file_pos_after_op_with_offset) + TEST_ENTRY (fs_null_req) +#ifdef _WIN32 + TEST_ENTRY (fs_exclusive_sharing_mode) +#endif + TEST_ENTRY (get_osfhandle_valid_handle) + 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_stack_size) + TEST_ENTRY (thread_mutex) + TEST_ENTRY (thread_mutex_recursive) + 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) + + TEST_ENTRY (handle_type_name) + TEST_ENTRY (req_type_name) + TEST_ENTRY (getters_setters) + +#ifndef _WIN32 + TEST_ENTRY (fork_timer) + TEST_ENTRY (fork_socketpair) + TEST_ENTRY (fork_socketpair_started) + TEST_ENTRY (fork_signal_to_child) + TEST_ENTRY (fork_signal_to_child_closed) + TEST_ENTRY (fork_fs_events_child) + TEST_ENTRY (fork_fs_events_child_dir) + TEST_ENTRY (fork_fs_events_file_parent_child) +#ifndef __MVS__ + TEST_ENTRY (fork_threadpool_queue_work_simple) +#endif +#endif + +#if 0 + /* These are for testing the test runner. */ + TEST_ENTRY (fail_always) + TEST_ENTRY (pass_always) +#endif +TASK_LIST_END diff --git a/3rd/libuv-1.19.2/test/test-loop-alive.c b/3rd/libuv-1.19.2/test/test-loop-alive.c new file mode 100644 index 00000000..cf4d3019 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-loop-close.c b/3rd/libuv-1.19.2/test/test-loop-close.c new file mode 100644 index 00000000..f0f3e627 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-loop-close.c @@ -0,0 +1,75 @@ +/* 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; + + loop.data = &loop; + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(loop.data == (void*) &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(loop.data == (void*) &loop); + ASSERT(0 == uv_loop_close(&loop)); + ASSERT(loop.data == (void*) &loop); + + return 0; +} + +static void loop_instant_close_work_cb(uv_work_t* req) { +} + +static void loop_instant_close_after_work_cb(uv_work_t* req, int status) { +} + +TEST_IMPL(loop_instant_close) { + static uv_loop_t loop; + static uv_work_t req; + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_queue_work(&loop, + &req, + loop_instant_close_work_cb, + loop_instant_close_after_work_cb)); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-loop-configure.c b/3rd/libuv-1.19.2/test/test-loop-configure.c new file mode 100644 index 00000000..d057c1ed --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-loop-configure.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2014, Ben Noordhuis + * + * 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/3rd/libuv-1.19.2/test/test-loop-handles.c b/3rd/libuv-1.19.2/test/test-loop-handles.c new file mode 100644 index 00000000..c3e8498a --- /dev/null +++ b/3rd/libuv-1.19.2/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 + + +#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/3rd/libuv-1.19.2/test/test-loop-stop.c b/3rd/libuv-1.19.2/test/test-loop-stop.c new file mode 100644 index 00000000..14b8c111 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-loop-time.c b/3rd/libuv-1.19.2/test/test-loop-time.c new file mode 100644 index 00000000..a2db42cc --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-multiple-listen.c b/3rd/libuv-1.19.2/test/test-multiple-listen.c new file mode 100644 index 00000000..4ae5fa67 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-mutexes.c b/3rd/libuv-1.19.2/test/test-mutexes.c new file mode 100644 index 00000000..975222ca --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-mutexes.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 +#include + +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_mutex_recursive) { + uv_mutex_t mutex; + int r; + + r = uv_mutex_init_recursive(&mutex); + ASSERT(r == 0); + + uv_mutex_lock(&mutex); + uv_mutex_lock(&mutex); + ASSERT(0 == uv_mutex_trylock(&mutex)); + + uv_mutex_unlock(&mutex); + uv_mutex_unlock(&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/3rd/libuv-1.19.2/test/test-osx-select.c b/3rd/libuv-1.19.2/test/test-osx-select.c new file mode 100644 index 00000000..a0afda91 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-pass-always.c b/3rd/libuv-1.19.2/test/test-pass-always.c new file mode 100644 index 00000000..4fb58ff9 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-ping-pong.c b/3rd/libuv-1.19.2/test/test-ping-pong.c new file mode 100644 index 00000000..508f0db6 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ping-pong.c @@ -0,0 +1,274 @@ +/* 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 +#include + +static int completed_pingers = 0; + +#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__) +#define NUM_PINGS 100 /* fewer pings to avoid timeout */ +#else +#define NUM_PINGS 1000 +#endif + +/* 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/3rd/libuv-1.19.2/test/test-pipe-bind-error.c b/3rd/libuv-1.19.2/test/test-pipe-bind-error.c new file mode 100644 index 00000000..9cf93165 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-bind-error.c @@ -0,0 +1,139 @@ +/* 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 +#include + + +#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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c b/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c new file mode 100644 index 00000000..4ab14789 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c @@ -0,0 +1,107 @@ +/* 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 +#include +#include +#include + +#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; + char buf; + 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]); + /* block until write end of pipe is closed */ + read(fd[0], &buf, 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/3rd/libuv-1.19.2/test/test-pipe-connect-error.c b/3rd/libuv-1.19.2/test/test-pipe-connect-error.c new file mode 100644 index 00000000..ebb2a6ca --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +#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/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c b/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c new file mode 100644 index 00000000..0a60d4a9 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 +#include + + +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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c b/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c new file mode 100644 index 00000000..a86e7284 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 +#include + + +#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/3rd/libuv-1.19.2/test/test-pipe-getsockname.c b/3rd/libuv-1.19.2/test/test-pipe-getsockname.c new file mode 100644 index 00000000..d1628a67 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-getsockname.c @@ -0,0 +1,266 @@ +/* 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 +#include +#include + +#if defined(__linux__) + #include + #include +#endif + +#ifndef _WIN32 +# include /* close */ +#else +# include +#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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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(buf[len] == '\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(len1 == 0); /* It's an annonymous pipe. */ + + 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(len2 == 0); /* It's an annonymous pipe. */ + + 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); + + CloseHandle(writeh); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c b/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c new file mode 100644 index 00000000..b6ff911a --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c b/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c new file mode 100644 index 00000000..3bf427f8 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-sendmsg.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 "task.h" + + +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include + + +/* 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) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-server-close.c b/3rd/libuv-1.19.2/test/test-pipe-server-close.c new file mode 100644 index 00000000..ea9977dd --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-server-close.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 +#include + + +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) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + 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/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c b/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c new file mode 100644 index 00000000..59f0e6f5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c @@ -0,0 +1,66 @@ +/* Copyright 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. +*/ + + +#include "uv.h" +#include "task.h" + +TEST_IMPL(pipe_set_chmod) { + uv_pipe_t pipe_handle; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_pipe_init(loop, &pipe_handle, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); + ASSERT(r == 0); + + /* No easy way to test if this works, we will only make sure that */ + /* the call is successful. */ + r = uv_pipe_chmod(&pipe_handle, UV_READABLE); + if (r == UV_EPERM) { + MAKE_VALGRIND_HAPPY(); + RETURN_SKIP("Insufficient privileges to alter pipe fmode"); + } + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + r = uv_pipe_chmod(&pipe_handle, 12345678); + ASSERT(r == UV_EINVAL); + + uv_close((uv_handle_t*)&pipe_handle, NULL); + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c b/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c new file mode 100644 index 00000000..fcc9fc0d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c @@ -0,0 +1,99 @@ +/* Copyright (c) 2015, Ben Noordhuis + * + * 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 +#include +#include +#include +#include +#include + +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/3rd/libuv-1.19.2/test/test-platform-output.c b/3rd/libuv-1.19.2/test/test-platform-output.c new file mode 100644 index 00000000..4025fba5 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-platform-output.c @@ -0,0 +1,157 @@ +/* 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 + + +TEST_IMPL(platform_output) { + char buffer[512]; + size_t rss; + size_t size; + double uptime; + uv_pid_t pid; + uv_pid_t ppid; + uv_rusage_t rusage; + uv_cpu_info_t* cpus; + uv_interface_address_t* interfaces; + uv_passwd_t pwd; + 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); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else + ASSERT(err == 0); + printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); +#endif + + 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); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + + err = uv_cpu_info(&cpus, &count); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else + 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); + } +#endif + 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); + + err = uv_os_get_passwd(&pwd); + ASSERT(err == 0); + + printf("uv_os_get_passwd:\n"); + printf(" euid: %ld\n", pwd.uid); + printf(" gid: %ld\n", pwd.gid); + printf(" username: %s\n", pwd.username); + printf(" shell: %s\n", pwd.shell); + printf(" home directory: %s\n", pwd.homedir); + + pid = uv_os_getpid(); + ASSERT(pid > 0); + printf("uv_os_getpid: %d\n", (int) pid); + ppid = uv_os_getppid(); + ASSERT(ppid > 0); + printf("uv_os_getppid: %d\n", (int) ppid); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c b/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c new file mode 100644 index 00000000..1dfc80e3 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c @@ -0,0 +1,116 @@ +/* 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. + */ + +#include +#include + +#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; + +#ifdef _WIN32 +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); +} +#endif + + +TEST_IMPL(poll_close_doesnt_corrupt_stack) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else + 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 +} diff --git a/3rd/libuv-1.19.2/test/test-poll-close.c b/3rd/libuv-1.19.2/test/test-poll-close.c new file mode 100644 index 00000000..2eccddf5 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + +#ifndef _WIN32 +# include +# include +# include +#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/3rd/libuv-1.19.2/test/test-poll-closesocket.c b/3rd/libuv-1.19.2/test/test-poll-closesocket.c new file mode 100644 index 00000000..ecaa9e54 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-closesocket.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 + +#include "uv.h" +#include "task.h" + +uv_os_sock_t sock; +uv_poll_t handle; + +#ifdef _WIN32 +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); + +} +#endif + + +TEST_IMPL(poll_closesocket) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else + 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/3rd/libuv-1.19.2/test/test-poll-oob.c b/3rd/libuv-1.19.2/test/test-poll-oob.c new file mode 100644 index 00000000..2a6da843 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll-oob.c @@ -0,0 +1,205 @@ +/* Copyright 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(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include +#include + +static uv_tcp_t server_handle; +static uv_tcp_t client_handle; +static uv_tcp_t peer_handle; +static uv_poll_t poll_req[2]; +static uv_idle_t idle; +static uv_os_fd_t client_fd; +static uv_os_fd_t server_fd; +static int ticks; +static const int kMaxTicks = 10; +static int cli_pr_check = 0; +static int cli_rd_check = 0; +static int srv_rd_check = 0; + +static int got_eagain(void) { + return errno == EAGAIN + || errno == EINPROGRESS +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ; +} + +static void idle_cb(uv_idle_t* idle) { + uv_sleep(100); + if (++ticks < kMaxTicks) + return; + + uv_poll_stop(&poll_req[0]); + uv_poll_stop(&poll_req[1]); + 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 poll_cb(uv_poll_t* handle, int status, int events) { + char buffer[5]; + int n; + int fd; + + ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + memset(buffer, 0, 5); + + if (events & UV_PRIORITIZED) { + do + n = recv(client_fd, &buffer, 5, MSG_OOB); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + cli_pr_check = 1; + ASSERT(0 == uv_poll_stop(&poll_req[0])); + ASSERT(0 == uv_poll_start(&poll_req[0], + UV_READABLE | UV_WRITABLE, + poll_cb)); + } + if (events & UV_READABLE) { + if (fd == client_fd) { + do + n = recv(client_fd, &buffer, 5, 0); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + if (cli_rd_check == 1) { + ASSERT(strncmp(buffer, "world", n) == 0); + ASSERT(5 == n); + cli_rd_check = 2; + } + if (cli_rd_check == 0) { + ASSERT(n == 4); + ASSERT(strncmp(buffer, "hello", n) == 0); + cli_rd_check = 1; + do { + do + n = recv(server_fd, &buffer, 5, 0); + while (n == -1 && errno == EINTR); + if (n > 0) { + ASSERT(n == 5); + ASSERT(strncmp(buffer, "world", n) == 0); + cli_rd_check = 2; + } + } while (n > 0); + + ASSERT(got_eagain()); + } + } + if (fd == server_fd) { + do + n = recv(server_fd, &buffer, 3, 0); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + ASSERT(3 == n); + ASSERT(strncmp(buffer, "foo", n) == 0); + srv_rd_check = 1; + uv_poll_stop(&poll_req[1]); + } + } + if (events & UV_WRITABLE) { + do { + n = send(client_fd, "foo", 3, 0); + } while (n < 0 && errno == EINTR); + ASSERT(3 == n); + } +} + +static void connection_cb(uv_stream_t* handle, int status) { + int r; + + ASSERT(0 == status); + ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); + ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); + ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); + ASSERT(0 == uv_poll_start(&poll_req[0], + UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, + poll_cb)); + ASSERT(0 == uv_poll_start(&poll_req[1], + UV_READABLE, + poll_cb)); + do { + r = send(server_fd, "hello", 5, MSG_OOB); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + do { + r = send(server_fd, "world", 5, 0); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + ASSERT(0 == uv_idle_start(&idle, idle_cb)); +} + + +TEST_IMPL(poll_oob) { + struct sockaddr_in addr; + int r = 0; + 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)); + + client_fd = socket(PF_INET, SOCK_STREAM, 0); + ASSERT(client_fd >= 0); + do { + errno = 0; + r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); + } while (r == -1 && errno == EINTR); + ASSERT(r == 0); + + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(ticks == kMaxTicks); + + /* Did client receive the POLLPRI message */ + ASSERT(cli_pr_check == 1); + /* Did client receive the POLLIN message */ + ASSERT(cli_rd_check == 2); + /* Could we write with POLLOUT and did the server receive our POLLOUT message + * through POLLIN. + */ + ASSERT(srv_rd_check == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif diff --git a/3rd/libuv-1.19.2/test/test-poll.c b/3rd/libuv-1.19.2/test/test-poll.c new file mode 100644 index 00000000..e828addb --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-poll.c @@ -0,0 +1,665 @@ +/* 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 + +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +#include "uv.h" +#include "task.h" + +#ifdef __linux__ +# include +#endif + +#ifdef UV_HAVE_KQUEUE +# include +# include +# include +#endif + + +#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, got_disconnect; + 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; + +#if !defined(_AIX) && !defined(__MVS__) +static int disconnects = 0; +#endif /* !_AIX && !__MVS__ */ + +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; + context->got_disconnect = 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 !defined(_AIX) && !defined(__MVS__) + if (events & UV_DISCONNECT) { + context->got_disconnect = 1; + ++disconnects; + new_events &= ~UV_DISCONNECT; + } + + if (context->got_fin && context->sent_fin && context->got_disconnect) { +#else /* _AIX && __MVS__ */ + if (context->got_fin && context->sent_fin) { +#endif /* !_AIX && !__MVS__ */ + /* 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 | UV_DISCONNECT; + r = uv_poll_start(&connection_context->poll_handle, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, + 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 | UV_DISCONNECT; + r = uv_poll_start(&context->poll_handle, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, + 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); +#if !defined(_AIX) && !defined(__MVS__) + ASSERT(disconnects == NUM_CLIENTS * 2); +#endif + MAKE_VALGRIND_HAPPY(); +} + + +TEST_IMPL(poll_duplex) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + test_mode = DUPLEX; + start_poll_test(); + return 0; +} + + +TEST_IMPL(poll_unidirectional) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + test_mode = UNIDIRECTIONAL; + start_poll_test(); + return 0; +} + + +/* Windows won't let you open a directory so we open a file instead. + * OS X lets you poll a file so open the $PWD instead. Both fail + * on Linux so it doesn't matter which one we pick. Both succeed + * on FreeBSD, Solaris and AIX so skip the test on those platforms. + */ +TEST_IMPL(poll_bad_fdtype) { +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ + !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) && \ + !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ + !defined(__NetBSD__) + uv_poll_t poll_handle; + int fd; + +#if defined(_WIN32) + fd = open("test/fixtures/empty_file", O_RDONLY); +#else + fd = open(".", O_RDONLY); +#endif + ASSERT(fd != -1); + ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == close(fd)); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#ifdef __linux__ +TEST_IMPL(poll_nested_epoll) { + uv_poll_t poll_handle; + int fd; + + fd = epoll_create(1); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* __linux__ */ + + +#ifdef UV_HAVE_KQUEUE +TEST_IMPL(poll_nested_kqueue) { + uv_poll_t poll_handle; + int fd; + + fd = kqueue(); + ASSERT(fd != -1); + + ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* UV_HAVE_KQUEUE */ diff --git a/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c b/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c new file mode 100644 index 00000000..d986576e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c @@ -0,0 +1,90 @@ +/* Copyright 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. +*/ + + +#include "uv.h" +#include "task.h" + +#include + +#ifdef __APPLE__ +# define NUM_ITERATIONS 20 +#else +# define NUM_ITERATIONS 50 +#endif + +static const char* titles[] = { + "8L2NY0Kdj0XyNFZnmUZigIOfcWjyNr0SkMmUhKw99VLUsZFrvCQQC3XIRfNR8pjyMjXObllled", + "jUAcscJN49oLSN8GdmXj2Wo34XX2T2vp2j5khfajNQarlOulp57cE130yiY53ipJFnPyTn5i82", + "9niCI5icXGFS72XudhXqo5alftmZ1tpE7B3cwUmrq0CCDjC84FzBNB8XAHqvpNQfI2QAQG6ztT", + "n8qXVXuG6IEHDpabJgTEiwtpY6LHMZ8MgznnMpdHARu5EywufA6hcBaQfetb0YhEsK0ykDd7JU" +}; + +static void getter_thread_body(void* arg) { + char buffer[512]; + + for (;;) { + ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); + ASSERT( + 0 == strcmp(buffer, titles[0]) || + 0 == strcmp(buffer, titles[1]) || + 0 == strcmp(buffer, titles[2]) || + 0 == strcmp(buffer, titles[3])); + + uv_sleep(0); + } +} + + +static void setter_thread_body(void* arg) { + int i; + + for (i = 0; i < NUM_ITERATIONS; i++) { + ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT(0 == uv_set_process_title(titles[1])); + ASSERT(0 == uv_set_process_title(titles[2])); + ASSERT(0 == uv_set_process_title(titles[3])); + } +} + + +TEST_IMPL(process_title_threadsafe) { + uv_thread_t setter_threads[4]; + uv_thread_t getter_thread; + int i; + +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ + defined(__MVS__) + RETURN_SKIP("uv_(get|set)_process_title is not implemented."); +#else + + ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT(0 == uv_thread_create(&getter_thread, getter_thread_body, NULL)); + + for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) + ASSERT(0 == uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); + + for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) + ASSERT(0 == uv_thread_join(&setter_threads[i])); + + return 0; +#endif +} diff --git a/3rd/libuv-1.19.2/test/test-process-title.c b/3rd/libuv-1.19.2/test/test-process-title.c new file mode 100644 index 00000000..886f83a7 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-process-title.c @@ -0,0 +1,75 @@ +/* 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 + + +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); +} + + +static void uv_get_process_title_edge_cases(void) { + char buffer[512]; + int r; + + /* Test a NULL buffer */ + r = uv_get_process_title(NULL, 100); + ASSERT(r == UV_EINVAL); + + /* Test size of zero */ + r = uv_get_process_title(buffer, 0); + ASSERT(r == UV_EINVAL); + + /* Test for insufficient buffer size */ + r = uv_get_process_title(buffer, 1); + ASSERT(r == UV_ENOBUFS); +} + + +TEST_IMPL(process_title) { +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) + 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"); + + /* Check uv_get_process_title() edge cases */ + uv_get_process_title_edge_cases(); + + return 0; +#endif +} diff --git a/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c b/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c new file mode 100644 index 00000000..45da2253 --- /dev/null +++ b/3rd/libuv-1.19.2/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 + + +/* + * 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/3rd/libuv-1.19.2/test/test-ref.c b/3rd/libuv-1.19.2/test/test-ref.c new file mode 100644 index 00000000..05728c83 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-ref.c @@ -0,0 +1,445 @@ +/* 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 +#include + + +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) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + 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/3rd/libuv-1.19.2/test/test-run-nowait.c b/3rd/libuv-1.19.2/test/test-run-nowait.c new file mode 100644 index 00000000..43524f63 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-run-once.c b/3rd/libuv-1.19.2/test/test-run-once.c new file mode 100644 index 00000000..10cbf95e --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-semaphore.c b/3rd/libuv-1.19.2/test/test-semaphore.c new file mode 100644 index 00000000..ac03bb08 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-shutdown-close.c b/3rd/libuv-1.19.2/test/test-shutdown-close.c new file mode 100644 index 00000000..78c369be --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-shutdown-eof.c b/3rd/libuv-1.19.2/test/test-shutdown-eof.c new file mode 100644 index 00000000..9f95e756 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-shutdown-twice.c b/3rd/libuv-1.19.2/test/test-shutdown-twice.c new file mode 100644 index 00000000..d7aae899 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-shutdown-twice.c @@ -0,0 +1,85 @@ +/* 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); + 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(shutdown_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c b/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c new file mode 100644 index 00000000..1272d457 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c @@ -0,0 +1,298 @@ +/* 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 +#include +#include +#include +#include +#include +#include + +/* 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) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: This test needs more investigation. Somehow the `read` in + uv__signal_lock fails spuriously with EACCES or even EAGAIN even + though it is supposed to be blocking. Also the test hangs during + thread setup occasionally. */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + 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); + } + + uv_sem_destroy(&sem); + 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/3rd/libuv-1.19.2/test/test-signal.c b/3rd/libuv-1.19.2/test/test-signal.c new file mode 100644 index 00000000..c2ce5ec0 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-signal.c @@ -0,0 +1,325 @@ +/* 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 +#endif + +TEST_IMPL(kill_invalid_signum) { + uv_pid_t pid; + + pid = uv_os_getpid(); + + ASSERT(uv_kill(pid, -1) == UV_EINVAL); +#ifdef _WIN32 + /* NSIG is not available on all platforms. */ + ASSERT(uv_kill(pid, NSIG) == UV_EINVAL); +#endif + ASSERT(uv_kill(pid, 4096) == UV_EINVAL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +/* For Windows we test only signum handling */ +#ifdef _WIN32 +static void signum_test_cb(uv_signal_t* handle, int signum) { + FATAL("signum_test_cb should not be called"); +} + +TEST_IMPL(win32_signum_number) { + uv_signal_t signal; + uv_loop_t* loop; + + loop = uv_default_loop(); + uv_signal_init(loop, &signal); + + ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0); + ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); + ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); + MAKE_VALGRIND_HAPPY(); + return 0; +} +#else +#include +#include +#include +#include +#include +#include +#include + +#define NSIGNALS 10 + +struct timer_ctx { + unsigned int ncalls; + uv_timer_t handle; + int signum; +}; + +struct signal_ctx { + enum { CLOSE, STOP, NOOP } stop_or_close; + unsigned int ncalls; + uv_signal_t handle; + int signum; + int one_shot; +}; + + +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 signal_cb_one_shot(uv_signal_t* handle, int signum) { + struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); + ASSERT(signum == ctx->signum); + ASSERT(++ctx->ncalls == 1); + if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); +} + + +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, + int one_shot) { + ctx->ncalls = 0; + ctx->signum = signum; + ctx->stop_or_close = CLOSE; + ctx->one_shot = one_shot; + ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + if (one_shot) + ASSERT(0 == uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); + else + 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, 0); + 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, 0); + start_watcher(loop, SIGUSR1, sc + 1, 0); + start_watcher(loop, SIGUSR2, sc + 2, 0); + start_watcher(loop, SIGUSR2, sc + 3, 0); + 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; +} + +TEST_IMPL(we_get_signal_one_shot) { + 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, 1); + sc.stop_or_close = NOOP; + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == 1); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(sc.ncalls == 1); + + sc.ncalls = 0; + sc.stop_or_close = CLOSE; /* now close it when it's done */ + uv_signal_start_oneshot(&sc.handle, signal_cb_one_shot, SIGCHLD); + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(we_get_signals_mixed) { + struct signal_ctx sc[4]; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + + /* 2 one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + start_watcher(loop, SIGCHLD, sc + 1, 1); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 1); + ASSERT(sc[1].ncalls == 1); + + /* 2 one-shot, 1 normal then remove normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + start_watcher(loop, SIGCHLD, sc + 1, 1); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + start_watcher(loop, SIGCHLD, sc + 2, 0); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 1); + ASSERT(sc[1].ncalls == 1); + ASSERT(sc[2].ncalls == 0); + + /* 2 normal, 1 one-shot then remove one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + sc[0].stop_or_close = CLOSE; + sc[1].stop_or_close = CLOSE; + start_watcher(loop, SIGCHLD, sc + 2, 1); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == NSIGNALS); + ASSERT(sc[1].ncalls == NSIGNALS); + ASSERT(sc[2].ncalls == 0); + + /* 2 normal, 2 one-shot then remove 2 normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + start_watcher(loop, SIGCHLD, sc + 2, 1); + start_watcher(loop, SIGCHLD, sc + 3, 1); + sc[2].stop_or_close = CLOSE; + sc[3].stop_or_close = CLOSE; + uv_close((uv_handle_t*)&(sc[0]).handle, NULL); + uv_close((uv_handle_t*)&(sc[1]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 0); + ASSERT(sc[1].ncalls == 0); + ASSERT(sc[2].ncalls == 1); + ASSERT(sc[2].ncalls == 1); + + /* 1 normal, 1 one-shot, 2 normal then remove 1st normal, 2nd normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 1); + start_watcher(loop, SIGCHLD, sc + 2, 0); + start_watcher(loop, SIGCHLD, sc + 3, 0); + sc[3].stop_or_close = CLOSE; + uv_close((uv_handle_t*)&(sc[0]).handle, NULL); + uv_close((uv_handle_t*)&(sc[2]).handle, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc[0].ncalls == 0); + ASSERT(sc[1].ncalls == 1); + ASSERT(sc[2].ncalls == 0); + ASSERT(sc[3].ncalls == NSIGNALS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* _WIN32 */ diff --git a/3rd/libuv-1.19.2/test/test-socket-buffer-size.c b/3rd/libuv-1.19.2/test/test-socket-buffer-size.c new file mode 100644 index 00000000..72f8c252 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-spawn.c b/3rd/libuv-1.19.2/test/test-spawn.c new file mode 100644 index 00000000..4a2869a1 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-spawn.c @@ -0,0 +1,1875 @@ + +/* 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 +#include +#include +#include +#include + +#ifdef _WIN32 +# if defined(__MINGW32__) +# include +# endif +# include +# include +#else +# include +# include +#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[5]; +static int no_term_signal; +static int timer_counter; +static uv_tcp_t tcp_server; + +#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 +#if defined(__APPLE__) || defined(__MVS__) + /* + * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a + * process that is still starting up kills it with SIGKILL instead of SIGTERM. + * See: https://github.com/libuv/libuv/issues/1226 + */ + ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL); +#else + ASSERT(no_term_signal || term_signal == SIGTERM); +#endif + 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; + args[3] = NULL; + args[4] = 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*)∈ + 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; +} + + +int spawn_tcp_server_helper(void) { + uv_tcp_t tcp; + uv_os_sock_t handle; + int r; + + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT(r == 0); + +#ifdef _WIN32 + handle = _get_osfhandle(3); +#else + handle = 3; +#endif + r = uv_tcp_open(&tcp, handle); + ASSERT(r == 0); + + /* Make sure that we can listen on a socket that was + * passed down from the parent process + */ + r = uv_listen((uv_stream_t*)&tcp, SOMAXCONN, NULL); + ASSERT(r == 0); + + return 1; +} + + +TEST_IMPL(spawn_tcp_server) { + uv_stdio_container_t stdio[4]; + struct sockaddr_in addr; + int fd; + int r; +#ifdef _WIN32 + uv_os_fd_t handle; +#endif + + init_process_options("spawn_tcp_server_helper", exit_cb); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + fd = -1; + r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET); + ASSERT(r == 0); + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); +#ifdef _WIN32 + r = uv_fileno((uv_handle_t*)&tcp_server, &handle); + fd = _open_osfhandle((intptr_t) handle, 0); +#else + r = uv_fileno((uv_handle_t*)&tcp_server, &fd); + #endif + ASSERT(r == 0); + ASSERT(fd > 0); + + options.stdio = stdio; + options.stdio[0].flags = UV_INHERIT_FD; + options.stdio[0].data.fd = 0; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = 1; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = 2; + options.stdio[3].flags = UV_INHERIT_FD; + options.stdio[3].data.fd = fd; + options.stdio_count = 4; + + 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_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); + + ASSERT(process.pid == uv_process_get_pid(&process)); + + 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*)∈ + 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*)∈ + 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*)∈ + 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*) ∈ + 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); + + /* Verify that uv_spawn() resets the signal disposition. */ +#ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL)); + } + ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); +#endif + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + +#ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); + } + ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); +#endif + + /* 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; + char uidstr[10]; + char gidstr[10]; + + /* if not root, then this will fail. */ + uv_uid_t uid = getuid(); + if (uid != 0) { + RETURN_SKIP("It should be run as root user"); + } + + init_process_options("spawn_helper_setuid_setgid", exit_cb); + + /* become the "nobody" user. */ + pw = getpwnam("nobody"); + ASSERT(pw != NULL); + options.uid = pw->pw_uid; + options.gid = pw->pw_gid; + snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); + snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); + options.args[2] = uidstr; + options.args[3] = gidstr; + 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); +#if defined(__CYGWIN__) + ASSERT(r == UV_EINVAL); +#else + ASSERT(r == UV_EPERM); +#endif + + 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; +#if defined(__MVS__) + options.gid = -1; +#else + options.gid = 0; +#endif + + r = uv_spawn(uv_default_loop(), &process, &options); +#if defined(__CYGWIN__) || defined(__MVS__) + ASSERT(r == UV_EINVAL); +#else + ASSERT(r == UV_EPERM); +#endif + + 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*) ∈ + 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"; +#elif defined __MVS__ + static const char dyld_path_var[] = "LIBPATH"; +#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); +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Carry over the dynamic linker path in case the test runner + is linked against cyguv-1.dll or msys-uv-1.dll, see above. */ + { + char* syspath = getenv("PATH"); + if (syspath != NULL) { + strcat(path, ":"); + strcat(path, syspath); + } + } +#endif + + 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; +} + +TEST_IMPL(spawn_quoted_path) { +#ifndef _WIN32 + RETURN_SKIP("Test for Windows"); +#else + char* quoted_path_env[2]; + args[0] = "not_existing"; + args[1] = NULL; + options.file = args[0]; + options.args = args; + options.exit_cb = exit_cb; + options.flags = 0; + /* We test if search_path works correctly with semicolons in quoted path. */ + /* We will use invalid drive, so we are sure no executable is spawned */ + quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; + quoted_path_env[1] = NULL; + options.env = quoted_path_env; + + /* We test if libuv will not segfault. */ + uv_spawn(uv_default_loop(), &process, &options); + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + +/* 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/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c b/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c new file mode 100644 index 00000000..15744761 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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*)∈ + 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/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c new file mode 100644 index 00000000..61ca667a --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c @@ -0,0 +1,123 @@ +/* Copyright 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 +#include +#include + +#include "uv.h" +#include "task.h" + +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 uv_write_t write_req; + +static char hello[] = "HELLO!"; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); +} + +static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + /* Do nothing, read_cb should be called with UV_ENOBUFS. */ +} + +static void conn_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == UV_ENOBUFS); + ASSERT(buf->base == NULL); + ASSERT(buf->len == 0); + + uv_close((uv_handle_t*) &incoming, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &server, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t buf; + + ASSERT(status == 0); + connect_cb_called++; + + buf = uv_buf_init(hello, sizeof(hello)); + r = uv_write(&write_req, 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)); + ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, + conn_alloc_cb, + conn_read_cb)); + + 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_alloc_cb_fail) { + 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(connection_cb_called == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-bind-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind-error.c new file mode 100644 index 00000000..10ed68e1 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c b/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c new file mode 100644 index 00000000..b762bcb3 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-close-accept.c b/3rd/libuv-1.19.2/test/test-tcp-close-accept.c new file mode 100644 index 00000000..e4878398 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-close-accept.c @@ -0,0 +1,194 @@ +/* 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 +#include + +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 unsigned int pending_incoming; + +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); + + /* + * Time to finish the test: close both the check and pending incoming + * connections + */ + uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], 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; + + pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; + ASSERT(pending_incoming < got_connections); + ASSERT(0 == uv_read_stop(stream)); + ASSERT(1 == nread); + + loop = stream->loop; + read_cb_called++; + + /* Close all active incomings, except current one */ + for (i = 0; i < got_connections; i++) { + if (i != pending_incoming) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + } + + /* Close server, so no one will connect to it */ + uv_close((uv_handle_t*) &tcp_server, 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)); +} + +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/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c b/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c new file mode 100644 index 00000000..8d0b8270 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c @@ -0,0 +1,97 @@ +/* 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 int netunreach_errors; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void connect_cb(uv_connect_t* req, int status) { + /* The expected error is UV_ECANCELED but the test tries to connect to what + * is basically an arbitrary address in the expectation that no network path + * exists, so UV_ENETUNREACH is an equally plausible outcome. + */ + ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH); + uv_timer_stop(&timer2_handle); + connect_cb_called++; + if (status == UV_ENETUNREACH) + netunreach_errors++; +} + + +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, 1, 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(); + + if (netunreach_errors > 0) + RETURN_SKIP("Network unreachable."); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-close.c b/3rd/libuv-1.19.2/test/test-tcp-close.c new file mode 100644 index 00000000..e65885aa --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include /* 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/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c new file mode 100644 index 00000000..3f2e3572 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-tcp-connect-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect-error.c new file mode 100644 index 00000000..eab1eeb2 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c b/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c new file mode 100644 index 00000000..081424b8 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c b/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c new file mode 100644 index 00000000..91ac0a3a --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c new file mode 100644 index 00000000..b87e7324 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 + +#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; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + 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); +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) + 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/3rd/libuv-1.19.2/test/test-tcp-flags.c b/3rd/libuv-1.19.2/test/test-tcp-flags.c new file mode 100644 index 00000000..68afb39f --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + + +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/3rd/libuv-1.19.2/test/test-tcp-oob.c b/3rd/libuv-1.19.2/test/test-tcp-oob.c new file mode 100644 index 00000000..4f1397a8 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-oob.c @@ -0,0 +1,141 @@ +/* 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 +#include +#include + +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) { +#ifdef __MVS__ + char lbuf[12]; +#endif + uv_os_fd_t fd; + + ASSERT(nread > 0); + ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + ASSERT(0 == uv_idle_start(&idle, idle_cb)); + +#ifdef __MVS__ + /* Need to flush out the OOB data. Otherwise, this callback will get + * triggered on every poll with nread = 0. + */ + ASSERT(-1 != recv(fd, lbuf, sizeof(lbuf), MSG_OOB)); +#endif +} + + +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/3rd/libuv-1.19.2/test/test-tcp-open.c b/3rd/libuv-1.19.2/test/test-tcp-open.c new file mode 100644 index 00000000..cb74c50e --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-open.c @@ -0,0 +1,277 @@ +/* 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 +#include +#include + +#ifndef _WIN32 +# include +#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; +} + + +TEST_IMPL(tcp_open_bound) { + struct sockaddr_in addr; + uv_tcp_t server; + uv_os_sock_t sock; + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + + ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_open(&server, sock)); + + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_open_connected) { + struct sockaddr_in addr; + uv_tcp_t client; + uv_os_sock_t sock; + uv_buf_t buf = uv_buf_init("PING", 4); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + + ASSERT(0 == uv_tcp_open(&client, sock)); + + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); + + ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); + + ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(shutdown_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tcp-read-stop.c b/3rd/libuv-1.19.2/test/test-tcp-read-stop.c new file mode 100644 index 00000000..488e8fb4 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c b/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c new file mode 100644 index 00000000..463b4b0d --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-try-write.c b/3rd/libuv-1.19.2/test/test-tcp-try-write.c new file mode 100644 index 00000000..97a1d6e3 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c b/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c new file mode 100644 index 00000000..c7b98145 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c b/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c new file mode 100644 index 00000000..aa03228f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-tcp-write-fail.c b/3rd/libuv-1.19.2/test/test-tcp-write-fail.c new file mode 100644 index 00000000..5256a9f4 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#ifndef _WIN32 +# include +#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/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c b/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c new file mode 100644 index 00000000..5119be6d --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c @@ -0,0 +1,139 @@ +/* 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 +#include +#include + +#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++; +} + +static 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); +} + +static 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)); + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb, 1, 0)); + + 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; + int buffer_size = 16 * 1024; + + 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_send_buffer_size((uv_handle_t*) &client, &buffer_size)); + + 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/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c b/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c new file mode 100644 index 00000000..2fa2ae72 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +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/3rd/libuv-1.19.2/test/test-tcp-writealot.c b/3rd/libuv-1.19.2/test/test-tcp-writealot.c new file mode 100644 index 00000000..7206fdc2 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tcp-writealot.c @@ -0,0 +1,180 @@ +/* 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 +#include + + +#define WRITES 3 +#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ +#define CHUNKS_PER_WRITE 2048 +#else +#define CHUNKS_PER_WRITE 4096 +#endif +#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/3rd/libuv-1.19.2/test/test-thread-equal.c b/3rd/libuv-1.19.2/test/test-thread-equal.c new file mode 100644 index 00000000..27c07ee2 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-thread.c b/3rd/libuv-1.19.2/test/test-thread.c new file mode 100644 index 00000000..955c9f2f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-thread.c @@ -0,0 +1,232 @@ +/* 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 +#include +#include /* 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; + 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 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[4]; + struct fs_req fs_reqs[4]; + uv_loop_t loop; + size_t i; + struct test_thread* thread = arg; + + ASSERT(0 == uv_loop_init(&loop)); + + for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { + struct getaddrinfo_req* req = getaddrinfo_reqs + i; + req->counter = 4; + req->loop = &loop; + getaddrinfo_do(req); + } + + for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { + struct fs_req* req = fs_reqs + i; + req->counter = 4; + req->loop = &loop; + fs_do(req); + } + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_loop_close(&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 == 1); + } + + 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; +} + + +static void thread_check_stack(void* arg) { +#if defined(__APPLE__) + /* 512 kB is the default stack size of threads other than the main thread + * on MacOS. */ + ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); +#elif defined(__linux__) && defined(__GLIBC__) + struct rlimit lim; + size_t stack_size; + pthread_attr_t attr; + ASSERT(0 == getrlimit(RLIMIT_STACK, &lim)); + if (lim.rlim_cur == RLIM_INFINITY) + lim.rlim_cur = 2 << 20; /* glibc default. */ + ASSERT(0 == pthread_getattr_np(pthread_self(), &attr)); + ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size)); + ASSERT(stack_size >= lim.rlim_cur); +#endif +} + + +TEST_IMPL(thread_stack_size) { + uv_thread_t thread; + ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT(0 == uv_thread_join(&thread)); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-threadpool-cancel.c b/3rd/libuv-1.19.2/test/test-threadpool-cancel.c new file mode 100644 index 00000000..dd13d8ae --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-threadpool-cancel.c @@ -0,0 +1,308 @@ +/* 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 unsigned fs_cb_called; +static unsigned done_cb_called; +static unsigned done2_cb_called; +static unsigned timer_cb_called; +static uv_work_t pause_reqs[4]; +static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)]; + + +static void work_cb(uv_work_t* req) { + uv_sem_wait(pause_sems + (req - pause_reqs)); +} + + +static void done_cb(uv_work_t* req, int status) { + uv_sem_destroy(pause_sems + (req - pause_reqs)); +} + + +static void saturate_threadpool(void) { + uv_loop_t* loop; + char buf[64]; + size_t i; + + snprintf(buf, + sizeof(buf), + "UV_THREADPOOL_SIZE=%lu", + (unsigned long)ARRAY_SIZE(pause_reqs)); + putenv(buf); + + loop = uv_default_loop(); + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) { + ASSERT(0 == uv_sem_init(pause_sems + i, 0)); + ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); + } +} + + +static void unblock_threadpool(void) { + size_t i; + + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) + uv_sem_post(pause_sems + i); +} + + +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_done_cb(uv_work_t* req, int status) { + ASSERT(status == UV_ECANCELED); + done_cb_called++; +} + + +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); + + 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); + + 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); + + 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); + + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(threadpool_cancel_single) { + uv_loop_t* loop; + uv_work_t req; + + saturate_threadpool(); + loop = uv_default_loop(); + ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); + ASSERT(0 == uv_cancel((uv_req_t*) &req)); + ASSERT(0 == done_cb_called); + unblock_threadpool(); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == done_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-threadpool.c b/3rd/libuv-1.19.2/test/test-threadpool.c new file mode 100644 index 00000000..e3d17d75 --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer-again.c b/3rd/libuv-1.19.2/test/test-timer-again.c new file mode 100644 index 00000000..f93c509b --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer-from-check.c b/3rd/libuv-1.19.2/test/test-timer-from-check.c new file mode 100644 index 00000000..a18c7e1f --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/test/test-timer.c b/3rd/libuv-1.19.2/test/test-timer.c new file mode 100644 index 00000000..080a7300 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-timer.c @@ -0,0 +1,330 @@ +/* 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; +} + + +static uint64_t timer_early_check_expected_time; + + +static void timer_early_check_cb(uv_timer_t* handle) { + uint64_t hrtime = uv_hrtime() / 1000000; + ASSERT(hrtime >= timer_early_check_expected_time); +} + + +TEST_IMPL(timer_early_check) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tmpdir.c b/3rd/libuv-1.19.2/test/test-tmpdir.c new file mode 100644 index 00000000..29e8055f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tmpdir.c @@ -0,0 +1,71 @@ +/* Copyright 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. + */ + +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-tty.c b/3rd/libuv-1.19.2/test/test-tty.c new file mode 100644 index 00000000..e761822f --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-tty.c @@ -0,0 +1,390 @@ +/* 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 +# include +#else /* Unix */ +# include +# include +# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) +# include +# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# include +# elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# endif +#endif + +#include +#include + + +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; +} + + +#ifdef _WIN32 +static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + +static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + ASSERT(nread == 1); + ASSERT(buf->base[0] == ' '); + uv_close((uv_handle_t*) tty_in, NULL); + } else { + ASSERT(nread == 0); + } +} + +TEST_IMPL(tty_raw) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop = uv_default_loop(); + HANDLE handle; + INPUT_RECORD record; + DWORD written; + + /* Make sure we have an FD that refers to a tty */ + 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); + ASSERT(ttyin_fd >= 0); + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ + Sleep(100); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); + ASSERT(r == 0); + + /* Write ' ' that should be read in raw mode */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; + record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L' '; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle, &record, 1, &written); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tty_empty_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[1]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + 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); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + bufs[0].len = 0; + bufs[0].base = &dummy[0]; + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tty_large_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[10000]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + 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); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + memset(dummy, '.', sizeof(dummy) - 1); + dummy[sizeof(dummy) - 1] = '\n'; + + bufs[0] = uv_buf_init(dummy, sizeof(dummy)); + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 10000); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + +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; +} + +TEST_IMPL(tty_pty) { +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + (defined(__linux__) && !defined(__ANDROID__)) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) + int master_fd, slave_fd, r; + struct winsize w; + uv_loop_t loop; + uv_tty_t master_tty, slave_tty; + + ASSERT(0 == uv_loop_init(&loop)); + + r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); + if (r != 0) + RETURN_SKIP("No pty available, skipping."); + + ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + /* Check if the file descriptor was reopened. If it is, + * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + */ + ASSERT(0 == (slave_tty.flags & 0x80)); + /* The master_fd of a pty should never be reopened. + */ + ASSERT(master_tty.flags & 0x80); + ASSERT(0 == close(slave_fd)); + uv_close((uv_handle_t*) &slave_tty, NULL); + ASSERT(0 == close(master_fd)); + uv_close((uv_handle_t*) &master_tty, NULL); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); +#endif + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c b/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c new file mode 100644 index 00000000..05b871e9 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c @@ -0,0 +1,197 @@ +/* Copyright libuv project 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 +#include +#include + +#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 sv_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 cl_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* Do nothing, recv_cb should be called with UV_ENOBUFS. */ +} + + +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); + ASSERT(nread == UV_ENOBUFS); + + 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, cl_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)); + + 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_alloc_cb_fail) { + 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, sv_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("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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-bind.c b/3rd/libuv-1.19.2/test/test-udp-bind.c new file mode 100644 index 00000000..a1e080ee --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + + +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/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c b/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c new file mode 100644 index 00000000..f7e46abc --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2015 Saúl Ibarra Corretgé . + * 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 + +#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; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + 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); +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) + 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/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c b/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c new file mode 100644 index 00000000..bd44c425 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-ipv6.c b/3rd/libuv-1.19.2/test/test-udp-ipv6.c new file mode 100644 index 00000000..00007918 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-ipv6.c @@ -0,0 +1,198 @@ +/* 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 +#include +#include + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#include +#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; + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +static int can_ipv6_ipv4_dual(void) { + 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 defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c new file mode 100644 index 00000000..0b3c0e62 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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 || status == UV_EPERM); + 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/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c new file mode 100644 index 00000000..40b05536 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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__) || defined(__FreeBSD_kernel__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-join.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join.c new file mode 100644 index 00000000..6110a8d9 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c b/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c new file mode 100644 index 00000000..8814b5ad --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c @@ -0,0 +1,165 @@ +/* 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 +#include +#include + + +#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) || \ + defined(__MVS__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) + 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/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c b/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c new file mode 100644 index 00000000..e92608be --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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 || status == UV_EPERM); + 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/3rd/libuv-1.19.2/test/test-udp-open.c b/3rd/libuv-1.19.2/test/test-udp-open.c new file mode 100644 index 00000000..4d77f45d --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#ifndef _WIN32 +# include +#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/3rd/libuv-1.19.2/test/test-udp-options.c b/3rd/libuv-1.19.2/test/test-udp-options.c new file mode 100644 index 00000000..8f913675 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-options.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 "uv.h" +#include "task.h" + +#include +#include +#include + + +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); +#if defined(__MVS__) + if (addr->sa_family == AF_INET6) + ASSERT(r == 0); + else + ASSERT(r == UV_ENOTSUP); +#else + ASSERT(r == 0); +#endif + } + + 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)); +#if defined(__MVS__) + ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); +#else + ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); +#endif + 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/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c b/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c new file mode 100644 index 00000000..633a1672 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c b/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c new file mode 100644 index 00000000..bf4dfebf --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c @@ -0,0 +1,99 @@ +/* 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 +#include +#include + +#define CHECK_OBJECT(handle, type, parent) \ + ASSERT((type*)(handle) == &(parent)) + +static uv_udp_t client; +static uv_idle_t idle_handle; +static uv_udp_send_t send_req; +static uv_buf_t buf; +static struct sockaddr_in addr; +static char send_data[1024]; + +static int loop_hang_called; + +static void send_cb(uv_udp_send_t* req, int status); + + +static void idle_cb(uv_idle_t* handle) { + int r; + + ASSERT(send_req.handle == NULL); + CHECK_OBJECT(handle, uv_idle_t, idle_handle); + ASSERT(0 == uv_idle_stop(handle)); + + /* It probably would have stalled by now if it's going to stall at all. */ + if (++loop_hang_called > 1000) { + uv_close((uv_handle_t*) &client, NULL); + uv_close((uv_handle_t*) &idle_handle, NULL); + return; + } + + r = uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0 || status == UV_ENETUNREACH); + CHECK_OBJECT(req->handle, uv_udp_t, client); + CHECK_OBJECT(req, uv_udp_send_t, send_req); + req->handle = NULL; + + ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); +} + + +TEST_IMPL(udp_send_hang_loop) { + ASSERT(0 == uv_idle_init(uv_default_loop(), &idle_handle)); + + /* 192.0.2.0/8 is "TEST-NET" and reserved for documentation. + * Good for us, though. Since we want to have something unreachable. + */ + ASSERT(0 == uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); + + ASSERT(0 == uv_udp_init(uv_default_loop(), &client)); + + buf = uv_buf_init(send_data, sizeof(send_data)); + + ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(loop_hang_called > 1000); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/3rd/libuv-1.19.2/test/test-udp-send-immediate.c b/3rd/libuv-1.19.2/test/test-udp-send-immediate.c new file mode 100644 index 00000000..215f7225 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-send-immediate.c @@ -0,0 +1,149 @@ +/* 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 +#include +#include + +#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); + ASSERT(r == 0); + + 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/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c b/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c new file mode 100644 index 00000000..c6500320 --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include +#include + +#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/3rd/libuv-1.19.2/test/test-udp-try-send.c b/3rd/libuv-1.19.2/test/test-udp-try-send.c new file mode 100644 index 00000000..a31d3822 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-udp-try-send.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 +#include +#include + +#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; +} diff --git a/3rd/libuv-1.19.2/test/test-walk-handles.c b/3rd/libuv-1.19.2/test/test-walk-handles.c new file mode 100644 index 00000000..4b0ca6eb --- /dev/null +++ b/3rd/libuv-1.19.2/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 +#include + +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/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c b/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c new file mode 100644 index 00000000..29a82a5c --- /dev/null +++ b/3rd/libuv-1.19.2/test/test-watcher-cross-stop.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 +#include + +/* NOTE: Number should be big enough to trigger this problem */ +#if defined(__CYGWIN__) || defined(__MSYS__) +/* Cygwin crashes or hangs in socket() with too many AF_INET sockets. */ +static uv_udp_t sockets[1250]; +#else +static uv_udp_t sockets[2500]; +#endif +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) { +#if defined(__MVS__) + RETURN_SKIP("zOS does not allow address or port reuse when using UDP sockets"); +#endif + 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/3rd/libuv-1.19.2/test/test.gyp b/3rd/libuv-1.19.2/test/test.gyp new file mode 100644 index 00000000..480e5a26 --- /dev/null +++ b/3rd/libuv-1.19.2/test/test.gyp @@ -0,0 +1,279 @@ +{ + 'targets': [ + { + 'target_name': 'run-tests', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'blackhole-server.c', + 'echo-server.c', + 'run-tests.c', + 'runner.c', + 'runner.h', + 'test-get-loadavg.c', + 'task.h', + 'test-active.c', + 'test-async.c', + 'test-async-null-cb.c', + 'test-callback-stack.c', + 'test-callback-order.c', + 'test-close-fd.c', + 'test-close-order.c', + 'test-connect-unspecified.c', + 'test-connection-fail.c', + 'test-cwd-and-chdir.c', + 'test-default-loop-close.c', + 'test-delayed-accept.c', + 'test-eintr-handling.c', + 'test-error.c', + 'test-embed.c', + 'test-emfile.c', + 'test-env-vars.c', + 'test-fail-always.c', + 'test-fork.c', + 'test-fs.c', + 'test-fs-copyfile.c', + 'test-fs-event.c', + 'test-getters-setters.c', + 'test-get-currentexe.c', + 'test-get-memory.c', + 'test-get-passwd.c', + 'test-getaddrinfo.c', + 'test-gethostname.c', + 'test-getnameinfo.c', + 'test-getsockname.c', + 'test-handle-fileno.c', + 'test-homedir.c', + 'test-hrtime.c', + 'test-idle.c', + 'test-ip6-addr.c', + 'test-ipc.c', + 'test-ipc-send-recv.c', + 'test-list.h', + 'test-loop-handles.c', + 'test-loop-alive.c', + 'test-loop-close.c', + 'test-loop-stop.c', + 'test-loop-time.c', + 'test-loop-configure.c', + 'test-walk-handles.c', + 'test-watcher-cross-stop.c', + 'test-multiple-listen.c', + 'test-osx-select.c', + 'test-pass-always.c', + 'test-ping-pong.c', + 'test-pipe-bind-error.c', + 'test-pipe-connect-error.c', + 'test-pipe-connect-multiple.c', + 'test-pipe-connect-prepare.c', + 'test-pipe-getsockname.c', + 'test-pipe-pending-instances.c', + 'test-pipe-sendmsg.c', + 'test-pipe-server-close.c', + 'test-pipe-close-stdout-read-stdin.c', + 'test-pipe-set-non-blocking.c', + 'test-pipe-set-fchmod.c', + 'test-platform-output.c', + 'test-poll.c', + 'test-poll-close.c', + 'test-poll-close-doesnt-corrupt-stack.c', + 'test-poll-closesocket.c', + 'test-poll-oob.c', + 'test-process-title.c', + 'test-process-title-threadsafe.c', + 'test-queue-foreach-delete.c', + 'test-ref.c', + 'test-run-nowait.c', + 'test-run-once.c', + 'test-semaphore.c', + 'test-shutdown-close.c', + 'test-shutdown-eof.c', + 'test-shutdown-twice.c', + 'test-signal.c', + 'test-signal-multiple-loops.c', + 'test-socket-buffer-size.c', + 'test-spawn.c', + 'test-fs-poll.c', + 'test-stdio-over-pipes.c', + 'test-tcp-alloc-cb-fail.c', + 'test-tcp-bind-error.c', + 'test-tcp-bind6-error.c', + 'test-tcp-close.c', + 'test-tcp-close-accept.c', + 'test-tcp-close-while-connecting.c', + 'test-tcp-create-socket-early.c', + 'test-tcp-connect-error-after-write.c', + 'test-tcp-shutdown-after-write.c', + 'test-tcp-flags.c', + 'test-tcp-connect-error.c', + 'test-tcp-connect-timeout.c', + 'test-tcp-connect6-error.c', + 'test-tcp-open.c', + 'test-tcp-write-to-half-open-connection.c', + 'test-tcp-write-after-connect.c', + 'test-tcp-writealot.c', + 'test-tcp-write-fail.c', + 'test-tcp-try-write.c', + 'test-tcp-unexpected-read.c', + 'test-tcp-oob.c', + 'test-tcp-read-stop.c', + 'test-tcp-write-queue-order.c', + 'test-threadpool.c', + 'test-threadpool-cancel.c', + 'test-thread-equal.c', + 'test-tmpdir.c', + 'test-mutexes.c', + 'test-thread.c', + 'test-barrier.c', + 'test-condvar.c', + 'test-timer-again.c', + 'test-timer-from-check.c', + 'test-timer.c', + 'test-tty.c', + 'test-udp-alloc-cb-fail.c', + 'test-udp-bind.c', + 'test-udp-create-socket-early.c', + 'test-udp-dgram-too-big.c', + 'test-udp-ipv6.c', + 'test-udp-open.c', + 'test-udp-options.c', + 'test-udp-send-and-recv.c', + 'test-udp-send-hang-loop.c', + 'test-udp-send-immediate.c', + 'test-udp-send-unreachable.c', + 'test-udp-multicast-join.c', + 'test-udp-multicast-join6.c', + 'test-dlerror.c', + 'test-udp-multicast-ttl.c', + 'test-ip4-addr.c', + 'test-ip6-addr.c', + 'test-udp-multicast-interface.c', + 'test-udp-multicast-interface6.c', + 'test-udp-try-send.c', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ], + 'conditions': [ + [ 'OS != "zos"', { + 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], + 'xcode_settings': { + 'WARNING_CFLAGS': [ '-Wno-long-long' ] + } + }], + ]}, + ], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], + [ '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', + ], + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + + { + 'target_name': 'run-benchmarks', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'benchmark-async.c', + 'benchmark-async-pummel.c', + 'benchmark-fs-stat.c', + 'benchmark-getaddrinfo.c', + 'benchmark-list.h', + 'benchmark-loop-count.c', + 'benchmark-million-async.c', + 'benchmark-million-timers.c', + 'benchmark-multi-accept.c', + 'benchmark-ping-pongs.c', + 'benchmark-pound.c', + 'benchmark-pump.c', + 'benchmark-sizes.c', + 'benchmark-spawn.c', + 'benchmark-thread.c', + 'benchmark-tcp-write-batch.c', + 'benchmark-udp-pummel.c', + 'dns-server.c', + 'echo-server.c', + 'blackhole-server.c', + 'run-benchmarks.c', + 'runner.c', + 'runner.h', + 'task.h', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'defines': [ '_GNU_SOURCE' ], + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ] + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + ], +} diff --git a/3rd/libuv-1.19.2/tools/make_dist_html.py b/3rd/libuv-1.19.2/tools/make_dist_html.py new file mode 100644 index 00000000..7a19d3e1 --- /dev/null +++ b/3rd/libuv-1.19.2/tools/make_dist_html.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +from __future__ import print_function + +import itertools +import os +import re +import subprocess + +HTML = r''' + + + + + + + + + {groups}
+ + +''' + +GROUPS = r''' + + {groups[0]} + {groups[1]} + {groups[2]} + {groups[3]} + +''' + +GROUP = r''' + + + + + + + + {rows} +
versiontarballgpgwindows
+''' + +ROW = r''' + + +
{tag} + + + tarball + + {maybe_gpg} + {maybe_exe} + +''' + +GPG = r''' +gpg +''' + +# The binaries don't have a predictable name, link to the directory instead. +EXE = r''' +exe +''' + +def version(tag): + return map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups()) + +def major_minor(tag): + return version(tag)[:2] + +def row_for(tag): + maybe_gpg = '' + maybe_exe = '' + # We didn't start signing releases and producing Windows installers + # until v1.7.0. + if version(tag) >= version('v1.7.0'): + maybe_gpg = GPG.format(**locals()) + maybe_exe = EXE.format(**locals()) + return ROW.format(**locals()) + +def group_for(tags): + rows = ''.join(row_for(tag) for tag in tags) + return GROUP.format(rows=rows) + +# Partition in groups of |n|. +def groups_for(groups, n=4): + html = '' + groups = groups[:] + [''] * (n - 1) + while len(groups) >= n: + html += GROUPS.format(groups=groups) + groups = groups[n:] + return html + +if __name__ == '__main__': + os.chdir(os.path.dirname(__file__)) + tags = subprocess.check_output(['git', 'tag']) + tags = [tag for tag in tags.split('\n') if tag.startswith('v')] + tags.sort(key=version, reverse=True) + groups = [group_for(list(g)) for _, g in itertools.groupby(tags, major_minor)] + groups = groups_for(groups) + html = HTML.format(groups=groups).strip() + html = re.sub('>\\s+<', '><', html) + print(html) diff --git a/3rd/libuv-1.19.2/uv.gyp b/3rd/libuv-1.19.2/uv.gyp new file mode 100644 index 00000000..a5046b87 --- /dev/null +++ b/3rd/libuv-1.19.2/uv.gyp @@ -0,0 +1,355 @@ +{ + 'variables': { + 'conditions': [ + ['OS=="win"', { + 'shared_unix_defines': [ + '_LARGEFILE_SOURCE', + '_FILE_OFFSET_BITS=64', + ], + }, { + 'shared_unix_defines': [ ], + }], + ['OS in "mac ios"', { + 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], + }, { + 'shared_mac_defines': [ ], + }], + ['OS=="zos"', { + 'shared_zos_defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_UNIX03_WITHDRAWN', + '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_IPV6', + '_OPEN_MSGQ_EXT', + '_XOPEN_SOURCE_EXTENDED', + '_ALL_SOURCE', + '_LARGE_TIME_API', + '_OPEN_SYS_FILE_EXT', + '_AE_BIMODAL', + 'PATH_MAX=255' + ], + }, { + 'shared_zos_defines': [ ], + }], + ], + }, + + 'targets': [ + { + 'target_name': 'libuv', + 'type': '<(uv_library)', + 'include_dirs': [ + 'include', + 'src/', + ], + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], + 'direct_dependent_settings': { + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], + 'include_dirs': [ 'include' ], + 'conditions': [ + ['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-data-getter-setters.c', + 'src/uv-common.c', + 'src/uv-common.h', + 'src/version.c' + ], + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'WARNING_CFLAGS': [ + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], + }, + '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/detect-wakeup.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/snprintf.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', + ], + 'link_settings': { + 'libraries': [ + '-ladvapi32', + '-liphlpapi', + '-lpsapi', + '-lshell32', + '-luser32', + '-luserenv', + '-lws2_32' + ], + }, + }, { # Not Windows i.e. POSIX + '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=="zos" and uv_library=="shared_library"', { + 'ldflags': [ '-Wl,DLL' ], + }], + ['OS != "solaris" and OS != "android" and OS != "zos"', { + 'ldflags': [ '-pthread' ], + }], + ], + }, + 'conditions': [ + ['uv_library=="shared_library"', { + 'conditions': [ + ['OS=="zos"', { + 'cflags': [ '-qexportall' ], + }, { + 'cflags': [ '-fPIC' ], + }], + ], + }], + ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { + # 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 zos"', { + 'sources': [ 'src/unix/proctitle.c' ], + }], + [ 'OS != "zos"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + }], + [ '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=="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', + 'src/unix/procfs-exepath.c', + 'src/unix/sysinfo-loadavg.c', + 'src/unix/sysinfo-memory.c', + ], + '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', + 'src/unix/procfs-exepath.c', + 'src/unix/sysinfo-loadavg.c', + 'src/unix/sysinfo-memory.c', + ], + 'link_settings': { + 'libraries': [ '-ldl' ], + }, + }], + [ 'OS=="solaris"', { + 'sources': [ + 'src/unix/no-proctitle.c', + 'src/unix/sunos.c', + ], + 'defines': [ + '__EXTENSIONS__', + '_XOPEN_SOURCE=500', + ], + 'link_settings': { + 'libraries': [ + '-lkstat', + '-lnsl', + '-lsendfile', + '-lsocket', + ], + }, + }], + [ 'OS=="aix"', { + 'variables': { + 'os_name': ' Date: Sat, 17 Mar 2018 04:54:02 +0800 Subject: [PATCH 06/11] add libuv project --- 3rd/libuv-1.19.2/libuv.vcxproj | 181 +++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 3rd/libuv-1.19.2/libuv.vcxproj diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv-1.19.2/libuv.vcxproj new file mode 100644 index 00000000..c35d001c --- /dev/null +++ b/3rd/libuv-1.19.2/libuv.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {33066374-88CB-CB8D-15DA-61032886329A} + Win32Proj + libuv + true + x64 + 10.0.16299.0 + + + + StaticLibrary + + + v141 + + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\ + $(Configuration)\obj\$(ProjectName)\ + false + true + $(SolutionDir)$(Configuration)\ + $(ProjectName) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + + include;src;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + Sync + false + false + Disabled + NotUsing + WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;DEBUG;_DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + true + true + false + Level3 + + + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + + true + true + true + true + true + + + include;src;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + include;src;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + Sync + Speed + true + AnySuitable + true + true + Full + NotUsing + WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + true + true + false + Level3 + true + + + /LTCG %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + + true + true + true + true + UseLinkTimeCodeGeneration + true + true + true + + + include;src;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;NDEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- Gitee From 122cdbef2ef5ca92657609fc4fb450fc75d13ff7 Mon Sep 17 00:00:00 2001 From: thinking Date: Sat, 17 Mar 2018 05:07:55 +0800 Subject: [PATCH 07/11] up libuv MD --- 3rd/libuv-1.19.2/libuv.vcxproj | 132 +++++++++++++++++---------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv-1.19.2/libuv.vcxproj index c35d001c..a35d17a0 100644 --- a/3rd/libuv-1.19.2/libuv.vcxproj +++ b/3rd/libuv-1.19.2/libuv.vcxproj @@ -18,20 +18,20 @@ x64 10.0.16299.0 - + StaticLibrary v141 - - - + + + - + - + $(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\ $(Configuration)\obj\$(ProjectName)\ @@ -54,7 +54,7 @@ Disabled NotUsing WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;DEBUG;_DEBUG;%(PreprocessorDefinitions) - MultiThreadedDebug + MultiThreadedDebugDLL true true false @@ -64,7 +64,8 @@ $(OutDir)lib\$(ProjectName)$(TargetExt) - + + true true true @@ -91,7 +92,7 @@ Full NotUsing WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_LARGEFILE_SOURCE;_FILE_OFFSET_BITS=64;_WIN32_WINNT=0x0600;_GNU_SOURCE;NDEBUG;%(PreprocessorDefinitions) - MultiThreaded + MultiThreadedDLL true true false @@ -103,7 +104,8 @@ $(OutDir)lib\$(ProjectName)$(TargetExt) - + + true true true @@ -119,63 +121,63 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + \ No newline at end of file -- Gitee From 4134f87c2137c5203e0327454cafedf31363af94 Mon Sep 17 00:00:00 2001 From: thinking Date: Sat, 17 Mar 2018 18:58:08 +0800 Subject: [PATCH 08/11] 3rd output --- 3rd/3rd.sln | 24 ++++++++++++++++++++++++ 3rd/libuv-1.19.2/libuv.vcxproj | 6 ++++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 3rd/3rd.sln diff --git a/3rd/3rd.sln b/3rd/3rd.sln new file mode 100644 index 00000000..0f4a5e3a --- /dev/null +++ b/3rd/3rd.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2002 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv-1.19.2\libuv.vcxproj", "{33066374-88CB-CB8D-15DA-61032886329A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33066374-88CB-CB8D-15DA-61032886329A}.Debug|x86.ActiveCfg = Debug|Win32 + {33066374-88CB-CB8D-15DA-61032886329A}.Debug|x86.Build.0 = Debug|Win32 + {33066374-88CB-CB8D-15DA-61032886329A}.Release|x86.ActiveCfg = Release|Win32 + {33066374-88CB-CB8D-15DA-61032886329A}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FFA68558-7FAF-455D-83CE-7FB35A07C34A} + EndGlobalSection +EndGlobal diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv-1.19.2/libuv.vcxproj index a35d17a0..71657bf5 100644 --- a/3rd/libuv-1.19.2/libuv.vcxproj +++ b/3rd/libuv-1.19.2/libuv.vcxproj @@ -59,9 +59,10 @@ true false Level3 + $(OutDir)obj\$(ProjectName).pdb - $(OutDir)lib\$(ProjectName)$(TargetExt) + $(OutDir)$(ProjectName)$(TargetExt) @@ -98,10 +99,11 @@ false Level3 true + $(OutDir)obj\$(ProjectName).pdb /LTCG %(AdditionalOptions) - $(OutDir)lib\$(ProjectName)$(TargetExt) + $(OutDir)$(ProjectName)$(TargetExt) -- Gitee From c04b10335ad3447039e7a585c22594e96e0a7257 Mon Sep 17 00:00:00 2001 From: thinking Date: Sat, 17 Mar 2018 23:02:52 +0800 Subject: [PATCH 09/11] add filter file --- .gitignore | 183 ++++++++++++++++++++++-------------------- CMakeLists.txt | 6 +- asynio/CMakeLists.txt | 6 +- 3 files changed, 101 insertions(+), 94 deletions(-) diff --git a/.gitignore b/.gitignore index 6d82aa60..7066f223 100644 --- a/.gitignore +++ b/.gitignore @@ -1,88 +1,95 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Libraries -*.lib -*.a -*.la -*.lo - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake - +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Libraries +*.lib +*.a +*.la +*.lo + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp +*.suo +*.opendb +*.ipch +*.log +*.VC.db + +# Precompiled Headers +*.gch +*.pch + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake + +#lbyc file +main diff --git a/CMakeLists.txt b/CMakeLists.txt index 56b40f74..f3cf98f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,20 +5,16 @@ cmake_minimum_required(VERSION 2.8) if(CMAKE_BUILD_TYPE STREQUAL Release) set(CMAKE_BUILD_TYPE Release) message("Release Compile Project") - set(by3rd_library_output "${PROJECT_SOURCE_DIR}/3rd/lib" CACHE INTERNAL "3rd Library" ) - set(by3rd_library_execute "${PROJECT_SOURCE_DIR}/3rdexecute/release" CACHE INTERNAL "3rd execute" ) else() set(CMAKE_BUILD_TYPE Debug) add_definitions(-DDEBUG) message("Debug Compile Project") - set(by3rd_library_output "${PROJECT_SOURCE_DIR}/3rd/lib" CACHE INTERNAL "3rd Library" ) - set(by3rd_library_execute "${PROJECT_SOURCE_DIR}/3rd/3rdexecute/debug" CACHE INTERNAL "3rd execute" ) endif() set(by3rd_library_include "${PROJECT_SOURCE_DIR}/3rd/include" CACHE INTERNAL "3rd include" ) -set(bycom "${PROJECT_SOURCE_DIR}" CACHE INTERNAL "bycom" ) + if (CMAKE_SYSTEM_NAME MATCHES "Android") diff --git a/asynio/CMakeLists.txt b/asynio/CMakeLists.txt index 2e36f0bb..ef422f98 100644 --- a/asynio/CMakeLists.txt +++ b/asynio/CMakeLists.txt @@ -17,12 +17,16 @@ if (${UNIX_OS}) /opt/local/include /usr/include ) + link_directories(/opt/local/lib) elseif (${WIN_OS}) else() endif() + + + set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) add_library(asynio SHARED ${asynio_src}) @@ -39,8 +43,8 @@ if(CMAKE_BUILD_TYPE STREQUAL Release) set_target_properties(asynio PROPERTIES COMPILE_FLAGS "-O3") endif() - target_link_libraries(asynio dl) +target_link_libraries(asynio libuv.a) install(TARGETS asynio LIBRARY DESTINATION bin -- Gitee From bafd17a3ed70757008e4a6e315024803033c3147 Mon Sep 17 00:00:00 2001 From: ThinkingT Date: Sat, 17 Mar 2018 23:07:09 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E7=9B=AE?= =?UTF-8?q?=E5=BD=953rd/libuv-1.19.2=E4=B8=BA3rd/libuv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.github/ISSUE_TEMPLATE.md | 0 3rd/{libuv-1.19.2 => libuv}/.gitignore | 0 3rd/{libuv-1.19.2 => libuv}/.mailmap | 0 3rd/{libuv-1.19.2 => libuv}/AUTHORS | 0 3rd/{libuv-1.19.2 => libuv}/CONTRIBUTING.md | 0 3rd/{libuv-1.19.2 => libuv}/ChangeLog | 0 3rd/{libuv-1.19.2 => libuv}/LICENSE | 0 3rd/{libuv-1.19.2 => libuv}/LICENSE-docs | 0 3rd/{libuv-1.19.2 => libuv}/MAINTAINERS.md | 0 3rd/{libuv-1.19.2 => libuv}/Makefile.am | 0 3rd/{libuv-1.19.2 => libuv}/Makefile.mingw | 0 3rd/{libuv-1.19.2 => libuv}/README.md | 0 3rd/{libuv-1.19.2 => libuv}/SUPPORTED_PLATFORMS.md | 0 3rd/{libuv-1.19.2 => libuv}/android-configure | 0 3rd/{libuv-1.19.2 => libuv}/appveyor.yml | 0 3rd/{libuv-1.19.2 => libuv}/autogen.sh | 0 3rd/{libuv-1.19.2 => libuv}/checksparse.sh | 0 3rd/{libuv-1.19.2 => libuv}/common.gypi | 0 3rd/{libuv-1.19.2 => libuv}/configure.ac | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/cgi/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/cgi/tick.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/detach/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/dns/main.c | 0 .../docs/code/helloworld/main.c | 0 .../docs/code/idle-basic/main.c | 0 .../docs/code/idle-compute/main.c | 0 .../docs/code/interfaces/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/locks/main.c | 0 .../docs/code/multi-echo-server/hammer.js | 0 .../docs/code/multi-echo-server/main.c | 0 .../docs/code/multi-echo-server/worker.c | 0 .../docs/code/onchange/main.c | 0 .../docs/code/pipe-echo-server/main.c | 0 .../docs/code/plugin/hello.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/plugin/main.c | 0 .../docs/code/plugin/plugin.h | 0 .../docs/code/proc-streams/main.c | 0 .../docs/code/proc-streams/test.c | 0 .../docs/code/progress/main.c | 0 .../docs/code/queue-cancel/main.c | 0 .../docs/code/queue-work/main.c | 0 .../docs/code/ref-timer/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/signal/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/spawn/main.c | 0 .../docs/code/tcp-echo-server/main.c | 0 .../docs/code/thread-create/main.c | 0 .../docs/code/tty-gravity/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/tty/main.c | 0 .../docs/code/udp-dhcp/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/uvcat/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/uvstop/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/uvtee/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/code/uvwget/main.c | 0 3rd/{libuv-1.19.2 => libuv}/docs/make.bat | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/api.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/async.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/check.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/conf.py | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/design.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/dll.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/dns.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/errors.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/fs.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/fs_event.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/fs_poll.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/guide.rst | 0 .../docs/src/guide/about.rst | 0 .../docs/src/guide/basics.rst | 0 .../docs/src/guide/eventloops.rst | 0 .../docs/src/guide/filesystem.rst | 0 .../docs/src/guide/introduction.rst | 0 .../docs/src/guide/networking.rst | 0 .../docs/src/guide/processes.rst | 0 .../docs/src/guide/threads.rst | 0 .../docs/src/guide/utilities.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/handle.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/idle.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/index.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/loop.rst | 0 .../docs/src/migration_010_100.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/misc.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/pipe.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/poll.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/prepare.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/process.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/request.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/signal.rst | 0 .../docs/src/sphinx-plugins/manpage.py | 0 .../docs/src/static/architecture.png | Bin .../docs/src/static/diagrams.key/Data/st0-311.jpg | Bin .../docs/src/static/diagrams.key/Data/st1-475.jpg | Bin .../docs/src/static/diagrams.key/Index.zip | Bin .../diagrams.key/Metadata/BuildVersionHistory.plist | 0 .../static/diagrams.key/Metadata/DocumentIdentifier | 0 .../static/diagrams.key/Metadata/Properties.plist | Bin .../docs/src/static/diagrams.key/preview-micro.jpg | Bin .../docs/src/static/diagrams.key/preview-web.jpg | Bin .../docs/src/static/diagrams.key/preview.jpg | Bin .../docs/src/static/favicon.ico | Bin .../docs/src/static/logo.png | Bin .../docs/src/static/loop_iteration.png | Bin 3rd/{libuv-1.19.2 => libuv}/docs/src/stream.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/tcp.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/threading.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/threadpool.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/timer.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/tty.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/udp.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/upgrading.rst | 0 3rd/{libuv-1.19.2 => libuv}/docs/src/version.rst | 0 3rd/{libuv-1.19.2 => libuv}/gyp_uv.py | 0 3rd/{libuv-1.19.2 => libuv}/img/banner.png | Bin 3rd/{libuv-1.19.2 => libuv}/img/logos.svg | 0 .../include/android-ifaddrs.h | 0 .../include/pthread-barrier.h | 0 .../include/stdint-msvc2008.h | 0 3rd/{libuv-1.19.2 => libuv}/include/tree.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-aix.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-bsd.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-darwin.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-errno.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-linux.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-os390.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-posix.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-sunos.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-threadpool.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-unix.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-version.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv-win.h | 0 3rd/{libuv-1.19.2 => libuv}/include/uv.h | 0 3rd/{libuv-1.19.2 => libuv}/libuv.pc.in | 0 3rd/{libuv-1.19.2 => libuv}/libuv.vcxproj | 0 3rd/{libuv-1.19.2 => libuv}/m4/.gitignore | 0 3rd/{libuv-1.19.2 => libuv}/m4/as_case.m4 | 0 3rd/{libuv-1.19.2 => libuv}/m4/libuv-check-flags.m4 | 0 3rd/{libuv-1.19.2 => libuv}/samples/.gitignore | 0 .../samples/socks5-proxy/.gitignore | 0 .../samples/socks5-proxy/LICENSE | 0 .../samples/socks5-proxy/build.gyp | 0 .../samples/socks5-proxy/client.c | 0 .../samples/socks5-proxy/defs.h | 0 .../samples/socks5-proxy/getopt.c | 0 .../samples/socks5-proxy/main.c | 0 .../samples/socks5-proxy/s5.c | 0 .../samples/socks5-proxy/s5.h | 0 .../samples/socks5-proxy/server.c | 0 .../samples/socks5-proxy/util.c | 0 3rd/{libuv-1.19.2 => libuv}/src/fs-poll.c | 0 3rd/{libuv-1.19.2 => libuv}/src/heap-inl.h | 0 3rd/{libuv-1.19.2 => libuv}/src/inet.c | 0 3rd/{libuv-1.19.2 => libuv}/src/queue.h | 0 3rd/{libuv-1.19.2 => libuv}/src/threadpool.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/aix-common.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/aix.c | 0 .../src/unix/android-ifaddrs.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/async.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/atomic-ops.h | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/bsd-ifaddrs.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/core.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/cygwin.c | 0 .../src/unix/darwin-proctitle.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/darwin.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/dl.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/freebsd.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/fs.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/fsevents.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/getaddrinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/getnameinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/ibmi.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/internal.h | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/kqueue.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/linux-core.c | 0 .../src/unix/linux-inotify.c | 0 .../src/unix/linux-syscalls.c | 0 .../src/unix/linux-syscalls.h | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/loop-watcher.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/loop.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/netbsd.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/no-fsevents.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/no-proctitle.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/openbsd.c | 0 .../src/unix/os390-syscalls.c | 0 .../src/unix/os390-syscalls.h | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/os390.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/pipe.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/poll.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/posix-hrtime.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/posix-poll.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/process.c | 0 .../src/unix/procfs-exepath.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/proctitle.c | 0 .../src/unix/pthread-fixes.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/signal.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/spinlock.h | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/stream.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/sunos.c | 0 .../src/unix/sysinfo-loadavg.c | 0 .../src/unix/sysinfo-memory.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/tcp.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/thread.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/timer.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/tty.c | 0 3rd/{libuv-1.19.2 => libuv}/src/unix/udp.c | 0 3rd/{libuv-1.19.2 => libuv}/src/uv-common.c | 0 3rd/{libuv-1.19.2 => libuv}/src/uv-common.h | 0 .../src/uv-data-getter-setters.c | 0 3rd/{libuv-1.19.2 => libuv}/src/version.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/async.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/atomicops-inl.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/core.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/detect-wakeup.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/dl.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/error.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/fs-event.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/fs.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/getaddrinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/getnameinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/handle-inl.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/handle.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/internal.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/loop-watcher.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/pipe.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/poll.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/process-stdio.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/process.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/req-inl.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/req.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/signal.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/snprintf.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/stream-inl.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/stream.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/tcp.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/thread.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/timer.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/tty.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/udp.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/util.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/winapi.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/winapi.h | 0 3rd/{libuv-1.19.2 => libuv}/src/win/winsock.c | 0 3rd/{libuv-1.19.2 => libuv}/src/win/winsock.h | 0 .../test/benchmark-async-pummel.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-async.c | 0 .../test/benchmark-fs-stat.c | 0 .../test/benchmark-getaddrinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-list.h | 0 .../test/benchmark-loop-count.c | 0 .../test/benchmark-million-async.c | 0 .../test/benchmark-million-timers.c | 0 .../test/benchmark-multi-accept.c | 0 .../test/benchmark-ping-pongs.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-pound.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-pump.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-sizes.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-spawn.c | 0 .../test/benchmark-tcp-write-batch.c | 0 3rd/{libuv-1.19.2 => libuv}/test/benchmark-thread.c | 0 .../test/benchmark-udp-pummel.c | 0 3rd/{libuv-1.19.2 => libuv}/test/blackhole-server.c | 0 3rd/{libuv-1.19.2 => libuv}/test/dns-server.c | 0 3rd/{libuv-1.19.2 => libuv}/test/echo-server.c | 0 .../test/fixtures/empty_file | 0 .../test/fixtures/load_error.node | 0 3rd/{libuv-1.19.2 => libuv}/test/run-benchmarks.c | 0 3rd/{libuv-1.19.2 => libuv}/test/run-tests.c | 0 3rd/{libuv-1.19.2 => libuv}/test/runner-unix.c | 0 3rd/{libuv-1.19.2 => libuv}/test/runner-unix.h | 0 3rd/{libuv-1.19.2 => libuv}/test/runner-win.c | 0 3rd/{libuv-1.19.2 => libuv}/test/runner-win.h | 0 3rd/{libuv-1.19.2 => libuv}/test/runner.c | 0 3rd/{libuv-1.19.2 => libuv}/test/runner.h | 0 3rd/{libuv-1.19.2 => libuv}/test/task.h | 0 3rd/{libuv-1.19.2 => libuv}/test/test-active.c | 0 .../test/test-async-null-cb.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-async.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-barrier.c | 0 .../test/test-callback-order.c | 0 .../test/test-callback-stack.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-close-fd.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-close-order.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-condvar.c | 0 .../test/test-connect-unspecified.c | 0 .../test/test-connection-fail.c | 0 .../test/test-cwd-and-chdir.c | 0 .../test/test-default-loop-close.c | 0 .../test/test-delayed-accept.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-dlerror.c | 0 .../test/test-eintr-handling.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-embed.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-emfile.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-env-vars.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-error.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fail-always.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fork.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fs-copyfile.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fs-event.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fs-poll.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-fs.c | 0 .../test/test-get-currentexe.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-get-loadavg.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-get-memory.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-get-passwd.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-getaddrinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-gethostname.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-getnameinfo.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-getsockname.c | 0 .../test/test-getters-setters.c | 0 .../test/test-handle-fileno.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-homedir.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-hrtime.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-idle.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-ip4-addr.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-ip6-addr.c | 0 .../test/test-ipc-send-recv.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-ipc.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-list.h | 0 3rd/{libuv-1.19.2 => libuv}/test/test-loop-alive.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-loop-close.c | 0 .../test/test-loop-configure.c | 0 .../test/test-loop-handles.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-loop-stop.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-loop-time.c | 0 .../test/test-multiple-listen.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-mutexes.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-osx-select.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-pass-always.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-ping-pong.c | 0 .../test/test-pipe-bind-error.c | 0 .../test/test-pipe-close-stdout-read-stdin.c | 0 .../test/test-pipe-connect-error.c | 0 .../test/test-pipe-connect-multiple.c | 0 .../test/test-pipe-connect-prepare.c | 0 .../test/test-pipe-getsockname.c | 0 .../test/test-pipe-pending-instances.c | 0 .../test/test-pipe-sendmsg.c | 0 .../test/test-pipe-server-close.c | 0 .../test/test-pipe-set-fchmod.c | 0 .../test/test-pipe-set-non-blocking.c | 0 .../test/test-platform-output.c | 0 .../test/test-poll-close-doesnt-corrupt-stack.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-poll-close.c | 0 .../test/test-poll-closesocket.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-poll-oob.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-poll.c | 0 .../test/test-process-title-threadsafe.c | 0 .../test/test-process-title.c | 0 .../test/test-queue-foreach-delete.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-ref.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-run-nowait.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-run-once.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-semaphore.c | 0 .../test/test-shutdown-close.c | 0 .../test/test-shutdown-eof.c | 0 .../test/test-shutdown-twice.c | 0 .../test/test-signal-multiple-loops.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-signal.c | 0 .../test/test-socket-buffer-size.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-spawn.c | 0 .../test/test-stdio-over-pipes.c | 0 .../test/test-tcp-alloc-cb-fail.c | 0 .../test/test-tcp-bind-error.c | 0 .../test/test-tcp-bind6-error.c | 0 .../test/test-tcp-close-accept.c | 0 .../test/test-tcp-close-while-connecting.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-close.c | 0 .../test/test-tcp-connect-error-after-write.c | 0 .../test/test-tcp-connect-error.c | 0 .../test/test-tcp-connect-timeout.c | 0 .../test/test-tcp-connect6-error.c | 0 .../test/test-tcp-create-socket-early.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-flags.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-oob.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-open.c | 0 .../test/test-tcp-read-stop.c | 0 .../test/test-tcp-shutdown-after-write.c | 0 .../test/test-tcp-try-write.c | 0 .../test/test-tcp-unexpected-read.c | 0 .../test/test-tcp-write-after-connect.c | 0 .../test/test-tcp-write-fail.c | 0 .../test/test-tcp-write-queue-order.c | 0 .../test/test-tcp-write-to-half-open-connection.c | 0 .../test/test-tcp-writealot.c | 0 .../test/test-thread-equal.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-thread.c | 0 .../test/test-threadpool-cancel.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-threadpool.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-timer-again.c | 0 .../test/test-timer-from-check.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-timer.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tmpdir.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-tty.c | 0 .../test/test-udp-alloc-cb-fail.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-udp-bind.c | 0 .../test/test-udp-create-socket-early.c | 0 .../test/test-udp-dgram-too-big.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-udp-ipv6.c | 0 .../test/test-udp-multicast-interface.c | 0 .../test/test-udp-multicast-interface6.c | 0 .../test/test-udp-multicast-join.c | 0 .../test/test-udp-multicast-join6.c | 0 .../test/test-udp-multicast-ttl.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-udp-open.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test-udp-options.c | 0 .../test/test-udp-send-and-recv.c | 0 .../test/test-udp-send-hang-loop.c | 0 .../test/test-udp-send-immediate.c | 0 .../test/test-udp-send-unreachable.c | 0 .../test/test-udp-try-send.c | 0 .../test/test-walk-handles.c | 0 .../test/test-watcher-cross-stop.c | 0 3rd/{libuv-1.19.2 => libuv}/test/test.gyp | 0 3rd/{libuv-1.19.2 => libuv}/tools/make_dist_html.py | 0 3rd/{libuv-1.19.2 => libuv}/uv.gyp | 0 3rd/{libuv-1.19.2 => libuv}/vcbuild.bat | 0 414 files changed, 0 insertions(+), 0 deletions(-) rename 3rd/{libuv-1.19.2 => libuv}/.github/ISSUE_TEMPLATE.md (100%) rename 3rd/{libuv-1.19.2 => libuv}/.gitignore (100%) rename 3rd/{libuv-1.19.2 => libuv}/.mailmap (100%) rename 3rd/{libuv-1.19.2 => libuv}/AUTHORS (100%) rename 3rd/{libuv-1.19.2 => libuv}/CONTRIBUTING.md (100%) rename 3rd/{libuv-1.19.2 => libuv}/ChangeLog (100%) rename 3rd/{libuv-1.19.2 => libuv}/LICENSE (100%) rename 3rd/{libuv-1.19.2 => libuv}/LICENSE-docs (100%) rename 3rd/{libuv-1.19.2 => libuv}/MAINTAINERS.md (100%) rename 3rd/{libuv-1.19.2 => libuv}/Makefile.am (100%) rename 3rd/{libuv-1.19.2 => libuv}/Makefile.mingw (100%) rename 3rd/{libuv-1.19.2 => libuv}/README.md (100%) rename 3rd/{libuv-1.19.2 => libuv}/SUPPORTED_PLATFORMS.md (100%) rename 3rd/{libuv-1.19.2 => libuv}/android-configure (100%) rename 3rd/{libuv-1.19.2 => libuv}/appveyor.yml (100%) rename 3rd/{libuv-1.19.2 => libuv}/autogen.sh (100%) rename 3rd/{libuv-1.19.2 => libuv}/checksparse.sh (100%) rename 3rd/{libuv-1.19.2 => libuv}/common.gypi (100%) rename 3rd/{libuv-1.19.2 => libuv}/configure.ac (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/cgi/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/cgi/tick.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/detach/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/dns/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/helloworld/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/idle-basic/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/idle-compute/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/interfaces/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/locks/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/multi-echo-server/hammer.js (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/multi-echo-server/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/multi-echo-server/worker.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/onchange/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/pipe-echo-server/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/plugin/hello.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/plugin/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/plugin/plugin.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/proc-streams/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/proc-streams/test.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/progress/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/queue-cancel/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/queue-work/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/ref-timer/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/signal/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/spawn/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/tcp-echo-server/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/thread-create/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/tty-gravity/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/tty/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/udp-dhcp/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/uvcat/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/uvstop/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/uvtee/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/code/uvwget/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/make.bat (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/api.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/async.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/check.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/conf.py (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/design.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/dll.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/dns.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/errors.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/fs.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/fs_event.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/fs_poll.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/about.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/basics.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/eventloops.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/filesystem.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/introduction.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/networking.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/processes.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/threads.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/guide/utilities.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/handle.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/idle.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/index.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/loop.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/migration_010_100.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/misc.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/pipe.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/poll.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/prepare.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/process.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/request.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/signal.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/sphinx-plugins/manpage.py (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/architecture.png (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Data/st0-311.jpg (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Data/st1-475.jpg (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Index.zip (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Metadata/DocumentIdentifier (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/Metadata/Properties.plist (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/preview-micro.jpg (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/preview-web.jpg (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/diagrams.key/preview.jpg (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/favicon.ico (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/logo.png (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/static/loop_iteration.png (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/stream.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/tcp.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/threading.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/threadpool.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/timer.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/tty.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/udp.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/upgrading.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/docs/src/version.rst (100%) rename 3rd/{libuv-1.19.2 => libuv}/gyp_uv.py (100%) rename 3rd/{libuv-1.19.2 => libuv}/img/banner.png (100%) rename 3rd/{libuv-1.19.2 => libuv}/img/logos.svg (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/android-ifaddrs.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/pthread-barrier.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/stdint-msvc2008.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/tree.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-aix.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-bsd.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-darwin.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-errno.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-linux.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-os390.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-posix.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-sunos.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-threadpool.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-unix.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-version.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv-win.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/include/uv.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/libuv.pc.in (100%) rename 3rd/{libuv-1.19.2 => libuv}/libuv.vcxproj (100%) rename 3rd/{libuv-1.19.2 => libuv}/m4/.gitignore (100%) rename 3rd/{libuv-1.19.2 => libuv}/m4/as_case.m4 (100%) rename 3rd/{libuv-1.19.2 => libuv}/m4/libuv-check-flags.m4 (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/.gitignore (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/.gitignore (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/LICENSE (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/build.gyp (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/client.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/defs.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/getopt.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/main.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/s5.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/s5.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/server.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/samples/socks5-proxy/util.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/fs-poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/heap-inl.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/inet.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/queue.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/threadpool.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/aix-common.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/aix.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/android-ifaddrs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/async.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/atomic-ops.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/bsd-ifaddrs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/core.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/cygwin.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/darwin-proctitle.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/darwin.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/dl.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/freebsd.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/fs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/fsevents.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/getaddrinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/getnameinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/ibmi.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/internal.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/kqueue.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/linux-core.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/linux-inotify.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/linux-syscalls.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/linux-syscalls.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/loop-watcher.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/loop.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/netbsd.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/no-fsevents.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/no-proctitle.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/openbsd.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/os390-syscalls.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/os390-syscalls.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/os390.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/pipe.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/posix-hrtime.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/posix-poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/process.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/procfs-exepath.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/proctitle.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/pthread-fixes.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/signal.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/spinlock.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/stream.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/sunos.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/sysinfo-loadavg.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/sysinfo-memory.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/tcp.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/thread.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/timer.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/tty.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/unix/udp.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/uv-common.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/uv-common.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/uv-data-getter-setters.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/version.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/async.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/atomicops-inl.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/core.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/detect-wakeup.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/dl.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/fs-event.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/fs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/getaddrinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/getnameinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/handle-inl.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/handle.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/internal.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/loop-watcher.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/pipe.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/process-stdio.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/process.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/req-inl.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/req.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/signal.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/snprintf.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/stream-inl.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/stream.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/tcp.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/thread.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/timer.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/tty.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/udp.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/util.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/winapi.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/winapi.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/winsock.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/src/win/winsock.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-async-pummel.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-async.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-fs-stat.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-getaddrinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-list.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-loop-count.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-million-async.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-million-timers.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-multi-accept.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-ping-pongs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-pound.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-pump.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-sizes.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-spawn.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-tcp-write-batch.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-thread.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/benchmark-udp-pummel.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/blackhole-server.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/dns-server.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/echo-server.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/fixtures/empty_file (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/fixtures/load_error.node (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/run-benchmarks.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/run-tests.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner-unix.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner-unix.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner-win.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner-win.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/runner.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/task.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-active.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-async-null-cb.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-async.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-barrier.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-callback-order.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-callback-stack.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-close-fd.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-close-order.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-condvar.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-connect-unspecified.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-connection-fail.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-cwd-and-chdir.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-default-loop-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-delayed-accept.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-dlerror.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-eintr-handling.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-embed.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-emfile.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-env-vars.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fail-always.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fork.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fs-copyfile.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fs-event.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fs-poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-fs.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-get-currentexe.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-get-loadavg.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-get-memory.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-get-passwd.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-getaddrinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-gethostname.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-getnameinfo.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-getsockname.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-getters-setters.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-handle-fileno.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-homedir.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-hrtime.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-idle.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ip4-addr.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ip6-addr.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ipc-send-recv.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ipc.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-list.h (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-alive.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-configure.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-handles.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-stop.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-loop-time.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-multiple-listen.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-mutexes.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-osx-select.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pass-always.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ping-pong.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-bind-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-close-stdout-read-stdin.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-connect-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-connect-multiple.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-connect-prepare.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-getsockname.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-pending-instances.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-sendmsg.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-server-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-set-fchmod.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-pipe-set-non-blocking.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-platform-output.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-poll-close-doesnt-corrupt-stack.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-poll-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-poll-closesocket.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-poll-oob.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-poll.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-process-title-threadsafe.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-process-title.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-queue-foreach-delete.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-ref.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-run-nowait.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-run-once.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-semaphore.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-shutdown-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-shutdown-eof.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-shutdown-twice.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-signal-multiple-loops.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-signal.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-socket-buffer-size.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-spawn.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-stdio-over-pipes.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-alloc-cb-fail.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-bind-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-bind6-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-close-accept.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-close-while-connecting.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-close.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-connect-error-after-write.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-connect-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-connect-timeout.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-connect6-error.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-create-socket-early.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-flags.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-oob.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-open.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-read-stop.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-shutdown-after-write.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-try-write.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-unexpected-read.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-write-after-connect.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-write-fail.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-write-queue-order.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-write-to-half-open-connection.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tcp-writealot.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-thread-equal.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-thread.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-threadpool-cancel.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-threadpool.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-timer-again.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-timer-from-check.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-timer.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tmpdir.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-tty.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-alloc-cb-fail.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-bind.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-create-socket-early.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-dgram-too-big.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-ipv6.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-multicast-interface.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-multicast-interface6.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-multicast-join.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-multicast-join6.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-multicast-ttl.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-open.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-options.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-send-and-recv.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-send-hang-loop.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-send-immediate.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-send-unreachable.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-udp-try-send.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-walk-handles.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test-watcher-cross-stop.c (100%) rename 3rd/{libuv-1.19.2 => libuv}/test/test.gyp (100%) rename 3rd/{libuv-1.19.2 => libuv}/tools/make_dist_html.py (100%) rename 3rd/{libuv-1.19.2 => libuv}/uv.gyp (100%) rename 3rd/{libuv-1.19.2 => libuv}/vcbuild.bat (100%) diff --git a/3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md b/3rd/libuv/.github/ISSUE_TEMPLATE.md similarity index 100% rename from 3rd/libuv-1.19.2/.github/ISSUE_TEMPLATE.md rename to 3rd/libuv/.github/ISSUE_TEMPLATE.md diff --git a/3rd/libuv-1.19.2/.gitignore b/3rd/libuv/.gitignore similarity index 100% rename from 3rd/libuv-1.19.2/.gitignore rename to 3rd/libuv/.gitignore diff --git a/3rd/libuv-1.19.2/.mailmap b/3rd/libuv/.mailmap similarity index 100% rename from 3rd/libuv-1.19.2/.mailmap rename to 3rd/libuv/.mailmap diff --git a/3rd/libuv-1.19.2/AUTHORS b/3rd/libuv/AUTHORS similarity index 100% rename from 3rd/libuv-1.19.2/AUTHORS rename to 3rd/libuv/AUTHORS diff --git a/3rd/libuv-1.19.2/CONTRIBUTING.md b/3rd/libuv/CONTRIBUTING.md similarity index 100% rename from 3rd/libuv-1.19.2/CONTRIBUTING.md rename to 3rd/libuv/CONTRIBUTING.md diff --git a/3rd/libuv-1.19.2/ChangeLog b/3rd/libuv/ChangeLog similarity index 100% rename from 3rd/libuv-1.19.2/ChangeLog rename to 3rd/libuv/ChangeLog diff --git a/3rd/libuv-1.19.2/LICENSE b/3rd/libuv/LICENSE similarity index 100% rename from 3rd/libuv-1.19.2/LICENSE rename to 3rd/libuv/LICENSE diff --git a/3rd/libuv-1.19.2/LICENSE-docs b/3rd/libuv/LICENSE-docs similarity index 100% rename from 3rd/libuv-1.19.2/LICENSE-docs rename to 3rd/libuv/LICENSE-docs diff --git a/3rd/libuv-1.19.2/MAINTAINERS.md b/3rd/libuv/MAINTAINERS.md similarity index 100% rename from 3rd/libuv-1.19.2/MAINTAINERS.md rename to 3rd/libuv/MAINTAINERS.md diff --git a/3rd/libuv-1.19.2/Makefile.am b/3rd/libuv/Makefile.am similarity index 100% rename from 3rd/libuv-1.19.2/Makefile.am rename to 3rd/libuv/Makefile.am diff --git a/3rd/libuv-1.19.2/Makefile.mingw b/3rd/libuv/Makefile.mingw similarity index 100% rename from 3rd/libuv-1.19.2/Makefile.mingw rename to 3rd/libuv/Makefile.mingw diff --git a/3rd/libuv-1.19.2/README.md b/3rd/libuv/README.md similarity index 100% rename from 3rd/libuv-1.19.2/README.md rename to 3rd/libuv/README.md diff --git a/3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md b/3rd/libuv/SUPPORTED_PLATFORMS.md similarity index 100% rename from 3rd/libuv-1.19.2/SUPPORTED_PLATFORMS.md rename to 3rd/libuv/SUPPORTED_PLATFORMS.md diff --git a/3rd/libuv-1.19.2/android-configure b/3rd/libuv/android-configure similarity index 100% rename from 3rd/libuv-1.19.2/android-configure rename to 3rd/libuv/android-configure diff --git a/3rd/libuv-1.19.2/appveyor.yml b/3rd/libuv/appveyor.yml similarity index 100% rename from 3rd/libuv-1.19.2/appveyor.yml rename to 3rd/libuv/appveyor.yml diff --git a/3rd/libuv-1.19.2/autogen.sh b/3rd/libuv/autogen.sh similarity index 100% rename from 3rd/libuv-1.19.2/autogen.sh rename to 3rd/libuv/autogen.sh diff --git a/3rd/libuv-1.19.2/checksparse.sh b/3rd/libuv/checksparse.sh similarity index 100% rename from 3rd/libuv-1.19.2/checksparse.sh rename to 3rd/libuv/checksparse.sh diff --git a/3rd/libuv-1.19.2/common.gypi b/3rd/libuv/common.gypi similarity index 100% rename from 3rd/libuv-1.19.2/common.gypi rename to 3rd/libuv/common.gypi diff --git a/3rd/libuv-1.19.2/configure.ac b/3rd/libuv/configure.ac similarity index 100% rename from 3rd/libuv-1.19.2/configure.ac rename to 3rd/libuv/configure.ac diff --git a/3rd/libuv-1.19.2/docs/code/cgi/main.c b/3rd/libuv/docs/code/cgi/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/cgi/main.c rename to 3rd/libuv/docs/code/cgi/main.c diff --git a/3rd/libuv-1.19.2/docs/code/cgi/tick.c b/3rd/libuv/docs/code/cgi/tick.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/cgi/tick.c rename to 3rd/libuv/docs/code/cgi/tick.c diff --git a/3rd/libuv-1.19.2/docs/code/detach/main.c b/3rd/libuv/docs/code/detach/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/detach/main.c rename to 3rd/libuv/docs/code/detach/main.c diff --git a/3rd/libuv-1.19.2/docs/code/dns/main.c b/3rd/libuv/docs/code/dns/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/dns/main.c rename to 3rd/libuv/docs/code/dns/main.c diff --git a/3rd/libuv-1.19.2/docs/code/helloworld/main.c b/3rd/libuv/docs/code/helloworld/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/helloworld/main.c rename to 3rd/libuv/docs/code/helloworld/main.c diff --git a/3rd/libuv-1.19.2/docs/code/idle-basic/main.c b/3rd/libuv/docs/code/idle-basic/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/idle-basic/main.c rename to 3rd/libuv/docs/code/idle-basic/main.c diff --git a/3rd/libuv-1.19.2/docs/code/idle-compute/main.c b/3rd/libuv/docs/code/idle-compute/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/idle-compute/main.c rename to 3rd/libuv/docs/code/idle-compute/main.c diff --git a/3rd/libuv-1.19.2/docs/code/interfaces/main.c b/3rd/libuv/docs/code/interfaces/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/interfaces/main.c rename to 3rd/libuv/docs/code/interfaces/main.c diff --git a/3rd/libuv-1.19.2/docs/code/locks/main.c b/3rd/libuv/docs/code/locks/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/locks/main.c rename to 3rd/libuv/docs/code/locks/main.c diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js b/3rd/libuv/docs/code/multi-echo-server/hammer.js similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/multi-echo-server/hammer.js rename to 3rd/libuv/docs/code/multi-echo-server/hammer.js diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c b/3rd/libuv/docs/code/multi-echo-server/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/multi-echo-server/main.c rename to 3rd/libuv/docs/code/multi-echo-server/main.c diff --git a/3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c b/3rd/libuv/docs/code/multi-echo-server/worker.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/multi-echo-server/worker.c rename to 3rd/libuv/docs/code/multi-echo-server/worker.c diff --git a/3rd/libuv-1.19.2/docs/code/onchange/main.c b/3rd/libuv/docs/code/onchange/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/onchange/main.c rename to 3rd/libuv/docs/code/onchange/main.c diff --git a/3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c b/3rd/libuv/docs/code/pipe-echo-server/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/pipe-echo-server/main.c rename to 3rd/libuv/docs/code/pipe-echo-server/main.c diff --git a/3rd/libuv-1.19.2/docs/code/plugin/hello.c b/3rd/libuv/docs/code/plugin/hello.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/plugin/hello.c rename to 3rd/libuv/docs/code/plugin/hello.c diff --git a/3rd/libuv-1.19.2/docs/code/plugin/main.c b/3rd/libuv/docs/code/plugin/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/plugin/main.c rename to 3rd/libuv/docs/code/plugin/main.c diff --git a/3rd/libuv-1.19.2/docs/code/plugin/plugin.h b/3rd/libuv/docs/code/plugin/plugin.h similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/plugin/plugin.h rename to 3rd/libuv/docs/code/plugin/plugin.h diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/main.c b/3rd/libuv/docs/code/proc-streams/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/proc-streams/main.c rename to 3rd/libuv/docs/code/proc-streams/main.c diff --git a/3rd/libuv-1.19.2/docs/code/proc-streams/test.c b/3rd/libuv/docs/code/proc-streams/test.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/proc-streams/test.c rename to 3rd/libuv/docs/code/proc-streams/test.c diff --git a/3rd/libuv-1.19.2/docs/code/progress/main.c b/3rd/libuv/docs/code/progress/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/progress/main.c rename to 3rd/libuv/docs/code/progress/main.c diff --git a/3rd/libuv-1.19.2/docs/code/queue-cancel/main.c b/3rd/libuv/docs/code/queue-cancel/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/queue-cancel/main.c rename to 3rd/libuv/docs/code/queue-cancel/main.c diff --git a/3rd/libuv-1.19.2/docs/code/queue-work/main.c b/3rd/libuv/docs/code/queue-work/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/queue-work/main.c rename to 3rd/libuv/docs/code/queue-work/main.c diff --git a/3rd/libuv-1.19.2/docs/code/ref-timer/main.c b/3rd/libuv/docs/code/ref-timer/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/ref-timer/main.c rename to 3rd/libuv/docs/code/ref-timer/main.c diff --git a/3rd/libuv-1.19.2/docs/code/signal/main.c b/3rd/libuv/docs/code/signal/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/signal/main.c rename to 3rd/libuv/docs/code/signal/main.c diff --git a/3rd/libuv-1.19.2/docs/code/spawn/main.c b/3rd/libuv/docs/code/spawn/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/spawn/main.c rename to 3rd/libuv/docs/code/spawn/main.c diff --git a/3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c b/3rd/libuv/docs/code/tcp-echo-server/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/tcp-echo-server/main.c rename to 3rd/libuv/docs/code/tcp-echo-server/main.c diff --git a/3rd/libuv-1.19.2/docs/code/thread-create/main.c b/3rd/libuv/docs/code/thread-create/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/thread-create/main.c rename to 3rd/libuv/docs/code/thread-create/main.c diff --git a/3rd/libuv-1.19.2/docs/code/tty-gravity/main.c b/3rd/libuv/docs/code/tty-gravity/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/tty-gravity/main.c rename to 3rd/libuv/docs/code/tty-gravity/main.c diff --git a/3rd/libuv-1.19.2/docs/code/tty/main.c b/3rd/libuv/docs/code/tty/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/tty/main.c rename to 3rd/libuv/docs/code/tty/main.c diff --git a/3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c b/3rd/libuv/docs/code/udp-dhcp/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/udp-dhcp/main.c rename to 3rd/libuv/docs/code/udp-dhcp/main.c diff --git a/3rd/libuv-1.19.2/docs/code/uvcat/main.c b/3rd/libuv/docs/code/uvcat/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/uvcat/main.c rename to 3rd/libuv/docs/code/uvcat/main.c diff --git a/3rd/libuv-1.19.2/docs/code/uvstop/main.c b/3rd/libuv/docs/code/uvstop/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/uvstop/main.c rename to 3rd/libuv/docs/code/uvstop/main.c diff --git a/3rd/libuv-1.19.2/docs/code/uvtee/main.c b/3rd/libuv/docs/code/uvtee/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/uvtee/main.c rename to 3rd/libuv/docs/code/uvtee/main.c diff --git a/3rd/libuv-1.19.2/docs/code/uvwget/main.c b/3rd/libuv/docs/code/uvwget/main.c similarity index 100% rename from 3rd/libuv-1.19.2/docs/code/uvwget/main.c rename to 3rd/libuv/docs/code/uvwget/main.c diff --git a/3rd/libuv-1.19.2/docs/make.bat b/3rd/libuv/docs/make.bat similarity index 100% rename from 3rd/libuv-1.19.2/docs/make.bat rename to 3rd/libuv/docs/make.bat diff --git a/3rd/libuv-1.19.2/docs/src/api.rst b/3rd/libuv/docs/src/api.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/api.rst rename to 3rd/libuv/docs/src/api.rst diff --git a/3rd/libuv-1.19.2/docs/src/async.rst b/3rd/libuv/docs/src/async.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/async.rst rename to 3rd/libuv/docs/src/async.rst diff --git a/3rd/libuv-1.19.2/docs/src/check.rst b/3rd/libuv/docs/src/check.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/check.rst rename to 3rd/libuv/docs/src/check.rst diff --git a/3rd/libuv-1.19.2/docs/src/conf.py b/3rd/libuv/docs/src/conf.py similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/conf.py rename to 3rd/libuv/docs/src/conf.py diff --git a/3rd/libuv-1.19.2/docs/src/design.rst b/3rd/libuv/docs/src/design.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/design.rst rename to 3rd/libuv/docs/src/design.rst diff --git a/3rd/libuv-1.19.2/docs/src/dll.rst b/3rd/libuv/docs/src/dll.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/dll.rst rename to 3rd/libuv/docs/src/dll.rst diff --git a/3rd/libuv-1.19.2/docs/src/dns.rst b/3rd/libuv/docs/src/dns.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/dns.rst rename to 3rd/libuv/docs/src/dns.rst diff --git a/3rd/libuv-1.19.2/docs/src/errors.rst b/3rd/libuv/docs/src/errors.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/errors.rst rename to 3rd/libuv/docs/src/errors.rst diff --git a/3rd/libuv-1.19.2/docs/src/fs.rst b/3rd/libuv/docs/src/fs.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/fs.rst rename to 3rd/libuv/docs/src/fs.rst diff --git a/3rd/libuv-1.19.2/docs/src/fs_event.rst b/3rd/libuv/docs/src/fs_event.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/fs_event.rst rename to 3rd/libuv/docs/src/fs_event.rst diff --git a/3rd/libuv-1.19.2/docs/src/fs_poll.rst b/3rd/libuv/docs/src/fs_poll.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/fs_poll.rst rename to 3rd/libuv/docs/src/fs_poll.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide.rst b/3rd/libuv/docs/src/guide.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide.rst rename to 3rd/libuv/docs/src/guide.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/about.rst b/3rd/libuv/docs/src/guide/about.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/about.rst rename to 3rd/libuv/docs/src/guide/about.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/basics.rst b/3rd/libuv/docs/src/guide/basics.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/basics.rst rename to 3rd/libuv/docs/src/guide/basics.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/eventloops.rst b/3rd/libuv/docs/src/guide/eventloops.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/eventloops.rst rename to 3rd/libuv/docs/src/guide/eventloops.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/filesystem.rst b/3rd/libuv/docs/src/guide/filesystem.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/filesystem.rst rename to 3rd/libuv/docs/src/guide/filesystem.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/introduction.rst b/3rd/libuv/docs/src/guide/introduction.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/introduction.rst rename to 3rd/libuv/docs/src/guide/introduction.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/networking.rst b/3rd/libuv/docs/src/guide/networking.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/networking.rst rename to 3rd/libuv/docs/src/guide/networking.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/processes.rst b/3rd/libuv/docs/src/guide/processes.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/processes.rst rename to 3rd/libuv/docs/src/guide/processes.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/threads.rst b/3rd/libuv/docs/src/guide/threads.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/threads.rst rename to 3rd/libuv/docs/src/guide/threads.rst diff --git a/3rd/libuv-1.19.2/docs/src/guide/utilities.rst b/3rd/libuv/docs/src/guide/utilities.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/guide/utilities.rst rename to 3rd/libuv/docs/src/guide/utilities.rst diff --git a/3rd/libuv-1.19.2/docs/src/handle.rst b/3rd/libuv/docs/src/handle.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/handle.rst rename to 3rd/libuv/docs/src/handle.rst diff --git a/3rd/libuv-1.19.2/docs/src/idle.rst b/3rd/libuv/docs/src/idle.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/idle.rst rename to 3rd/libuv/docs/src/idle.rst diff --git a/3rd/libuv-1.19.2/docs/src/index.rst b/3rd/libuv/docs/src/index.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/index.rst rename to 3rd/libuv/docs/src/index.rst diff --git a/3rd/libuv-1.19.2/docs/src/loop.rst b/3rd/libuv/docs/src/loop.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/loop.rst rename to 3rd/libuv/docs/src/loop.rst diff --git a/3rd/libuv-1.19.2/docs/src/migration_010_100.rst b/3rd/libuv/docs/src/migration_010_100.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/migration_010_100.rst rename to 3rd/libuv/docs/src/migration_010_100.rst diff --git a/3rd/libuv-1.19.2/docs/src/misc.rst b/3rd/libuv/docs/src/misc.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/misc.rst rename to 3rd/libuv/docs/src/misc.rst diff --git a/3rd/libuv-1.19.2/docs/src/pipe.rst b/3rd/libuv/docs/src/pipe.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/pipe.rst rename to 3rd/libuv/docs/src/pipe.rst diff --git a/3rd/libuv-1.19.2/docs/src/poll.rst b/3rd/libuv/docs/src/poll.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/poll.rst rename to 3rd/libuv/docs/src/poll.rst diff --git a/3rd/libuv-1.19.2/docs/src/prepare.rst b/3rd/libuv/docs/src/prepare.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/prepare.rst rename to 3rd/libuv/docs/src/prepare.rst diff --git a/3rd/libuv-1.19.2/docs/src/process.rst b/3rd/libuv/docs/src/process.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/process.rst rename to 3rd/libuv/docs/src/process.rst diff --git a/3rd/libuv-1.19.2/docs/src/request.rst b/3rd/libuv/docs/src/request.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/request.rst rename to 3rd/libuv/docs/src/request.rst diff --git a/3rd/libuv-1.19.2/docs/src/signal.rst b/3rd/libuv/docs/src/signal.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/signal.rst rename to 3rd/libuv/docs/src/signal.rst diff --git a/3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py b/3rd/libuv/docs/src/sphinx-plugins/manpage.py similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/sphinx-plugins/manpage.py rename to 3rd/libuv/docs/src/sphinx-plugins/manpage.py diff --git a/3rd/libuv-1.19.2/docs/src/static/architecture.png b/3rd/libuv/docs/src/static/architecture.png similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/architecture.png rename to 3rd/libuv/docs/src/static/architecture.png diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rd/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st0-311.jpg rename to 3rd/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rd/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Data/st1-475.jpg rename to 3rd/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip b/3rd/libuv/docs/src/static/diagrams.key/Index.zip similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Index.zip rename to 3rd/libuv/docs/src/static/diagrams.key/Index.zip diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist b/3rd/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist rename to 3rd/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rd/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/DocumentIdentifier rename to 3rd/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rd/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/Metadata/Properties.plist rename to 3rd/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-micro.jpg b/3rd/libuv/docs/src/static/diagrams.key/preview-micro.jpg similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-micro.jpg rename to 3rd/libuv/docs/src/static/diagrams.key/preview-micro.jpg diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-web.jpg b/3rd/libuv/docs/src/static/diagrams.key/preview-web.jpg similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview-web.jpg rename to 3rd/libuv/docs/src/static/diagrams.key/preview-web.jpg diff --git a/3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview.jpg b/3rd/libuv/docs/src/static/diagrams.key/preview.jpg similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/diagrams.key/preview.jpg rename to 3rd/libuv/docs/src/static/diagrams.key/preview.jpg diff --git a/3rd/libuv-1.19.2/docs/src/static/favicon.ico b/3rd/libuv/docs/src/static/favicon.ico similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/favicon.ico rename to 3rd/libuv/docs/src/static/favicon.ico diff --git a/3rd/libuv-1.19.2/docs/src/static/logo.png b/3rd/libuv/docs/src/static/logo.png similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/logo.png rename to 3rd/libuv/docs/src/static/logo.png diff --git a/3rd/libuv-1.19.2/docs/src/static/loop_iteration.png b/3rd/libuv/docs/src/static/loop_iteration.png similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/static/loop_iteration.png rename to 3rd/libuv/docs/src/static/loop_iteration.png diff --git a/3rd/libuv-1.19.2/docs/src/stream.rst b/3rd/libuv/docs/src/stream.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/stream.rst rename to 3rd/libuv/docs/src/stream.rst diff --git a/3rd/libuv-1.19.2/docs/src/tcp.rst b/3rd/libuv/docs/src/tcp.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/tcp.rst rename to 3rd/libuv/docs/src/tcp.rst diff --git a/3rd/libuv-1.19.2/docs/src/threading.rst b/3rd/libuv/docs/src/threading.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/threading.rst rename to 3rd/libuv/docs/src/threading.rst diff --git a/3rd/libuv-1.19.2/docs/src/threadpool.rst b/3rd/libuv/docs/src/threadpool.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/threadpool.rst rename to 3rd/libuv/docs/src/threadpool.rst diff --git a/3rd/libuv-1.19.2/docs/src/timer.rst b/3rd/libuv/docs/src/timer.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/timer.rst rename to 3rd/libuv/docs/src/timer.rst diff --git a/3rd/libuv-1.19.2/docs/src/tty.rst b/3rd/libuv/docs/src/tty.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/tty.rst rename to 3rd/libuv/docs/src/tty.rst diff --git a/3rd/libuv-1.19.2/docs/src/udp.rst b/3rd/libuv/docs/src/udp.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/udp.rst rename to 3rd/libuv/docs/src/udp.rst diff --git a/3rd/libuv-1.19.2/docs/src/upgrading.rst b/3rd/libuv/docs/src/upgrading.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/upgrading.rst rename to 3rd/libuv/docs/src/upgrading.rst diff --git a/3rd/libuv-1.19.2/docs/src/version.rst b/3rd/libuv/docs/src/version.rst similarity index 100% rename from 3rd/libuv-1.19.2/docs/src/version.rst rename to 3rd/libuv/docs/src/version.rst diff --git a/3rd/libuv-1.19.2/gyp_uv.py b/3rd/libuv/gyp_uv.py similarity index 100% rename from 3rd/libuv-1.19.2/gyp_uv.py rename to 3rd/libuv/gyp_uv.py diff --git a/3rd/libuv-1.19.2/img/banner.png b/3rd/libuv/img/banner.png similarity index 100% rename from 3rd/libuv-1.19.2/img/banner.png rename to 3rd/libuv/img/banner.png diff --git a/3rd/libuv-1.19.2/img/logos.svg b/3rd/libuv/img/logos.svg similarity index 100% rename from 3rd/libuv-1.19.2/img/logos.svg rename to 3rd/libuv/img/logos.svg diff --git a/3rd/libuv-1.19.2/include/android-ifaddrs.h b/3rd/libuv/include/android-ifaddrs.h similarity index 100% rename from 3rd/libuv-1.19.2/include/android-ifaddrs.h rename to 3rd/libuv/include/android-ifaddrs.h diff --git a/3rd/libuv-1.19.2/include/pthread-barrier.h b/3rd/libuv/include/pthread-barrier.h similarity index 100% rename from 3rd/libuv-1.19.2/include/pthread-barrier.h rename to 3rd/libuv/include/pthread-barrier.h diff --git a/3rd/libuv-1.19.2/include/stdint-msvc2008.h b/3rd/libuv/include/stdint-msvc2008.h similarity index 100% rename from 3rd/libuv-1.19.2/include/stdint-msvc2008.h rename to 3rd/libuv/include/stdint-msvc2008.h diff --git a/3rd/libuv-1.19.2/include/tree.h b/3rd/libuv/include/tree.h similarity index 100% rename from 3rd/libuv-1.19.2/include/tree.h rename to 3rd/libuv/include/tree.h diff --git a/3rd/libuv-1.19.2/include/uv-aix.h b/3rd/libuv/include/uv-aix.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-aix.h rename to 3rd/libuv/include/uv-aix.h diff --git a/3rd/libuv-1.19.2/include/uv-bsd.h b/3rd/libuv/include/uv-bsd.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-bsd.h rename to 3rd/libuv/include/uv-bsd.h diff --git a/3rd/libuv-1.19.2/include/uv-darwin.h b/3rd/libuv/include/uv-darwin.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-darwin.h rename to 3rd/libuv/include/uv-darwin.h diff --git a/3rd/libuv-1.19.2/include/uv-errno.h b/3rd/libuv/include/uv-errno.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-errno.h rename to 3rd/libuv/include/uv-errno.h diff --git a/3rd/libuv-1.19.2/include/uv-linux.h b/3rd/libuv/include/uv-linux.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-linux.h rename to 3rd/libuv/include/uv-linux.h diff --git a/3rd/libuv-1.19.2/include/uv-os390.h b/3rd/libuv/include/uv-os390.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-os390.h rename to 3rd/libuv/include/uv-os390.h diff --git a/3rd/libuv-1.19.2/include/uv-posix.h b/3rd/libuv/include/uv-posix.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-posix.h rename to 3rd/libuv/include/uv-posix.h diff --git a/3rd/libuv-1.19.2/include/uv-sunos.h b/3rd/libuv/include/uv-sunos.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-sunos.h rename to 3rd/libuv/include/uv-sunos.h diff --git a/3rd/libuv-1.19.2/include/uv-threadpool.h b/3rd/libuv/include/uv-threadpool.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-threadpool.h rename to 3rd/libuv/include/uv-threadpool.h diff --git a/3rd/libuv-1.19.2/include/uv-unix.h b/3rd/libuv/include/uv-unix.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-unix.h rename to 3rd/libuv/include/uv-unix.h diff --git a/3rd/libuv-1.19.2/include/uv-version.h b/3rd/libuv/include/uv-version.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-version.h rename to 3rd/libuv/include/uv-version.h diff --git a/3rd/libuv-1.19.2/include/uv-win.h b/3rd/libuv/include/uv-win.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv-win.h rename to 3rd/libuv/include/uv-win.h diff --git a/3rd/libuv-1.19.2/include/uv.h b/3rd/libuv/include/uv.h similarity index 100% rename from 3rd/libuv-1.19.2/include/uv.h rename to 3rd/libuv/include/uv.h diff --git a/3rd/libuv-1.19.2/libuv.pc.in b/3rd/libuv/libuv.pc.in similarity index 100% rename from 3rd/libuv-1.19.2/libuv.pc.in rename to 3rd/libuv/libuv.pc.in diff --git a/3rd/libuv-1.19.2/libuv.vcxproj b/3rd/libuv/libuv.vcxproj similarity index 100% rename from 3rd/libuv-1.19.2/libuv.vcxproj rename to 3rd/libuv/libuv.vcxproj diff --git a/3rd/libuv-1.19.2/m4/.gitignore b/3rd/libuv/m4/.gitignore similarity index 100% rename from 3rd/libuv-1.19.2/m4/.gitignore rename to 3rd/libuv/m4/.gitignore diff --git a/3rd/libuv-1.19.2/m4/as_case.m4 b/3rd/libuv/m4/as_case.m4 similarity index 100% rename from 3rd/libuv-1.19.2/m4/as_case.m4 rename to 3rd/libuv/m4/as_case.m4 diff --git a/3rd/libuv-1.19.2/m4/libuv-check-flags.m4 b/3rd/libuv/m4/libuv-check-flags.m4 similarity index 100% rename from 3rd/libuv-1.19.2/m4/libuv-check-flags.m4 rename to 3rd/libuv/m4/libuv-check-flags.m4 diff --git a/3rd/libuv-1.19.2/samples/.gitignore b/3rd/libuv/samples/.gitignore similarity index 100% rename from 3rd/libuv-1.19.2/samples/.gitignore rename to 3rd/libuv/samples/.gitignore diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore b/3rd/libuv/samples/socks5-proxy/.gitignore similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/.gitignore rename to 3rd/libuv/samples/socks5-proxy/.gitignore diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE b/3rd/libuv/samples/socks5-proxy/LICENSE similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/LICENSE rename to 3rd/libuv/samples/socks5-proxy/LICENSE diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp b/3rd/libuv/samples/socks5-proxy/build.gyp similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/build.gyp rename to 3rd/libuv/samples/socks5-proxy/build.gyp diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/client.c b/3rd/libuv/samples/socks5-proxy/client.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/client.c rename to 3rd/libuv/samples/socks5-proxy/client.c diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/defs.h b/3rd/libuv/samples/socks5-proxy/defs.h similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/defs.h rename to 3rd/libuv/samples/socks5-proxy/defs.h diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c b/3rd/libuv/samples/socks5-proxy/getopt.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/getopt.c rename to 3rd/libuv/samples/socks5-proxy/getopt.c diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/main.c b/3rd/libuv/samples/socks5-proxy/main.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/main.c rename to 3rd/libuv/samples/socks5-proxy/main.c diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.c b/3rd/libuv/samples/socks5-proxy/s5.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/s5.c rename to 3rd/libuv/samples/socks5-proxy/s5.c diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/s5.h b/3rd/libuv/samples/socks5-proxy/s5.h similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/s5.h rename to 3rd/libuv/samples/socks5-proxy/s5.h diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/server.c b/3rd/libuv/samples/socks5-proxy/server.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/server.c rename to 3rd/libuv/samples/socks5-proxy/server.c diff --git a/3rd/libuv-1.19.2/samples/socks5-proxy/util.c b/3rd/libuv/samples/socks5-proxy/util.c similarity index 100% rename from 3rd/libuv-1.19.2/samples/socks5-proxy/util.c rename to 3rd/libuv/samples/socks5-proxy/util.c diff --git a/3rd/libuv-1.19.2/src/fs-poll.c b/3rd/libuv/src/fs-poll.c similarity index 100% rename from 3rd/libuv-1.19.2/src/fs-poll.c rename to 3rd/libuv/src/fs-poll.c diff --git a/3rd/libuv-1.19.2/src/heap-inl.h b/3rd/libuv/src/heap-inl.h similarity index 100% rename from 3rd/libuv-1.19.2/src/heap-inl.h rename to 3rd/libuv/src/heap-inl.h diff --git a/3rd/libuv-1.19.2/src/inet.c b/3rd/libuv/src/inet.c similarity index 100% rename from 3rd/libuv-1.19.2/src/inet.c rename to 3rd/libuv/src/inet.c diff --git a/3rd/libuv-1.19.2/src/queue.h b/3rd/libuv/src/queue.h similarity index 100% rename from 3rd/libuv-1.19.2/src/queue.h rename to 3rd/libuv/src/queue.h diff --git a/3rd/libuv-1.19.2/src/threadpool.c b/3rd/libuv/src/threadpool.c similarity index 100% rename from 3rd/libuv-1.19.2/src/threadpool.c rename to 3rd/libuv/src/threadpool.c diff --git a/3rd/libuv-1.19.2/src/unix/aix-common.c b/3rd/libuv/src/unix/aix-common.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/aix-common.c rename to 3rd/libuv/src/unix/aix-common.c diff --git a/3rd/libuv-1.19.2/src/unix/aix.c b/3rd/libuv/src/unix/aix.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/aix.c rename to 3rd/libuv/src/unix/aix.c diff --git a/3rd/libuv-1.19.2/src/unix/android-ifaddrs.c b/3rd/libuv/src/unix/android-ifaddrs.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/android-ifaddrs.c rename to 3rd/libuv/src/unix/android-ifaddrs.c diff --git a/3rd/libuv-1.19.2/src/unix/async.c b/3rd/libuv/src/unix/async.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/async.c rename to 3rd/libuv/src/unix/async.c diff --git a/3rd/libuv-1.19.2/src/unix/atomic-ops.h b/3rd/libuv/src/unix/atomic-ops.h similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/atomic-ops.h rename to 3rd/libuv/src/unix/atomic-ops.h diff --git a/3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c b/3rd/libuv/src/unix/bsd-ifaddrs.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/bsd-ifaddrs.c rename to 3rd/libuv/src/unix/bsd-ifaddrs.c diff --git a/3rd/libuv-1.19.2/src/unix/core.c b/3rd/libuv/src/unix/core.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/core.c rename to 3rd/libuv/src/unix/core.c diff --git a/3rd/libuv-1.19.2/src/unix/cygwin.c b/3rd/libuv/src/unix/cygwin.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/cygwin.c rename to 3rd/libuv/src/unix/cygwin.c diff --git a/3rd/libuv-1.19.2/src/unix/darwin-proctitle.c b/3rd/libuv/src/unix/darwin-proctitle.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/darwin-proctitle.c rename to 3rd/libuv/src/unix/darwin-proctitle.c diff --git a/3rd/libuv-1.19.2/src/unix/darwin.c b/3rd/libuv/src/unix/darwin.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/darwin.c rename to 3rd/libuv/src/unix/darwin.c diff --git a/3rd/libuv-1.19.2/src/unix/dl.c b/3rd/libuv/src/unix/dl.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/dl.c rename to 3rd/libuv/src/unix/dl.c diff --git a/3rd/libuv-1.19.2/src/unix/freebsd.c b/3rd/libuv/src/unix/freebsd.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/freebsd.c rename to 3rd/libuv/src/unix/freebsd.c diff --git a/3rd/libuv-1.19.2/src/unix/fs.c b/3rd/libuv/src/unix/fs.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/fs.c rename to 3rd/libuv/src/unix/fs.c diff --git a/3rd/libuv-1.19.2/src/unix/fsevents.c b/3rd/libuv/src/unix/fsevents.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/fsevents.c rename to 3rd/libuv/src/unix/fsevents.c diff --git a/3rd/libuv-1.19.2/src/unix/getaddrinfo.c b/3rd/libuv/src/unix/getaddrinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/getaddrinfo.c rename to 3rd/libuv/src/unix/getaddrinfo.c diff --git a/3rd/libuv-1.19.2/src/unix/getnameinfo.c b/3rd/libuv/src/unix/getnameinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/getnameinfo.c rename to 3rd/libuv/src/unix/getnameinfo.c diff --git a/3rd/libuv-1.19.2/src/unix/ibmi.c b/3rd/libuv/src/unix/ibmi.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/ibmi.c rename to 3rd/libuv/src/unix/ibmi.c diff --git a/3rd/libuv-1.19.2/src/unix/internal.h b/3rd/libuv/src/unix/internal.h similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/internal.h rename to 3rd/libuv/src/unix/internal.h diff --git a/3rd/libuv-1.19.2/src/unix/kqueue.c b/3rd/libuv/src/unix/kqueue.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/kqueue.c rename to 3rd/libuv/src/unix/kqueue.c diff --git a/3rd/libuv-1.19.2/src/unix/linux-core.c b/3rd/libuv/src/unix/linux-core.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/linux-core.c rename to 3rd/libuv/src/unix/linux-core.c diff --git a/3rd/libuv-1.19.2/src/unix/linux-inotify.c b/3rd/libuv/src/unix/linux-inotify.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/linux-inotify.c rename to 3rd/libuv/src/unix/linux-inotify.c diff --git a/3rd/libuv-1.19.2/src/unix/linux-syscalls.c b/3rd/libuv/src/unix/linux-syscalls.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/linux-syscalls.c rename to 3rd/libuv/src/unix/linux-syscalls.c diff --git a/3rd/libuv-1.19.2/src/unix/linux-syscalls.h b/3rd/libuv/src/unix/linux-syscalls.h similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/linux-syscalls.h rename to 3rd/libuv/src/unix/linux-syscalls.h diff --git a/3rd/libuv-1.19.2/src/unix/loop-watcher.c b/3rd/libuv/src/unix/loop-watcher.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/loop-watcher.c rename to 3rd/libuv/src/unix/loop-watcher.c diff --git a/3rd/libuv-1.19.2/src/unix/loop.c b/3rd/libuv/src/unix/loop.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/loop.c rename to 3rd/libuv/src/unix/loop.c diff --git a/3rd/libuv-1.19.2/src/unix/netbsd.c b/3rd/libuv/src/unix/netbsd.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/netbsd.c rename to 3rd/libuv/src/unix/netbsd.c diff --git a/3rd/libuv-1.19.2/src/unix/no-fsevents.c b/3rd/libuv/src/unix/no-fsevents.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/no-fsevents.c rename to 3rd/libuv/src/unix/no-fsevents.c diff --git a/3rd/libuv-1.19.2/src/unix/no-proctitle.c b/3rd/libuv/src/unix/no-proctitle.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/no-proctitle.c rename to 3rd/libuv/src/unix/no-proctitle.c diff --git a/3rd/libuv-1.19.2/src/unix/openbsd.c b/3rd/libuv/src/unix/openbsd.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/openbsd.c rename to 3rd/libuv/src/unix/openbsd.c diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.c b/3rd/libuv/src/unix/os390-syscalls.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/os390-syscalls.c rename to 3rd/libuv/src/unix/os390-syscalls.c diff --git a/3rd/libuv-1.19.2/src/unix/os390-syscalls.h b/3rd/libuv/src/unix/os390-syscalls.h similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/os390-syscalls.h rename to 3rd/libuv/src/unix/os390-syscalls.h diff --git a/3rd/libuv-1.19.2/src/unix/os390.c b/3rd/libuv/src/unix/os390.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/os390.c rename to 3rd/libuv/src/unix/os390.c diff --git a/3rd/libuv-1.19.2/src/unix/pipe.c b/3rd/libuv/src/unix/pipe.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/pipe.c rename to 3rd/libuv/src/unix/pipe.c diff --git a/3rd/libuv-1.19.2/src/unix/poll.c b/3rd/libuv/src/unix/poll.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/poll.c rename to 3rd/libuv/src/unix/poll.c diff --git a/3rd/libuv-1.19.2/src/unix/posix-hrtime.c b/3rd/libuv/src/unix/posix-hrtime.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/posix-hrtime.c rename to 3rd/libuv/src/unix/posix-hrtime.c diff --git a/3rd/libuv-1.19.2/src/unix/posix-poll.c b/3rd/libuv/src/unix/posix-poll.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/posix-poll.c rename to 3rd/libuv/src/unix/posix-poll.c diff --git a/3rd/libuv-1.19.2/src/unix/process.c b/3rd/libuv/src/unix/process.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/process.c rename to 3rd/libuv/src/unix/process.c diff --git a/3rd/libuv-1.19.2/src/unix/procfs-exepath.c b/3rd/libuv/src/unix/procfs-exepath.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/procfs-exepath.c rename to 3rd/libuv/src/unix/procfs-exepath.c diff --git a/3rd/libuv-1.19.2/src/unix/proctitle.c b/3rd/libuv/src/unix/proctitle.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/proctitle.c rename to 3rd/libuv/src/unix/proctitle.c diff --git a/3rd/libuv-1.19.2/src/unix/pthread-fixes.c b/3rd/libuv/src/unix/pthread-fixes.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/pthread-fixes.c rename to 3rd/libuv/src/unix/pthread-fixes.c diff --git a/3rd/libuv-1.19.2/src/unix/signal.c b/3rd/libuv/src/unix/signal.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/signal.c rename to 3rd/libuv/src/unix/signal.c diff --git a/3rd/libuv-1.19.2/src/unix/spinlock.h b/3rd/libuv/src/unix/spinlock.h similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/spinlock.h rename to 3rd/libuv/src/unix/spinlock.h diff --git a/3rd/libuv-1.19.2/src/unix/stream.c b/3rd/libuv/src/unix/stream.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/stream.c rename to 3rd/libuv/src/unix/stream.c diff --git a/3rd/libuv-1.19.2/src/unix/sunos.c b/3rd/libuv/src/unix/sunos.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/sunos.c rename to 3rd/libuv/src/unix/sunos.c diff --git a/3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c b/3rd/libuv/src/unix/sysinfo-loadavg.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/sysinfo-loadavg.c rename to 3rd/libuv/src/unix/sysinfo-loadavg.c diff --git a/3rd/libuv-1.19.2/src/unix/sysinfo-memory.c b/3rd/libuv/src/unix/sysinfo-memory.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/sysinfo-memory.c rename to 3rd/libuv/src/unix/sysinfo-memory.c diff --git a/3rd/libuv-1.19.2/src/unix/tcp.c b/3rd/libuv/src/unix/tcp.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/tcp.c rename to 3rd/libuv/src/unix/tcp.c diff --git a/3rd/libuv-1.19.2/src/unix/thread.c b/3rd/libuv/src/unix/thread.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/thread.c rename to 3rd/libuv/src/unix/thread.c diff --git a/3rd/libuv-1.19.2/src/unix/timer.c b/3rd/libuv/src/unix/timer.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/timer.c rename to 3rd/libuv/src/unix/timer.c diff --git a/3rd/libuv-1.19.2/src/unix/tty.c b/3rd/libuv/src/unix/tty.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/tty.c rename to 3rd/libuv/src/unix/tty.c diff --git a/3rd/libuv-1.19.2/src/unix/udp.c b/3rd/libuv/src/unix/udp.c similarity index 100% rename from 3rd/libuv-1.19.2/src/unix/udp.c rename to 3rd/libuv/src/unix/udp.c diff --git a/3rd/libuv-1.19.2/src/uv-common.c b/3rd/libuv/src/uv-common.c similarity index 100% rename from 3rd/libuv-1.19.2/src/uv-common.c rename to 3rd/libuv/src/uv-common.c diff --git a/3rd/libuv-1.19.2/src/uv-common.h b/3rd/libuv/src/uv-common.h similarity index 100% rename from 3rd/libuv-1.19.2/src/uv-common.h rename to 3rd/libuv/src/uv-common.h diff --git a/3rd/libuv-1.19.2/src/uv-data-getter-setters.c b/3rd/libuv/src/uv-data-getter-setters.c similarity index 100% rename from 3rd/libuv-1.19.2/src/uv-data-getter-setters.c rename to 3rd/libuv/src/uv-data-getter-setters.c diff --git a/3rd/libuv-1.19.2/src/version.c b/3rd/libuv/src/version.c similarity index 100% rename from 3rd/libuv-1.19.2/src/version.c rename to 3rd/libuv/src/version.c diff --git a/3rd/libuv-1.19.2/src/win/async.c b/3rd/libuv/src/win/async.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/async.c rename to 3rd/libuv/src/win/async.c diff --git a/3rd/libuv-1.19.2/src/win/atomicops-inl.h b/3rd/libuv/src/win/atomicops-inl.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/atomicops-inl.h rename to 3rd/libuv/src/win/atomicops-inl.h diff --git a/3rd/libuv-1.19.2/src/win/core.c b/3rd/libuv/src/win/core.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/core.c rename to 3rd/libuv/src/win/core.c diff --git a/3rd/libuv-1.19.2/src/win/detect-wakeup.c b/3rd/libuv/src/win/detect-wakeup.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/detect-wakeup.c rename to 3rd/libuv/src/win/detect-wakeup.c diff --git a/3rd/libuv-1.19.2/src/win/dl.c b/3rd/libuv/src/win/dl.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/dl.c rename to 3rd/libuv/src/win/dl.c diff --git a/3rd/libuv-1.19.2/src/win/error.c b/3rd/libuv/src/win/error.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/error.c rename to 3rd/libuv/src/win/error.c diff --git a/3rd/libuv-1.19.2/src/win/fs-event.c b/3rd/libuv/src/win/fs-event.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/fs-event.c rename to 3rd/libuv/src/win/fs-event.c diff --git a/3rd/libuv-1.19.2/src/win/fs.c b/3rd/libuv/src/win/fs.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/fs.c rename to 3rd/libuv/src/win/fs.c diff --git a/3rd/libuv-1.19.2/src/win/getaddrinfo.c b/3rd/libuv/src/win/getaddrinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/getaddrinfo.c rename to 3rd/libuv/src/win/getaddrinfo.c diff --git a/3rd/libuv-1.19.2/src/win/getnameinfo.c b/3rd/libuv/src/win/getnameinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/getnameinfo.c rename to 3rd/libuv/src/win/getnameinfo.c diff --git a/3rd/libuv-1.19.2/src/win/handle-inl.h b/3rd/libuv/src/win/handle-inl.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/handle-inl.h rename to 3rd/libuv/src/win/handle-inl.h diff --git a/3rd/libuv-1.19.2/src/win/handle.c b/3rd/libuv/src/win/handle.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/handle.c rename to 3rd/libuv/src/win/handle.c diff --git a/3rd/libuv-1.19.2/src/win/internal.h b/3rd/libuv/src/win/internal.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/internal.h rename to 3rd/libuv/src/win/internal.h diff --git a/3rd/libuv-1.19.2/src/win/loop-watcher.c b/3rd/libuv/src/win/loop-watcher.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/loop-watcher.c rename to 3rd/libuv/src/win/loop-watcher.c diff --git a/3rd/libuv-1.19.2/src/win/pipe.c b/3rd/libuv/src/win/pipe.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/pipe.c rename to 3rd/libuv/src/win/pipe.c diff --git a/3rd/libuv-1.19.2/src/win/poll.c b/3rd/libuv/src/win/poll.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/poll.c rename to 3rd/libuv/src/win/poll.c diff --git a/3rd/libuv-1.19.2/src/win/process-stdio.c b/3rd/libuv/src/win/process-stdio.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/process-stdio.c rename to 3rd/libuv/src/win/process-stdio.c diff --git a/3rd/libuv-1.19.2/src/win/process.c b/3rd/libuv/src/win/process.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/process.c rename to 3rd/libuv/src/win/process.c diff --git a/3rd/libuv-1.19.2/src/win/req-inl.h b/3rd/libuv/src/win/req-inl.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/req-inl.h rename to 3rd/libuv/src/win/req-inl.h diff --git a/3rd/libuv-1.19.2/src/win/req.c b/3rd/libuv/src/win/req.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/req.c rename to 3rd/libuv/src/win/req.c diff --git a/3rd/libuv-1.19.2/src/win/signal.c b/3rd/libuv/src/win/signal.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/signal.c rename to 3rd/libuv/src/win/signal.c diff --git a/3rd/libuv-1.19.2/src/win/snprintf.c b/3rd/libuv/src/win/snprintf.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/snprintf.c rename to 3rd/libuv/src/win/snprintf.c diff --git a/3rd/libuv-1.19.2/src/win/stream-inl.h b/3rd/libuv/src/win/stream-inl.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/stream-inl.h rename to 3rd/libuv/src/win/stream-inl.h diff --git a/3rd/libuv-1.19.2/src/win/stream.c b/3rd/libuv/src/win/stream.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/stream.c rename to 3rd/libuv/src/win/stream.c diff --git a/3rd/libuv-1.19.2/src/win/tcp.c b/3rd/libuv/src/win/tcp.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/tcp.c rename to 3rd/libuv/src/win/tcp.c diff --git a/3rd/libuv-1.19.2/src/win/thread.c b/3rd/libuv/src/win/thread.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/thread.c rename to 3rd/libuv/src/win/thread.c diff --git a/3rd/libuv-1.19.2/src/win/timer.c b/3rd/libuv/src/win/timer.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/timer.c rename to 3rd/libuv/src/win/timer.c diff --git a/3rd/libuv-1.19.2/src/win/tty.c b/3rd/libuv/src/win/tty.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/tty.c rename to 3rd/libuv/src/win/tty.c diff --git a/3rd/libuv-1.19.2/src/win/udp.c b/3rd/libuv/src/win/udp.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/udp.c rename to 3rd/libuv/src/win/udp.c diff --git a/3rd/libuv-1.19.2/src/win/util.c b/3rd/libuv/src/win/util.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/util.c rename to 3rd/libuv/src/win/util.c diff --git a/3rd/libuv-1.19.2/src/win/winapi.c b/3rd/libuv/src/win/winapi.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/winapi.c rename to 3rd/libuv/src/win/winapi.c diff --git a/3rd/libuv-1.19.2/src/win/winapi.h b/3rd/libuv/src/win/winapi.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/winapi.h rename to 3rd/libuv/src/win/winapi.h diff --git a/3rd/libuv-1.19.2/src/win/winsock.c b/3rd/libuv/src/win/winsock.c similarity index 100% rename from 3rd/libuv-1.19.2/src/win/winsock.c rename to 3rd/libuv/src/win/winsock.c diff --git a/3rd/libuv-1.19.2/src/win/winsock.h b/3rd/libuv/src/win/winsock.h similarity index 100% rename from 3rd/libuv-1.19.2/src/win/winsock.h rename to 3rd/libuv/src/win/winsock.h diff --git a/3rd/libuv-1.19.2/test/benchmark-async-pummel.c b/3rd/libuv/test/benchmark-async-pummel.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-async-pummel.c rename to 3rd/libuv/test/benchmark-async-pummel.c diff --git a/3rd/libuv-1.19.2/test/benchmark-async.c b/3rd/libuv/test/benchmark-async.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-async.c rename to 3rd/libuv/test/benchmark-async.c diff --git a/3rd/libuv-1.19.2/test/benchmark-fs-stat.c b/3rd/libuv/test/benchmark-fs-stat.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-fs-stat.c rename to 3rd/libuv/test/benchmark-fs-stat.c diff --git a/3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c b/3rd/libuv/test/benchmark-getaddrinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-getaddrinfo.c rename to 3rd/libuv/test/benchmark-getaddrinfo.c diff --git a/3rd/libuv-1.19.2/test/benchmark-list.h b/3rd/libuv/test/benchmark-list.h similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-list.h rename to 3rd/libuv/test/benchmark-list.h diff --git a/3rd/libuv-1.19.2/test/benchmark-loop-count.c b/3rd/libuv/test/benchmark-loop-count.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-loop-count.c rename to 3rd/libuv/test/benchmark-loop-count.c diff --git a/3rd/libuv-1.19.2/test/benchmark-million-async.c b/3rd/libuv/test/benchmark-million-async.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-million-async.c rename to 3rd/libuv/test/benchmark-million-async.c diff --git a/3rd/libuv-1.19.2/test/benchmark-million-timers.c b/3rd/libuv/test/benchmark-million-timers.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-million-timers.c rename to 3rd/libuv/test/benchmark-million-timers.c diff --git a/3rd/libuv-1.19.2/test/benchmark-multi-accept.c b/3rd/libuv/test/benchmark-multi-accept.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-multi-accept.c rename to 3rd/libuv/test/benchmark-multi-accept.c diff --git a/3rd/libuv-1.19.2/test/benchmark-ping-pongs.c b/3rd/libuv/test/benchmark-ping-pongs.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-ping-pongs.c rename to 3rd/libuv/test/benchmark-ping-pongs.c diff --git a/3rd/libuv-1.19.2/test/benchmark-pound.c b/3rd/libuv/test/benchmark-pound.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-pound.c rename to 3rd/libuv/test/benchmark-pound.c diff --git a/3rd/libuv-1.19.2/test/benchmark-pump.c b/3rd/libuv/test/benchmark-pump.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-pump.c rename to 3rd/libuv/test/benchmark-pump.c diff --git a/3rd/libuv-1.19.2/test/benchmark-sizes.c b/3rd/libuv/test/benchmark-sizes.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-sizes.c rename to 3rd/libuv/test/benchmark-sizes.c diff --git a/3rd/libuv-1.19.2/test/benchmark-spawn.c b/3rd/libuv/test/benchmark-spawn.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-spawn.c rename to 3rd/libuv/test/benchmark-spawn.c diff --git a/3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c b/3rd/libuv/test/benchmark-tcp-write-batch.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-tcp-write-batch.c rename to 3rd/libuv/test/benchmark-tcp-write-batch.c diff --git a/3rd/libuv-1.19.2/test/benchmark-thread.c b/3rd/libuv/test/benchmark-thread.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-thread.c rename to 3rd/libuv/test/benchmark-thread.c diff --git a/3rd/libuv-1.19.2/test/benchmark-udp-pummel.c b/3rd/libuv/test/benchmark-udp-pummel.c similarity index 100% rename from 3rd/libuv-1.19.2/test/benchmark-udp-pummel.c rename to 3rd/libuv/test/benchmark-udp-pummel.c diff --git a/3rd/libuv-1.19.2/test/blackhole-server.c b/3rd/libuv/test/blackhole-server.c similarity index 100% rename from 3rd/libuv-1.19.2/test/blackhole-server.c rename to 3rd/libuv/test/blackhole-server.c diff --git a/3rd/libuv-1.19.2/test/dns-server.c b/3rd/libuv/test/dns-server.c similarity index 100% rename from 3rd/libuv-1.19.2/test/dns-server.c rename to 3rd/libuv/test/dns-server.c diff --git a/3rd/libuv-1.19.2/test/echo-server.c b/3rd/libuv/test/echo-server.c similarity index 100% rename from 3rd/libuv-1.19.2/test/echo-server.c rename to 3rd/libuv/test/echo-server.c diff --git a/3rd/libuv-1.19.2/test/fixtures/empty_file b/3rd/libuv/test/fixtures/empty_file similarity index 100% rename from 3rd/libuv-1.19.2/test/fixtures/empty_file rename to 3rd/libuv/test/fixtures/empty_file diff --git a/3rd/libuv-1.19.2/test/fixtures/load_error.node b/3rd/libuv/test/fixtures/load_error.node similarity index 100% rename from 3rd/libuv-1.19.2/test/fixtures/load_error.node rename to 3rd/libuv/test/fixtures/load_error.node diff --git a/3rd/libuv-1.19.2/test/run-benchmarks.c b/3rd/libuv/test/run-benchmarks.c similarity index 100% rename from 3rd/libuv-1.19.2/test/run-benchmarks.c rename to 3rd/libuv/test/run-benchmarks.c diff --git a/3rd/libuv-1.19.2/test/run-tests.c b/3rd/libuv/test/run-tests.c similarity index 100% rename from 3rd/libuv-1.19.2/test/run-tests.c rename to 3rd/libuv/test/run-tests.c diff --git a/3rd/libuv-1.19.2/test/runner-unix.c b/3rd/libuv/test/runner-unix.c similarity index 100% rename from 3rd/libuv-1.19.2/test/runner-unix.c rename to 3rd/libuv/test/runner-unix.c diff --git a/3rd/libuv-1.19.2/test/runner-unix.h b/3rd/libuv/test/runner-unix.h similarity index 100% rename from 3rd/libuv-1.19.2/test/runner-unix.h rename to 3rd/libuv/test/runner-unix.h diff --git a/3rd/libuv-1.19.2/test/runner-win.c b/3rd/libuv/test/runner-win.c similarity index 100% rename from 3rd/libuv-1.19.2/test/runner-win.c rename to 3rd/libuv/test/runner-win.c diff --git a/3rd/libuv-1.19.2/test/runner-win.h b/3rd/libuv/test/runner-win.h similarity index 100% rename from 3rd/libuv-1.19.2/test/runner-win.h rename to 3rd/libuv/test/runner-win.h diff --git a/3rd/libuv-1.19.2/test/runner.c b/3rd/libuv/test/runner.c similarity index 100% rename from 3rd/libuv-1.19.2/test/runner.c rename to 3rd/libuv/test/runner.c diff --git a/3rd/libuv-1.19.2/test/runner.h b/3rd/libuv/test/runner.h similarity index 100% rename from 3rd/libuv-1.19.2/test/runner.h rename to 3rd/libuv/test/runner.h diff --git a/3rd/libuv-1.19.2/test/task.h b/3rd/libuv/test/task.h similarity index 100% rename from 3rd/libuv-1.19.2/test/task.h rename to 3rd/libuv/test/task.h diff --git a/3rd/libuv-1.19.2/test/test-active.c b/3rd/libuv/test/test-active.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-active.c rename to 3rd/libuv/test/test-active.c diff --git a/3rd/libuv-1.19.2/test/test-async-null-cb.c b/3rd/libuv/test/test-async-null-cb.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-async-null-cb.c rename to 3rd/libuv/test/test-async-null-cb.c diff --git a/3rd/libuv-1.19.2/test/test-async.c b/3rd/libuv/test/test-async.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-async.c rename to 3rd/libuv/test/test-async.c diff --git a/3rd/libuv-1.19.2/test/test-barrier.c b/3rd/libuv/test/test-barrier.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-barrier.c rename to 3rd/libuv/test/test-barrier.c diff --git a/3rd/libuv-1.19.2/test/test-callback-order.c b/3rd/libuv/test/test-callback-order.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-callback-order.c rename to 3rd/libuv/test/test-callback-order.c diff --git a/3rd/libuv-1.19.2/test/test-callback-stack.c b/3rd/libuv/test/test-callback-stack.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-callback-stack.c rename to 3rd/libuv/test/test-callback-stack.c diff --git a/3rd/libuv-1.19.2/test/test-close-fd.c b/3rd/libuv/test/test-close-fd.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-close-fd.c rename to 3rd/libuv/test/test-close-fd.c diff --git a/3rd/libuv-1.19.2/test/test-close-order.c b/3rd/libuv/test/test-close-order.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-close-order.c rename to 3rd/libuv/test/test-close-order.c diff --git a/3rd/libuv-1.19.2/test/test-condvar.c b/3rd/libuv/test/test-condvar.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-condvar.c rename to 3rd/libuv/test/test-condvar.c diff --git a/3rd/libuv-1.19.2/test/test-connect-unspecified.c b/3rd/libuv/test/test-connect-unspecified.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-connect-unspecified.c rename to 3rd/libuv/test/test-connect-unspecified.c diff --git a/3rd/libuv-1.19.2/test/test-connection-fail.c b/3rd/libuv/test/test-connection-fail.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-connection-fail.c rename to 3rd/libuv/test/test-connection-fail.c diff --git a/3rd/libuv-1.19.2/test/test-cwd-and-chdir.c b/3rd/libuv/test/test-cwd-and-chdir.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-cwd-and-chdir.c rename to 3rd/libuv/test/test-cwd-and-chdir.c diff --git a/3rd/libuv-1.19.2/test/test-default-loop-close.c b/3rd/libuv/test/test-default-loop-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-default-loop-close.c rename to 3rd/libuv/test/test-default-loop-close.c diff --git a/3rd/libuv-1.19.2/test/test-delayed-accept.c b/3rd/libuv/test/test-delayed-accept.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-delayed-accept.c rename to 3rd/libuv/test/test-delayed-accept.c diff --git a/3rd/libuv-1.19.2/test/test-dlerror.c b/3rd/libuv/test/test-dlerror.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-dlerror.c rename to 3rd/libuv/test/test-dlerror.c diff --git a/3rd/libuv-1.19.2/test/test-eintr-handling.c b/3rd/libuv/test/test-eintr-handling.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-eintr-handling.c rename to 3rd/libuv/test/test-eintr-handling.c diff --git a/3rd/libuv-1.19.2/test/test-embed.c b/3rd/libuv/test/test-embed.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-embed.c rename to 3rd/libuv/test/test-embed.c diff --git a/3rd/libuv-1.19.2/test/test-emfile.c b/3rd/libuv/test/test-emfile.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-emfile.c rename to 3rd/libuv/test/test-emfile.c diff --git a/3rd/libuv-1.19.2/test/test-env-vars.c b/3rd/libuv/test/test-env-vars.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-env-vars.c rename to 3rd/libuv/test/test-env-vars.c diff --git a/3rd/libuv-1.19.2/test/test-error.c b/3rd/libuv/test/test-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-error.c rename to 3rd/libuv/test/test-error.c diff --git a/3rd/libuv-1.19.2/test/test-fail-always.c b/3rd/libuv/test/test-fail-always.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fail-always.c rename to 3rd/libuv/test/test-fail-always.c diff --git a/3rd/libuv-1.19.2/test/test-fork.c b/3rd/libuv/test/test-fork.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fork.c rename to 3rd/libuv/test/test-fork.c diff --git a/3rd/libuv-1.19.2/test/test-fs-copyfile.c b/3rd/libuv/test/test-fs-copyfile.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fs-copyfile.c rename to 3rd/libuv/test/test-fs-copyfile.c diff --git a/3rd/libuv-1.19.2/test/test-fs-event.c b/3rd/libuv/test/test-fs-event.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fs-event.c rename to 3rd/libuv/test/test-fs-event.c diff --git a/3rd/libuv-1.19.2/test/test-fs-poll.c b/3rd/libuv/test/test-fs-poll.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fs-poll.c rename to 3rd/libuv/test/test-fs-poll.c diff --git a/3rd/libuv-1.19.2/test/test-fs.c b/3rd/libuv/test/test-fs.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-fs.c rename to 3rd/libuv/test/test-fs.c diff --git a/3rd/libuv-1.19.2/test/test-get-currentexe.c b/3rd/libuv/test/test-get-currentexe.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-get-currentexe.c rename to 3rd/libuv/test/test-get-currentexe.c diff --git a/3rd/libuv-1.19.2/test/test-get-loadavg.c b/3rd/libuv/test/test-get-loadavg.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-get-loadavg.c rename to 3rd/libuv/test/test-get-loadavg.c diff --git a/3rd/libuv-1.19.2/test/test-get-memory.c b/3rd/libuv/test/test-get-memory.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-get-memory.c rename to 3rd/libuv/test/test-get-memory.c diff --git a/3rd/libuv-1.19.2/test/test-get-passwd.c b/3rd/libuv/test/test-get-passwd.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-get-passwd.c rename to 3rd/libuv/test/test-get-passwd.c diff --git a/3rd/libuv-1.19.2/test/test-getaddrinfo.c b/3rd/libuv/test/test-getaddrinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-getaddrinfo.c rename to 3rd/libuv/test/test-getaddrinfo.c diff --git a/3rd/libuv-1.19.2/test/test-gethostname.c b/3rd/libuv/test/test-gethostname.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-gethostname.c rename to 3rd/libuv/test/test-gethostname.c diff --git a/3rd/libuv-1.19.2/test/test-getnameinfo.c b/3rd/libuv/test/test-getnameinfo.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-getnameinfo.c rename to 3rd/libuv/test/test-getnameinfo.c diff --git a/3rd/libuv-1.19.2/test/test-getsockname.c b/3rd/libuv/test/test-getsockname.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-getsockname.c rename to 3rd/libuv/test/test-getsockname.c diff --git a/3rd/libuv-1.19.2/test/test-getters-setters.c b/3rd/libuv/test/test-getters-setters.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-getters-setters.c rename to 3rd/libuv/test/test-getters-setters.c diff --git a/3rd/libuv-1.19.2/test/test-handle-fileno.c b/3rd/libuv/test/test-handle-fileno.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-handle-fileno.c rename to 3rd/libuv/test/test-handle-fileno.c diff --git a/3rd/libuv-1.19.2/test/test-homedir.c b/3rd/libuv/test/test-homedir.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-homedir.c rename to 3rd/libuv/test/test-homedir.c diff --git a/3rd/libuv-1.19.2/test/test-hrtime.c b/3rd/libuv/test/test-hrtime.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-hrtime.c rename to 3rd/libuv/test/test-hrtime.c diff --git a/3rd/libuv-1.19.2/test/test-idle.c b/3rd/libuv/test/test-idle.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-idle.c rename to 3rd/libuv/test/test-idle.c diff --git a/3rd/libuv-1.19.2/test/test-ip4-addr.c b/3rd/libuv/test/test-ip4-addr.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ip4-addr.c rename to 3rd/libuv/test/test-ip4-addr.c diff --git a/3rd/libuv-1.19.2/test/test-ip6-addr.c b/3rd/libuv/test/test-ip6-addr.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ip6-addr.c rename to 3rd/libuv/test/test-ip6-addr.c diff --git a/3rd/libuv-1.19.2/test/test-ipc-send-recv.c b/3rd/libuv/test/test-ipc-send-recv.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ipc-send-recv.c rename to 3rd/libuv/test/test-ipc-send-recv.c diff --git a/3rd/libuv-1.19.2/test/test-ipc.c b/3rd/libuv/test/test-ipc.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ipc.c rename to 3rd/libuv/test/test-ipc.c diff --git a/3rd/libuv-1.19.2/test/test-list.h b/3rd/libuv/test/test-list.h similarity index 100% rename from 3rd/libuv-1.19.2/test/test-list.h rename to 3rd/libuv/test/test-list.h diff --git a/3rd/libuv-1.19.2/test/test-loop-alive.c b/3rd/libuv/test/test-loop-alive.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-alive.c rename to 3rd/libuv/test/test-loop-alive.c diff --git a/3rd/libuv-1.19.2/test/test-loop-close.c b/3rd/libuv/test/test-loop-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-close.c rename to 3rd/libuv/test/test-loop-close.c diff --git a/3rd/libuv-1.19.2/test/test-loop-configure.c b/3rd/libuv/test/test-loop-configure.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-configure.c rename to 3rd/libuv/test/test-loop-configure.c diff --git a/3rd/libuv-1.19.2/test/test-loop-handles.c b/3rd/libuv/test/test-loop-handles.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-handles.c rename to 3rd/libuv/test/test-loop-handles.c diff --git a/3rd/libuv-1.19.2/test/test-loop-stop.c b/3rd/libuv/test/test-loop-stop.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-stop.c rename to 3rd/libuv/test/test-loop-stop.c diff --git a/3rd/libuv-1.19.2/test/test-loop-time.c b/3rd/libuv/test/test-loop-time.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-loop-time.c rename to 3rd/libuv/test/test-loop-time.c diff --git a/3rd/libuv-1.19.2/test/test-multiple-listen.c b/3rd/libuv/test/test-multiple-listen.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-multiple-listen.c rename to 3rd/libuv/test/test-multiple-listen.c diff --git a/3rd/libuv-1.19.2/test/test-mutexes.c b/3rd/libuv/test/test-mutexes.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-mutexes.c rename to 3rd/libuv/test/test-mutexes.c diff --git a/3rd/libuv-1.19.2/test/test-osx-select.c b/3rd/libuv/test/test-osx-select.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-osx-select.c rename to 3rd/libuv/test/test-osx-select.c diff --git a/3rd/libuv-1.19.2/test/test-pass-always.c b/3rd/libuv/test/test-pass-always.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pass-always.c rename to 3rd/libuv/test/test-pass-always.c diff --git a/3rd/libuv-1.19.2/test/test-ping-pong.c b/3rd/libuv/test/test-ping-pong.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ping-pong.c rename to 3rd/libuv/test/test-ping-pong.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-bind-error.c b/3rd/libuv/test/test-pipe-bind-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-bind-error.c rename to 3rd/libuv/test/test-pipe-bind-error.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c b/3rd/libuv/test/test-pipe-close-stdout-read-stdin.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-close-stdout-read-stdin.c rename to 3rd/libuv/test/test-pipe-close-stdout-read-stdin.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-connect-error.c b/3rd/libuv/test/test-pipe-connect-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-connect-error.c rename to 3rd/libuv/test/test-pipe-connect-error.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c b/3rd/libuv/test/test-pipe-connect-multiple.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-connect-multiple.c rename to 3rd/libuv/test/test-pipe-connect-multiple.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c b/3rd/libuv/test/test-pipe-connect-prepare.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-connect-prepare.c rename to 3rd/libuv/test/test-pipe-connect-prepare.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-getsockname.c b/3rd/libuv/test/test-pipe-getsockname.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-getsockname.c rename to 3rd/libuv/test/test-pipe-getsockname.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-pending-instances.c b/3rd/libuv/test/test-pipe-pending-instances.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-pending-instances.c rename to 3rd/libuv/test/test-pipe-pending-instances.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-sendmsg.c b/3rd/libuv/test/test-pipe-sendmsg.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-sendmsg.c rename to 3rd/libuv/test/test-pipe-sendmsg.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-server-close.c b/3rd/libuv/test/test-pipe-server-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-server-close.c rename to 3rd/libuv/test/test-pipe-server-close.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c b/3rd/libuv/test/test-pipe-set-fchmod.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-set-fchmod.c rename to 3rd/libuv/test/test-pipe-set-fchmod.c diff --git a/3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c b/3rd/libuv/test/test-pipe-set-non-blocking.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-pipe-set-non-blocking.c rename to 3rd/libuv/test/test-pipe-set-non-blocking.c diff --git a/3rd/libuv-1.19.2/test/test-platform-output.c b/3rd/libuv/test/test-platform-output.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-platform-output.c rename to 3rd/libuv/test/test-platform-output.c diff --git a/3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c b/3rd/libuv/test/test-poll-close-doesnt-corrupt-stack.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-poll-close-doesnt-corrupt-stack.c rename to 3rd/libuv/test/test-poll-close-doesnt-corrupt-stack.c diff --git a/3rd/libuv-1.19.2/test/test-poll-close.c b/3rd/libuv/test/test-poll-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-poll-close.c rename to 3rd/libuv/test/test-poll-close.c diff --git a/3rd/libuv-1.19.2/test/test-poll-closesocket.c b/3rd/libuv/test/test-poll-closesocket.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-poll-closesocket.c rename to 3rd/libuv/test/test-poll-closesocket.c diff --git a/3rd/libuv-1.19.2/test/test-poll-oob.c b/3rd/libuv/test/test-poll-oob.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-poll-oob.c rename to 3rd/libuv/test/test-poll-oob.c diff --git a/3rd/libuv-1.19.2/test/test-poll.c b/3rd/libuv/test/test-poll.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-poll.c rename to 3rd/libuv/test/test-poll.c diff --git a/3rd/libuv-1.19.2/test/test-process-title-threadsafe.c b/3rd/libuv/test/test-process-title-threadsafe.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-process-title-threadsafe.c rename to 3rd/libuv/test/test-process-title-threadsafe.c diff --git a/3rd/libuv-1.19.2/test/test-process-title.c b/3rd/libuv/test/test-process-title.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-process-title.c rename to 3rd/libuv/test/test-process-title.c diff --git a/3rd/libuv-1.19.2/test/test-queue-foreach-delete.c b/3rd/libuv/test/test-queue-foreach-delete.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-queue-foreach-delete.c rename to 3rd/libuv/test/test-queue-foreach-delete.c diff --git a/3rd/libuv-1.19.2/test/test-ref.c b/3rd/libuv/test/test-ref.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-ref.c rename to 3rd/libuv/test/test-ref.c diff --git a/3rd/libuv-1.19.2/test/test-run-nowait.c b/3rd/libuv/test/test-run-nowait.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-run-nowait.c rename to 3rd/libuv/test/test-run-nowait.c diff --git a/3rd/libuv-1.19.2/test/test-run-once.c b/3rd/libuv/test/test-run-once.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-run-once.c rename to 3rd/libuv/test/test-run-once.c diff --git a/3rd/libuv-1.19.2/test/test-semaphore.c b/3rd/libuv/test/test-semaphore.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-semaphore.c rename to 3rd/libuv/test/test-semaphore.c diff --git a/3rd/libuv-1.19.2/test/test-shutdown-close.c b/3rd/libuv/test/test-shutdown-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-shutdown-close.c rename to 3rd/libuv/test/test-shutdown-close.c diff --git a/3rd/libuv-1.19.2/test/test-shutdown-eof.c b/3rd/libuv/test/test-shutdown-eof.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-shutdown-eof.c rename to 3rd/libuv/test/test-shutdown-eof.c diff --git a/3rd/libuv-1.19.2/test/test-shutdown-twice.c b/3rd/libuv/test/test-shutdown-twice.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-shutdown-twice.c rename to 3rd/libuv/test/test-shutdown-twice.c diff --git a/3rd/libuv-1.19.2/test/test-signal-multiple-loops.c b/3rd/libuv/test/test-signal-multiple-loops.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-signal-multiple-loops.c rename to 3rd/libuv/test/test-signal-multiple-loops.c diff --git a/3rd/libuv-1.19.2/test/test-signal.c b/3rd/libuv/test/test-signal.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-signal.c rename to 3rd/libuv/test/test-signal.c diff --git a/3rd/libuv-1.19.2/test/test-socket-buffer-size.c b/3rd/libuv/test/test-socket-buffer-size.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-socket-buffer-size.c rename to 3rd/libuv/test/test-socket-buffer-size.c diff --git a/3rd/libuv-1.19.2/test/test-spawn.c b/3rd/libuv/test/test-spawn.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-spawn.c rename to 3rd/libuv/test/test-spawn.c diff --git a/3rd/libuv-1.19.2/test/test-stdio-over-pipes.c b/3rd/libuv/test/test-stdio-over-pipes.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-stdio-over-pipes.c rename to 3rd/libuv/test/test-stdio-over-pipes.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c b/3rd/libuv/test/test-tcp-alloc-cb-fail.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-alloc-cb-fail.c rename to 3rd/libuv/test/test-tcp-alloc-cb-fail.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-bind-error.c b/3rd/libuv/test/test-tcp-bind-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-bind-error.c rename to 3rd/libuv/test/test-tcp-bind-error.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-bind6-error.c b/3rd/libuv/test/test-tcp-bind6-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-bind6-error.c rename to 3rd/libuv/test/test-tcp-bind6-error.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-close-accept.c b/3rd/libuv/test/test-tcp-close-accept.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-close-accept.c rename to 3rd/libuv/test/test-tcp-close-accept.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c b/3rd/libuv/test/test-tcp-close-while-connecting.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-close-while-connecting.c rename to 3rd/libuv/test/test-tcp-close-while-connecting.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-close.c b/3rd/libuv/test/test-tcp-close.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-close.c rename to 3rd/libuv/test/test-tcp-close.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c b/3rd/libuv/test/test-tcp-connect-error-after-write.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-connect-error-after-write.c rename to 3rd/libuv/test/test-tcp-connect-error-after-write.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-connect-error.c b/3rd/libuv/test/test-tcp-connect-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-connect-error.c rename to 3rd/libuv/test/test-tcp-connect-error.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c b/3rd/libuv/test/test-tcp-connect-timeout.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-connect-timeout.c rename to 3rd/libuv/test/test-tcp-connect-timeout.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-connect6-error.c b/3rd/libuv/test/test-tcp-connect6-error.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-connect6-error.c rename to 3rd/libuv/test/test-tcp-connect6-error.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c b/3rd/libuv/test/test-tcp-create-socket-early.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-create-socket-early.c rename to 3rd/libuv/test/test-tcp-create-socket-early.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-flags.c b/3rd/libuv/test/test-tcp-flags.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-flags.c rename to 3rd/libuv/test/test-tcp-flags.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-oob.c b/3rd/libuv/test/test-tcp-oob.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-oob.c rename to 3rd/libuv/test/test-tcp-oob.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-open.c b/3rd/libuv/test/test-tcp-open.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-open.c rename to 3rd/libuv/test/test-tcp-open.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-read-stop.c b/3rd/libuv/test/test-tcp-read-stop.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-read-stop.c rename to 3rd/libuv/test/test-tcp-read-stop.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c b/3rd/libuv/test/test-tcp-shutdown-after-write.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-shutdown-after-write.c rename to 3rd/libuv/test/test-tcp-shutdown-after-write.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-try-write.c b/3rd/libuv/test/test-tcp-try-write.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-try-write.c rename to 3rd/libuv/test/test-tcp-try-write.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c b/3rd/libuv/test/test-tcp-unexpected-read.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-unexpected-read.c rename to 3rd/libuv/test/test-tcp-unexpected-read.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c b/3rd/libuv/test/test-tcp-write-after-connect.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-write-after-connect.c rename to 3rd/libuv/test/test-tcp-write-after-connect.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-write-fail.c b/3rd/libuv/test/test-tcp-write-fail.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-write-fail.c rename to 3rd/libuv/test/test-tcp-write-fail.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c b/3rd/libuv/test/test-tcp-write-queue-order.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-write-queue-order.c rename to 3rd/libuv/test/test-tcp-write-queue-order.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c b/3rd/libuv/test/test-tcp-write-to-half-open-connection.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-write-to-half-open-connection.c rename to 3rd/libuv/test/test-tcp-write-to-half-open-connection.c diff --git a/3rd/libuv-1.19.2/test/test-tcp-writealot.c b/3rd/libuv/test/test-tcp-writealot.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tcp-writealot.c rename to 3rd/libuv/test/test-tcp-writealot.c diff --git a/3rd/libuv-1.19.2/test/test-thread-equal.c b/3rd/libuv/test/test-thread-equal.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-thread-equal.c rename to 3rd/libuv/test/test-thread-equal.c diff --git a/3rd/libuv-1.19.2/test/test-thread.c b/3rd/libuv/test/test-thread.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-thread.c rename to 3rd/libuv/test/test-thread.c diff --git a/3rd/libuv-1.19.2/test/test-threadpool-cancel.c b/3rd/libuv/test/test-threadpool-cancel.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-threadpool-cancel.c rename to 3rd/libuv/test/test-threadpool-cancel.c diff --git a/3rd/libuv-1.19.2/test/test-threadpool.c b/3rd/libuv/test/test-threadpool.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-threadpool.c rename to 3rd/libuv/test/test-threadpool.c diff --git a/3rd/libuv-1.19.2/test/test-timer-again.c b/3rd/libuv/test/test-timer-again.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-timer-again.c rename to 3rd/libuv/test/test-timer-again.c diff --git a/3rd/libuv-1.19.2/test/test-timer-from-check.c b/3rd/libuv/test/test-timer-from-check.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-timer-from-check.c rename to 3rd/libuv/test/test-timer-from-check.c diff --git a/3rd/libuv-1.19.2/test/test-timer.c b/3rd/libuv/test/test-timer.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-timer.c rename to 3rd/libuv/test/test-timer.c diff --git a/3rd/libuv-1.19.2/test/test-tmpdir.c b/3rd/libuv/test/test-tmpdir.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tmpdir.c rename to 3rd/libuv/test/test-tmpdir.c diff --git a/3rd/libuv-1.19.2/test/test-tty.c b/3rd/libuv/test/test-tty.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-tty.c rename to 3rd/libuv/test/test-tty.c diff --git a/3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c b/3rd/libuv/test/test-udp-alloc-cb-fail.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-alloc-cb-fail.c rename to 3rd/libuv/test/test-udp-alloc-cb-fail.c diff --git a/3rd/libuv-1.19.2/test/test-udp-bind.c b/3rd/libuv/test/test-udp-bind.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-bind.c rename to 3rd/libuv/test/test-udp-bind.c diff --git a/3rd/libuv-1.19.2/test/test-udp-create-socket-early.c b/3rd/libuv/test/test-udp-create-socket-early.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-create-socket-early.c rename to 3rd/libuv/test/test-udp-create-socket-early.c diff --git a/3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c b/3rd/libuv/test/test-udp-dgram-too-big.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-dgram-too-big.c rename to 3rd/libuv/test/test-udp-dgram-too-big.c diff --git a/3rd/libuv-1.19.2/test/test-udp-ipv6.c b/3rd/libuv/test/test-udp-ipv6.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-ipv6.c rename to 3rd/libuv/test/test-udp-ipv6.c diff --git a/3rd/libuv-1.19.2/test/test-udp-multicast-interface.c b/3rd/libuv/test/test-udp-multicast-interface.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-multicast-interface.c rename to 3rd/libuv/test/test-udp-multicast-interface.c diff --git a/3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c b/3rd/libuv/test/test-udp-multicast-interface6.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-multicast-interface6.c rename to 3rd/libuv/test/test-udp-multicast-interface6.c diff --git a/3rd/libuv-1.19.2/test/test-udp-multicast-join.c b/3rd/libuv/test/test-udp-multicast-join.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-multicast-join.c rename to 3rd/libuv/test/test-udp-multicast-join.c diff --git a/3rd/libuv-1.19.2/test/test-udp-multicast-join6.c b/3rd/libuv/test/test-udp-multicast-join6.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-multicast-join6.c rename to 3rd/libuv/test/test-udp-multicast-join6.c diff --git a/3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c b/3rd/libuv/test/test-udp-multicast-ttl.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-multicast-ttl.c rename to 3rd/libuv/test/test-udp-multicast-ttl.c diff --git a/3rd/libuv-1.19.2/test/test-udp-open.c b/3rd/libuv/test/test-udp-open.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-open.c rename to 3rd/libuv/test/test-udp-open.c diff --git a/3rd/libuv-1.19.2/test/test-udp-options.c b/3rd/libuv/test/test-udp-options.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-options.c rename to 3rd/libuv/test/test-udp-options.c diff --git a/3rd/libuv-1.19.2/test/test-udp-send-and-recv.c b/3rd/libuv/test/test-udp-send-and-recv.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-send-and-recv.c rename to 3rd/libuv/test/test-udp-send-and-recv.c diff --git a/3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c b/3rd/libuv/test/test-udp-send-hang-loop.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-send-hang-loop.c rename to 3rd/libuv/test/test-udp-send-hang-loop.c diff --git a/3rd/libuv-1.19.2/test/test-udp-send-immediate.c b/3rd/libuv/test/test-udp-send-immediate.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-send-immediate.c rename to 3rd/libuv/test/test-udp-send-immediate.c diff --git a/3rd/libuv-1.19.2/test/test-udp-send-unreachable.c b/3rd/libuv/test/test-udp-send-unreachable.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-send-unreachable.c rename to 3rd/libuv/test/test-udp-send-unreachable.c diff --git a/3rd/libuv-1.19.2/test/test-udp-try-send.c b/3rd/libuv/test/test-udp-try-send.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-udp-try-send.c rename to 3rd/libuv/test/test-udp-try-send.c diff --git a/3rd/libuv-1.19.2/test/test-walk-handles.c b/3rd/libuv/test/test-walk-handles.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-walk-handles.c rename to 3rd/libuv/test/test-walk-handles.c diff --git a/3rd/libuv-1.19.2/test/test-watcher-cross-stop.c b/3rd/libuv/test/test-watcher-cross-stop.c similarity index 100% rename from 3rd/libuv-1.19.2/test/test-watcher-cross-stop.c rename to 3rd/libuv/test/test-watcher-cross-stop.c diff --git a/3rd/libuv-1.19.2/test/test.gyp b/3rd/libuv/test/test.gyp similarity index 100% rename from 3rd/libuv-1.19.2/test/test.gyp rename to 3rd/libuv/test/test.gyp diff --git a/3rd/libuv-1.19.2/tools/make_dist_html.py b/3rd/libuv/tools/make_dist_html.py similarity index 100% rename from 3rd/libuv-1.19.2/tools/make_dist_html.py rename to 3rd/libuv/tools/make_dist_html.py diff --git a/3rd/libuv-1.19.2/uv.gyp b/3rd/libuv/uv.gyp similarity index 100% rename from 3rd/libuv-1.19.2/uv.gyp rename to 3rd/libuv/uv.gyp diff --git a/3rd/libuv-1.19.2/vcbuild.bat b/3rd/libuv/vcbuild.bat similarity index 100% rename from 3rd/libuv-1.19.2/vcbuild.bat rename to 3rd/libuv/vcbuild.bat -- Gitee From e71d84f369e952f855cb80bf6e5146e7559facaf Mon Sep 17 00:00:00 2001 From: thinking Date: Sun, 18 Mar 2018 02:07:41 +0800 Subject: [PATCH 11/11] add libuv event demo --- .gitignore | 5 + 3rd/3rd.sln | 2 +- 3rd/include/libuv/android-ifaddrs.h | 54 + 3rd/include/libuv/pthread-barrier.h | 69 ++ 3rd/include/libuv/stdint-msvc2008.h | 247 +++++ 3rd/include/libuv/tree.h | 768 +++++++++++++ 3rd/include/libuv/uv-aix.h | 32 + 3rd/include/libuv/uv-bsd.h | 34 + 3rd/include/libuv/uv-darwin.h | 61 ++ 3rd/include/libuv/uv-errno.h | 437 ++++++++ 3rd/include/libuv/uv-linux.h | 34 + 3rd/include/libuv/uv-os390.h | 33 + 3rd/include/libuv/uv-posix.h | 31 + 3rd/include/libuv/uv-sunos.h | 44 + 3rd/include/libuv/uv-threadpool.h | 37 + 3rd/include/libuv/uv-unix.h | 464 ++++++++ 3rd/include/libuv/uv-version.h | 43 + 3rd/include/libuv/uv-win.h | 676 ++++++++++++ 3rd/include/libuv/uv.h | 1567 +++++++++++++++++++++++++++ asynio/asynio.vcxproj | 17 +- asynio/ioeventdef.h | 82 ++ asynio/ioeventloop.cpp | 2 + asynio/ioeventloop.h | 51 + asynio/iostreambase.cpp | 1 + asynio/iostreambase.h | 19 + asynio/iotcpbase.cpp | 2 + asynio/iotcpbase.h | 44 + asynio/tcpsocketimpl.h | 4 +- 28 files changed, 4852 insertions(+), 8 deletions(-) create mode 100644 3rd/include/libuv/android-ifaddrs.h create mode 100644 3rd/include/libuv/pthread-barrier.h create mode 100644 3rd/include/libuv/stdint-msvc2008.h create mode 100644 3rd/include/libuv/tree.h create mode 100644 3rd/include/libuv/uv-aix.h create mode 100644 3rd/include/libuv/uv-bsd.h create mode 100644 3rd/include/libuv/uv-darwin.h create mode 100644 3rd/include/libuv/uv-errno.h create mode 100644 3rd/include/libuv/uv-linux.h create mode 100644 3rd/include/libuv/uv-os390.h create mode 100644 3rd/include/libuv/uv-posix.h create mode 100644 3rd/include/libuv/uv-sunos.h create mode 100644 3rd/include/libuv/uv-threadpool.h create mode 100644 3rd/include/libuv/uv-unix.h create mode 100644 3rd/include/libuv/uv-version.h create mode 100644 3rd/include/libuv/uv-win.h create mode 100644 3rd/include/libuv/uv.h create mode 100644 asynio/ioeventdef.h create mode 100644 asynio/ioeventloop.cpp create mode 100644 asynio/ioeventloop.h create mode 100644 asynio/iostreambase.cpp create mode 100644 asynio/iostreambase.h create mode 100644 asynio/iotcpbase.cpp create mode 100644 asynio/iotcpbase.h diff --git a/.gitignore b/.gitignore index 7066f223..235cfcbd 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,11 @@ *.ipch *.log *.VC.db +*.Tlog +# VC project +*.user + + # Precompiled Headers *.gch diff --git a/3rd/3rd.sln b/3rd/3rd.sln index 0f4a5e3a..3bc074dc 100644 --- a/3rd/3rd.sln +++ b/3rd/3rd.sln @@ -2,7 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27428.2002 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv-1.19.2\libuv.vcxproj", "{33066374-88CB-CB8D-15DA-61032886329A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv\libuv.vcxproj", "{33066374-88CB-CB8D-15DA-61032886329A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/3rd/include/libuv/android-ifaddrs.h b/3rd/include/libuv/android-ifaddrs.h new file mode 100644 index 00000000..9cd19fec --- /dev/null +++ b/3rd/include/libuv/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 . Note that if 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 + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/3rd/include/libuv/pthread-barrier.h b/3rd/include/libuv/pthread-barrier.h new file mode 100644 index 00000000..07db9b8a --- /dev/null +++ b/3rd/include/libuv/pthread-barrier.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#if !defined(__MVS__) +#include /* sem_t */ +#endif + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 +#define UV__PTHREAD_BARRIER_FALLBACK 1 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#else +# define UV_BARRIER_STRUCT_PADDING 0 +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} 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 /* _UV_PTHREAD_BARRIER_ */ diff --git a/3rd/include/libuv/stdint-msvc2008.h b/3rd/include/libuv/stdint-msvc2008.h new file mode 100644 index 00000000..d02608a5 --- /dev/null +++ b/3rd/include/libuv/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 + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap 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 +#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 +#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/3rd/include/libuv/tree.h b/3rd/include/libuv/tree.h new file mode 100644 index 00000000..f936416e --- /dev/null +++ b/3rd/include/libuv/tree.h @@ -0,0 +1,768 @@ +/*- + * Copyright 2002 Niels Provos + * 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/3rd/include/libuv/uv-aix.h b/3rd/include/libuv/uv-aix.h new file mode 100644 index 00000000..7dc992fa --- /dev/null +++ b/3rd/include/libuv/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/3rd/include/libuv/uv-bsd.h b/3rd/include/libuv/uv-bsd.h new file mode 100644 index 00000000..2d72b3d7 --- /dev/null +++ b/3rd/include/libuv/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/3rd/include/libuv/uv-darwin.h b/3rd/include/libuv/uv-darwin.h new file mode 100644 index 00000000..d2264158 --- /dev/null +++ b/3rd/include/libuv/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 +# include +# include +# include +# 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/3rd/include/libuv/uv-errno.h b/3rd/include/libuv/uv-errno.h new file mode 100644 index 00000000..aa4d4509 --- /dev/null +++ b/3rd/include/libuv/uv-errno.h @@ -0,0 +1,437 @@ +/* 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 +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + +#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 UV__ERR(E2BIG) +#else +# define UV__E2BIG (-4093) +#endif + +#if defined(EACCES) && !defined(_WIN32) +# define UV__EACCES UV__ERR(EACCES) +#else +# define UV__EACCES (-4092) +#endif + +#if defined(EADDRINUSE) && !defined(_WIN32) +# define UV__EADDRINUSE UV__ERR(EADDRINUSE) +#else +# define UV__EADDRINUSE (-4091) +#endif + +#if defined(EADDRNOTAVAIL) && !defined(_WIN32) +# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL) +#else +# define UV__EADDRNOTAVAIL (-4090) +#endif + +#if defined(EAFNOSUPPORT) && !defined(_WIN32) +# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT) +#else +# define UV__EAFNOSUPPORT (-4089) +#endif + +#if defined(EAGAIN) && !defined(_WIN32) +# define UV__EAGAIN UV__ERR(EAGAIN) +#else +# define UV__EAGAIN (-4088) +#endif + +#if defined(EALREADY) && !defined(_WIN32) +# define UV__EALREADY UV__ERR(EALREADY) +#else +# define UV__EALREADY (-4084) +#endif + +#if defined(EBADF) && !defined(_WIN32) +# define UV__EBADF UV__ERR(EBADF) +#else +# define UV__EBADF (-4083) +#endif + +#if defined(EBUSY) && !defined(_WIN32) +# define UV__EBUSY UV__ERR(EBUSY) +#else +# define UV__EBUSY (-4082) +#endif + +#if defined(ECANCELED) && !defined(_WIN32) +# define UV__ECANCELED UV__ERR(ECANCELED) +#else +# define UV__ECANCELED (-4081) +#endif + +#if defined(ECHARSET) && !defined(_WIN32) +# define UV__ECHARSET UV__ERR(ECHARSET) +#else +# define UV__ECHARSET (-4080) +#endif + +#if defined(ECONNABORTED) && !defined(_WIN32) +# define UV__ECONNABORTED UV__ERR(ECONNABORTED) +#else +# define UV__ECONNABORTED (-4079) +#endif + +#if defined(ECONNREFUSED) && !defined(_WIN32) +# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED) +#else +# define UV__ECONNREFUSED (-4078) +#endif + +#if defined(ECONNRESET) && !defined(_WIN32) +# define UV__ECONNRESET UV__ERR(ECONNRESET) +#else +# define UV__ECONNRESET (-4077) +#endif + +#if defined(EDESTADDRREQ) && !defined(_WIN32) +# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ) +#else +# define UV__EDESTADDRREQ (-4076) +#endif + +#if defined(EEXIST) && !defined(_WIN32) +# define UV__EEXIST UV__ERR(EEXIST) +#else +# define UV__EEXIST (-4075) +#endif + +#if defined(EFAULT) && !defined(_WIN32) +# define UV__EFAULT UV__ERR(EFAULT) +#else +# define UV__EFAULT (-4074) +#endif + +#if defined(EHOSTUNREACH) && !defined(_WIN32) +# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH) +#else +# define UV__EHOSTUNREACH (-4073) +#endif + +#if defined(EINTR) && !defined(_WIN32) +# define UV__EINTR UV__ERR(EINTR) +#else +# define UV__EINTR (-4072) +#endif + +#if defined(EINVAL) && !defined(_WIN32) +# define UV__EINVAL UV__ERR(EINVAL) +#else +# define UV__EINVAL (-4071) +#endif + +#if defined(EIO) && !defined(_WIN32) +# define UV__EIO UV__ERR(EIO) +#else +# define UV__EIO (-4070) +#endif + +#if defined(EISCONN) && !defined(_WIN32) +# define UV__EISCONN UV__ERR(EISCONN) +#else +# define UV__EISCONN (-4069) +#endif + +#if defined(EISDIR) && !defined(_WIN32) +# define UV__EISDIR UV__ERR(EISDIR) +#else +# define UV__EISDIR (-4068) +#endif + +#if defined(ELOOP) && !defined(_WIN32) +# define UV__ELOOP UV__ERR(ELOOP) +#else +# define UV__ELOOP (-4067) +#endif + +#if defined(EMFILE) && !defined(_WIN32) +# define UV__EMFILE UV__ERR(EMFILE) +#else +# define UV__EMFILE (-4066) +#endif + +#if defined(EMSGSIZE) && !defined(_WIN32) +# define UV__EMSGSIZE UV__ERR(EMSGSIZE) +#else +# define UV__EMSGSIZE (-4065) +#endif + +#if defined(ENAMETOOLONG) && !defined(_WIN32) +# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG) +#else +# define UV__ENAMETOOLONG (-4064) +#endif + +#if defined(ENETDOWN) && !defined(_WIN32) +# define UV__ENETDOWN UV__ERR(ENETDOWN) +#else +# define UV__ENETDOWN (-4063) +#endif + +#if defined(ENETUNREACH) && !defined(_WIN32) +# define UV__ENETUNREACH UV__ERR(ENETUNREACH) +#else +# define UV__ENETUNREACH (-4062) +#endif + +#if defined(ENFILE) && !defined(_WIN32) +# define UV__ENFILE UV__ERR(ENFILE) +#else +# define UV__ENFILE (-4061) +#endif + +#if defined(ENOBUFS) && !defined(_WIN32) +# define UV__ENOBUFS UV__ERR(ENOBUFS) +#else +# define UV__ENOBUFS (-4060) +#endif + +#if defined(ENODEV) && !defined(_WIN32) +# define UV__ENODEV UV__ERR(ENODEV) +#else +# define UV__ENODEV (-4059) +#endif + +#if defined(ENOENT) && !defined(_WIN32) +# define UV__ENOENT UV__ERR(ENOENT) +#else +# define UV__ENOENT (-4058) +#endif + +#if defined(ENOMEM) && !defined(_WIN32) +# define UV__ENOMEM UV__ERR(ENOMEM) +#else +# define UV__ENOMEM (-4057) +#endif + +#if defined(ENONET) && !defined(_WIN32) +# define UV__ENONET UV__ERR(ENONET) +#else +# define UV__ENONET (-4056) +#endif + +#if defined(ENOSPC) && !defined(_WIN32) +# define UV__ENOSPC UV__ERR(ENOSPC) +#else +# define UV__ENOSPC (-4055) +#endif + +#if defined(ENOSYS) && !defined(_WIN32) +# define UV__ENOSYS UV__ERR(ENOSYS) +#else +# define UV__ENOSYS (-4054) +#endif + +#if defined(ENOTCONN) && !defined(_WIN32) +# define UV__ENOTCONN UV__ERR(ENOTCONN) +#else +# define UV__ENOTCONN (-4053) +#endif + +#if defined(ENOTDIR) && !defined(_WIN32) +# define UV__ENOTDIR UV__ERR(ENOTDIR) +#else +# define UV__ENOTDIR (-4052) +#endif + +#if defined(ENOTEMPTY) && !defined(_WIN32) +# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY) +#else +# define UV__ENOTEMPTY (-4051) +#endif + +#if defined(ENOTSOCK) && !defined(_WIN32) +# define UV__ENOTSOCK UV__ERR(ENOTSOCK) +#else +# define UV__ENOTSOCK (-4050) +#endif + +#if defined(ENOTSUP) && !defined(_WIN32) +# define UV__ENOTSUP UV__ERR(ENOTSUP) +#else +# define UV__ENOTSUP (-4049) +#endif + +#if defined(EPERM) && !defined(_WIN32) +# define UV__EPERM UV__ERR(EPERM) +#else +# define UV__EPERM (-4048) +#endif + +#if defined(EPIPE) && !defined(_WIN32) +# define UV__EPIPE UV__ERR(EPIPE) +#else +# define UV__EPIPE (-4047) +#endif + +#if defined(EPROTO) && !defined(_WIN32) +# define UV__EPROTO UV__ERR(EPROTO) +#else +# define UV__EPROTO UV__ERR(4046) +#endif + +#if defined(EPROTONOSUPPORT) && !defined(_WIN32) +# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT) +#else +# define UV__EPROTONOSUPPORT (-4045) +#endif + +#if defined(EPROTOTYPE) && !defined(_WIN32) +# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE) +#else +# define UV__EPROTOTYPE (-4044) +#endif + +#if defined(EROFS) && !defined(_WIN32) +# define UV__EROFS UV__ERR(EROFS) +#else +# define UV__EROFS (-4043) +#endif + +#if defined(ESHUTDOWN) && !defined(_WIN32) +# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN) +#else +# define UV__ESHUTDOWN (-4042) +#endif + +#if defined(ESPIPE) && !defined(_WIN32) +# define UV__ESPIPE UV__ERR(ESPIPE) +#else +# define UV__ESPIPE (-4041) +#endif + +#if defined(ESRCH) && !defined(_WIN32) +# define UV__ESRCH UV__ERR(ESRCH) +#else +# define UV__ESRCH (-4040) +#endif + +#if defined(ETIMEDOUT) && !defined(_WIN32) +# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT) +#else +# define UV__ETIMEDOUT (-4039) +#endif + +#if defined(ETXTBSY) && !defined(_WIN32) +# define UV__ETXTBSY UV__ERR(ETXTBSY) +#else +# define UV__ETXTBSY (-4038) +#endif + +#if defined(EXDEV) && !defined(_WIN32) +# define UV__EXDEV UV__ERR(EXDEV) +#else +# define UV__EXDEV (-4037) +#endif + +#if defined(EFBIG) && !defined(_WIN32) +# define UV__EFBIG UV__ERR(EFBIG) +#else +# define UV__EFBIG (-4036) +#endif + +#if defined(ENOPROTOOPT) && !defined(_WIN32) +# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT) +#else +# define UV__ENOPROTOOPT (-4035) +#endif + +#if defined(ERANGE) && !defined(_WIN32) +# define UV__ERANGE UV__ERR(ERANGE) +#else +# define UV__ERANGE (-4034) +#endif + +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO UV__ERR(ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + +#if defined(EMLINK) && !defined(_WIN32) +# define UV__EMLINK UV__ERR(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 UV__ERR(EHOSTDOWN) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) +# define UV__EHOSTDOWN (-64) +#else +# define UV__EHOSTDOWN (-4031) +#endif + +#if defined(EREMOTEIO) && !defined(_WIN32) +# define UV__EREMOTEIO UV__ERR(EREMOTEIO) +#else +# define UV__EREMOTEIO (-4030) +#endif + +#if defined(ENOTTY) && !defined(_WIN32) +# define UV__ENOTTY UV__ERR(ENOTTY) +#else +# define UV__ENOTTY (-4029) +#endif + + +#endif /* UV_ERRNO_H_ */ diff --git a/3rd/include/libuv/uv-linux.h b/3rd/include/libuv/uv-linux.h new file mode 100644 index 00000000..9b38405a --- /dev/null +++ b/3rd/include/libuv/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/3rd/include/libuv/uv-os390.h b/3rd/include/libuv/uv-os390.h new file mode 100644 index 00000000..39e7384d --- /dev/null +++ b/3rd/include/libuv/uv-os390.h @@ -0,0 +1,33 @@ +/* Copyright 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. + */ + +#ifndef UV_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#define UV_PLATFORM_LOOP_FIELDS \ + void* ep; \ + +#define UV_PLATFORM_FS_EVENT_FIELDS \ + char rfis_rftok[8]; \ + +#endif /* UV_MVS_H */ diff --git a/3rd/include/libuv/uv-posix.h b/3rd/include/libuv/uv-posix.h new file mode 100644 index 00000000..9a96634d --- /dev/null +++ b/3rd/include/libuv/uv-posix.h @@ -0,0 +1,31 @@ +/* Copyright 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. + */ + +#ifndef UV_POSIX_H +#define UV_POSIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + struct pollfd* poll_fds; \ + size_t poll_fds_used; \ + size_t poll_fds_size; \ + unsigned char poll_fds_iterating; \ + +#endif /* UV_POSIX_H */ diff --git a/3rd/include/libuv/uv-sunos.h b/3rd/include/libuv/uv-sunos.h new file mode 100644 index 00000000..04216642 --- /dev/null +++ b/3rd/include/libuv/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 +#include + +/* 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/3rd/include/libuv/uv-threadpool.h b/3rd/include/libuv/uv-threadpool.h new file mode 100644 index 00000000..9708ebdd --- /dev/null +++ b/3rd/include/libuv/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/3rd/include/libuv/uv-unix.h b/3rd/include/libuv/uv-unix.h new file mode 100644 index 00000000..da32f86e --- /dev/null +++ b/3rd/include/libuv/uv-unix.h @@ -0,0 +1,464 @@ +/* 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(__MVS__) +#include +#endif +#include +#include + +#include "uv-threadpool.h" + +#if defined(__linux__) +# include "uv-linux.h" +#elif defined (__MVS__) +# include "uv-os390.h" +#elif defined(_PASE) +# include "uv-posix.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(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) +# include "uv-bsd.h" +#elif defined(__CYGWIN__) || defined(__MSYS__) +# include "uv-posix.h" +#endif + +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.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_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 +}; + +#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; +typedef pid_t uv_pid_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; +typedef pthread_barrier_t uv_barrier_t; + + +/* 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]; \ + void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ + uv__io_t async_io_watcher; \ + int async_wfd; \ + 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 \ + +/* fs open() flags supported on this platform: */ +#if defined(O_APPEND) +# define UV_FS_O_APPEND O_APPEND +#else +# define UV_FS_O_APPEND 0 +#endif +#if defined(O_CREAT) +# define UV_FS_O_CREAT O_CREAT +#else +# define UV_FS_O_CREAT 0 +#endif +#if defined(O_DIRECT) +# define UV_FS_O_DIRECT O_DIRECT +#else +# define UV_FS_O_DIRECT 0 +#endif +#if defined(O_DIRECTORY) +# define UV_FS_O_DIRECTORY O_DIRECTORY +#else +# define UV_FS_O_DIRECTORY 0 +#endif +#if defined(O_DSYNC) +# define UV_FS_O_DSYNC O_DSYNC +#else +# define UV_FS_O_DSYNC 0 +#endif +#if defined(O_EXCL) +# define UV_FS_O_EXCL O_EXCL +#else +# define UV_FS_O_EXCL 0 +#endif +#if defined(O_EXLOCK) +# define UV_FS_O_EXLOCK O_EXLOCK +#else +# define UV_FS_O_EXLOCK 0 +#endif +#if defined(O_NOATIME) +# define UV_FS_O_NOATIME O_NOATIME +#else +# define UV_FS_O_NOATIME 0 +#endif +#if defined(O_NOCTTY) +# define UV_FS_O_NOCTTY O_NOCTTY +#else +# define UV_FS_O_NOCTTY 0 +#endif +#if defined(O_NOFOLLOW) +# define UV_FS_O_NOFOLLOW O_NOFOLLOW +#else +# define UV_FS_O_NOFOLLOW 0 +#endif +#if defined(O_NONBLOCK) +# define UV_FS_O_NONBLOCK O_NONBLOCK +#else +# define UV_FS_O_NONBLOCK 0 +#endif +#if defined(O_RDONLY) +# define UV_FS_O_RDONLY O_RDONLY +#else +# define UV_FS_O_RDONLY 0 +#endif +#if defined(O_RDWR) +# define UV_FS_O_RDWR O_RDWR +#else +# define UV_FS_O_RDWR 0 +#endif +#if defined(O_SYMLINK) +# define UV_FS_O_SYMLINK O_SYMLINK +#else +# define UV_FS_O_SYMLINK 0 +#endif +#if defined(O_SYNC) +# define UV_FS_O_SYNC O_SYNC +#else +# define UV_FS_O_SYNC 0 +#endif +#if defined(O_TRUNC) +# define UV_FS_O_TRUNC O_TRUNC +#else +# define UV_FS_O_TRUNC 0 +#endif +#if defined(O_WRONLY) +# define UV_FS_O_WRONLY O_WRONLY +#else +# define UV_FS_O_WRONLY 0 +#endif + +/* fs open() flags supported on other platforms: */ +#define UV_FS_O_RANDOM 0 +#define UV_FS_O_SHORT_LIVED 0 +#define UV_FS_O_SEQUENTIAL 0 +#define UV_FS_O_TEMPORARY 0 + +#endif /* UV_UNIX_H */ diff --git a/3rd/include/libuv/uv-version.h b/3rd/include/libuv/uv-version.h new file mode 100644 index 00000000..c2753d51 --- /dev/null +++ b/3rd/include/libuv/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 19 +#define UV_VERSION_PATCH 2 +#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/3rd/include/libuv/uv-win.h b/3rd/include/libuv/uv-win.h new file mode 100644 index 00000000..4c6c50a2 --- /dev/null +++ b/3rd/include/libuv/uv-win.h @@ -0,0 +1,676 @@ +/* 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 0x0600 +#endif + +#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) +typedef intptr_t ssize_t; +# define _SSIZE_T_ +# define _SSIZE_T_DEFINED +#endif + +#include + +#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 +#include +#include + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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 int uv_pid_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 */ \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + 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; + +#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 + +/* fs open() flags supported on this platform: */ +#define UV_FS_O_APPEND _O_APPEND +#define UV_FS_O_CREAT _O_CREAT +#define UV_FS_O_EXCL _O_EXCL +#define UV_FS_O_RANDOM _O_RANDOM +#define UV_FS_O_RDONLY _O_RDONLY +#define UV_FS_O_RDWR _O_RDWR +#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL +#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED +#define UV_FS_O_TEMPORARY _O_TEMPORARY +#define UV_FS_O_TRUNC _O_TRUNC +#define UV_FS_O_WRONLY _O_WRONLY + +/* fs open() flags supported on other platforms (or mapped on this platform): */ +#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECTORY 0 +#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ +#define UV_FS_O_NOATIME 0 +#define UV_FS_O_NOCTTY 0 +#define UV_FS_O_NOFOLLOW 0 +#define UV_FS_O_NONBLOCK 0 +#define UV_FS_O_SYMLINK 0 +#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/3rd/include/libuv/uv.h b/3rd/include/libuv/uv.h new file mode 100644 index 00000000..9794d996 --- /dev/null +++ b/3rd/include/libuv/uv.h @@ -0,0 +1,1567 @@ +/* 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 +#include + +#if defined(_MSC_VER) && _MSC_VER < 1600 +# include "stdint-msvc2008.h" +#else +# include +#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") \ + XX(EREMOTEIO, "remote I/O error") \ + XX(ENOTTY, "inappropriate ioctl for device") \ + +#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 struct uv_passwd_s uv_passwd_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_loop_fork(uv_loop_t* loop); + +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 int uv_translate_sys_error(int sys_errno); + +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 uv_handle_type uv_handle_get_type(const uv_handle_t* handle); +UV_EXTERN const char* uv_handle_type_name(uv_handle_type type); +UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle); +UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle); +UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data); + +UV_EXTERN size_t uv_req_size(uv_req_type type); +UV_EXTERN void* uv_req_get_data(const uv_req_t* req); +UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data); +UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req); +UV_EXTERN const char* uv_req_type_name(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 size_t uv_stream_get_write_queue_size(const uv_stream_t* stream); + +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_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); +UV_EXTERN size_t uv_udp_get_send_queue_count(const 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(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); +UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); + + +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_DISCONNECT = 4, + UV_PRIORITIZED = 8 +}; + +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_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*); + + +/* + * 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; +}; + +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + +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); +UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); + +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_os_tmpdir(char* buffer, size_t* size); +UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); +UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); +UV_EXTERN uv_pid_t uv_os_getpid(void); +UV_EXTERN uv_pid_t uv_os_getppid(void); + +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); + +UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); +UV_EXTERN int uv_os_setenv(const char* name, const char* value); +UV_EXTERN int uv_os_unsetenv(const char* name); + +UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); + + +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_COPYFILE +} 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 uv_fs_type uv_fs_get_type(const uv_fs_t*); +UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); +UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); +UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); +UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); + +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); +/* + * This flag can be used with uv_fs_copyfile() to return an error if the + * destination already exists. + */ +#define UV_FS_COPYFILE_EXCL 0x0001 + +UV_EXTERN int uv_fs_copyfile(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_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_start_oneshot(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); + +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE (IFNAMSIZ + 1) +#else +# define UV_IF_NAMESIZE (16 + 1) +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, + char* buffer, + size_t* size); +UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, + char* buffer, + size_t* size); + +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 int uv_mutex_init_recursive(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 +}; + +UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); +UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); + +/* 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 +#undef UV__ERR + +#ifdef __cplusplus +} +#endif +#endif /* UV_H */ diff --git a/asynio/asynio.vcxproj b/asynio/asynio.vcxproj index d501640c..a3f1c98b 100644 --- a/asynio/asynio.vcxproj +++ b/asynio/asynio.vcxproj @@ -46,16 +46,18 @@ $(SolutionDir)\bin\$(IntDir) $(Configuration)\ true + ../3rd/$(IntDir);$(LibraryPath) $(SolutionDir)\bin\$(IntDir) $(Configuration)\ false + ../3rd/$(IntDir);$(LibraryPath) Disabled - ../include;../extensions/include;%(AdditionalIncludeDirectories) + ../include;../extensions/include;../3rd/include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FILEIO_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks @@ -73,14 +75,14 @@ Windows ..\lib\$(IntDir)$(TargetName).lib MachineX86 - wsock32.lib;%(AdditionalDependencies) + wsock32.lib;libuv.lib;%(AdditionalDependencies) MaxSpeed true - ../include;../extensions/include;%(AdditionalIncludeDirectories) + ../include;../extensions/include;../3rd/include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;FILEIO_EXPORTS;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -98,7 +100,7 @@ true ..\lib\$(IntDir)$(TargetName).lib MachineX86 - wsock32.lib;%(AdditionalDependencies) + wsock32.lib;libuv.lib;%(AdditionalDependencies) @@ -114,6 +116,9 @@ + + + @@ -124,6 +129,10 @@ + + + + diff --git a/asynio/ioeventdef.h b/asynio/ioeventdef.h new file mode 100644 index 00000000..1f8a1bc2 --- /dev/null +++ b/asynio/ioeventdef.h @@ -0,0 +1,82 @@ +#ifndef _IOEVENTDEF_H_ +#define _IOEVENTDEF_H_ + + +#include + +template +struct evptr +{ +public: + evptr(const _Traits& tr = _Traits()) : m_tr(tr) + { + m_p = (_Ptr)m_tr.default_value(); + } + evptr(_Ptr p, const _Traits& tr = _Traits()) : m_p(p), m_tr(tr) + { + + } + ~evptr() + { + m_tr.destroy(m_p); + } + evptr& operator = (_Ptr p) + { + if (!m_tr.equal_to(m_p, p)) + { + m_tr.destroy(m_p); m_p = p; + } + return *this; + } + + void dispose() + { + m_tr.destroy(m_p); + m_p = (_Ptr)m_tr.default_value(); + } + operator _Ptr () const + { + return m_p; + } + _Ptr operator -> () const + { + return m_p; + } + + _Ptr ptr() + { + return m_p; + } + const _Ptr ptr() const + { + return m_p; + } + +public: + _Ptr m_p; + _Traits m_tr; +private: + evptr(const evptr&); + evptr& operator = (const evptr&); +}; + +struct uv_loop_handler +{ + static uv_loop_t* default_value() { + return uv_loop_new(); + + } + template static bool equal_to(_Ptr l, _Ptr r) { + return l == r; + } + template static void destroy(_Ptr p) { + if (p != NULL) + { + uv_loop_delete(p); + p = NULL; + } + } +}; + +#endif // _IOEVENTDEF_H_ + diff --git a/asynio/ioeventloop.cpp b/asynio/ioeventloop.cpp new file mode 100644 index 00000000..561486dc --- /dev/null +++ b/asynio/ioeventloop.cpp @@ -0,0 +1,2 @@ +#include "ioeventloop.h" + diff --git a/asynio/ioeventloop.h b/asynio/ioeventloop.h new file mode 100644 index 00000000..679482d3 --- /dev/null +++ b/asynio/ioeventloop.h @@ -0,0 +1,51 @@ +#ifndef _IOEVENTLOOP_H_ +#define _IOEVENTLOOP_H_ + +#include "ioeventdef.h" + +typedef void* (*EventMsgProc)(unsigned long msgid,WPARAM wParam,LPARAM lParam); + +class ioeventbase +{ +public: + ioeventbase() { + m_MsgProc = NULL; + } + virtual ~ioeventbase() { + + } +public: + void SetMsgProc(EventMsgProc Proc) + { + if (m_MsgProc != NULL) + m_MsgProc = Proc; + else { + + } + } + uv_loop_t* GetEv() { + return uvloopbase; + } + + int DoRun() { + return uv_run(GetEv(), UV_RUN_DEFAULT); + } + int DoOnceRun() { + return uv_run(GetEv(), UV_RUN_ONCE); + } + int DoWaitRun() { + return uv_run(GetEv(), UV_RUN_NOWAIT); + } + int DoClose() { + uv_stop(GetEv()); + } + +protected: + evptr uvloopbase; + EventMsgProc m_MsgProc; +}; + + + + +#endif \ No newline at end of file diff --git a/asynio/iostreambase.cpp b/asynio/iostreambase.cpp new file mode 100644 index 00000000..5684bfc3 --- /dev/null +++ b/asynio/iostreambase.cpp @@ -0,0 +1 @@ +#include "iostreambase.h" \ No newline at end of file diff --git a/asynio/iostreambase.h b/asynio/iostreambase.h new file mode 100644 index 00000000..3794c218 --- /dev/null +++ b/asynio/iostreambase.h @@ -0,0 +1,19 @@ +#ifndef _IOSTREAMBASE_H_ +#define _IOSTREAMBASE_H_ + + +#include "ioeventloop.h" + +class io_stream_t : public ioeventbase +{ +public: + io_stream_t() { + + } + virtual ~io_stream_t() { + + } +}; + + +#endif diff --git a/asynio/iotcpbase.cpp b/asynio/iotcpbase.cpp new file mode 100644 index 00000000..a26aecff --- /dev/null +++ b/asynio/iotcpbase.cpp @@ -0,0 +1,2 @@ +#include "iotcpbase.h" + diff --git a/asynio/iotcpbase.h b/asynio/iotcpbase.h new file mode 100644 index 00000000..e790ccd5 --- /dev/null +++ b/asynio/iotcpbase.h @@ -0,0 +1,44 @@ +#ifndef _IOTCPBASE_H_ +#define _IOTCPBASE_H_ + +#include "iostreambase.h" + +class iotcpbase : public io_stream_t +{ +public: + iotcpbase() { + tcphandler = NULL; + uv_tcp_init(GetEv(), tcphandler); + } + virtual ~iotcpbase() { + + } + int AattchToIo(SOCKET sock) { + return uv_tcp_open(tcphandler, sock); + } +private: + uv_tcp_t *tcphandler; +}; + + +class io_tcp_s : public iotcpbase +{ +public: + io_tcp_s() { + + } + virtual ~io_tcp_s() { + + } +}; +class io_tcp_c : public iotcpbase +{ +public: + io_tcp_c() { + + } + virtual ~io_tcp_c() { + + } +}; +#endif diff --git a/asynio/tcpsocketimpl.h b/asynio/tcpsocketimpl.h index a7dff092..2151ae68 100644 --- a/asynio/tcpsocketimpl.h +++ b/asynio/tcpsocketimpl.h @@ -31,13 +31,11 @@ public: ////////////////////////////////////////////////////////////////////////// SOCKET m_socketFd; - - - private: + }; -- Gitee

IlG||>&m()vh!j1bs%Xt$;1BU+W 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 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 a 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: + + :: + + void cb(uv_write_t* req, int status) { + /* Logic which handles the write result */ + } + + 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, cb); + uv_write(&req2, stream, b, 2, cb); + + .. note:: + The memory pointed to by the buffers must remain valid until the callback gets called. + This also holds for :c:func:`uv_write2`. + +.. 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. + +.. c:function:: size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) + + Returns `stream->write_queue_size`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/tcp.rst b/3rd/libuv-1.19.2/docs/src/tcp.rst new file mode 100644 index 00000000..e761b460 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/tcp.rst @@ -0,0 +1,115 @@ + +.. _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 `TCP_NODELAY`, which disables 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``. + + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + + The callback is made when the connection has been established or when a + connection error happened. + + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + +.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/threading.rst b/3rd/libuv-1.19.2/docs/src/threading.rst new file mode 100644 index 00000000..89bb4a6f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/threading.rst @@ -0,0 +1,168 @@ + +.. _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:: int uv_mutex_init_recursive(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:: + 1. Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` + and :c:func:`uv_cond_timedwait`. + 2. The timeout parameter for :c:func:`uv_cond_timedwait` is relative to the time + at which function is called. + 3. On z/OS, the timeout parameter for :c:func:`uv_cond_timedwait` is converted to an + absolute system time at which the wait expires. If the current system clock time + passes the absolute time calculated before the condition is signaled, an ETIMEDOUT + error results. After the wait begins, the wait time is not affected by changes + to the system clock. + +.. 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/3rd/libuv-1.19.2/docs/src/threadpool.rst b/3rd/libuv-1.19.2/docs/src/threadpool.rst new file mode 100644 index 00000000..93bd236d --- /dev/null +++ b/3rd/libuv-1.19.2/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 file system +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/3rd/libuv-1.19.2/docs/src/timer.rst b/3rd/libuv-1.19.2/docs/src/timer.rst new file mode 100644 index 00000000..e163e288 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/timer.rst @@ -0,0 +1,81 @@ + +.. _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. + + .. note:: + Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. + + If the timer is already active, it is simply updated. + +.. 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/3rd/libuv-1.19.2/docs/src/tty.rst b/3rd/libuv-1.19.2/docs/src/tty.rst new file mode 100644 index 00000000..01a05852 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/tty.rst @@ -0,0 +1,101 @@ + +.. _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 determine the path of the fd of the terminal + using :man:`ttyname_r(3)`, open it, 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. + + This function is not thread safe on systems that don't support + ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. + + .. note:: + If reopening the TTY fails, libuv falls back to blocking writes for + non-readable TTY streams. + + .. versionchanged:: 1.9.0: the path of the TTY is determined by + :man:`ttyname_r(3)`. In earlier versions libuv opened + `/dev/tty` instead. + + .. 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/3rd/libuv-1.19.2/docs/src/udp.rst b/3rd/libuv-1.19.2/docs/src/udp.rst new file mode 100644 index 00000000..81488285 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/udp.rst @@ -0,0 +1,314 @@ + +.. _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. + + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + + :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. + + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + +.. 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. + +.. c:function:: size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) + + Returns `handle->send_queue_size`. + + .. versionadded:: 1.19.0 + +.. c:function:: size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) + + Returns `handle->send_queue_count`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/upgrading.rst b/3rd/libuv-1.19.2/docs/src/upgrading.rst new file mode 100644 index 00000000..32840c26 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/upgrading.rst @@ -0,0 +1,11 @@ +.. _upgrading: + +Upgrading +========= + +Migration guides for different libuv versions, starting with 1.0. + +.. toctree:: + :maxdepth: 1 + + migration_010_100 diff --git a/3rd/libuv-1.19.2/docs/src/version.rst b/3rd/libuv-1.19.2/docs/src/version.rst new file mode 100644 index 00000000..e1715b2d --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/gyp_uv.py b/3rd/libuv-1.19.2/gyp_uv.py new file mode 100644 index 00000000..c2add5ca --- /dev/null +++ b/3rd/libuv-1.19.2/gyp_uv.py @@ -0,0 +1,73 @@ +#!/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 == 'AMD64': return 'x64' + 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:] + args.extend('-I common.gypi test/test.gyp'.split(' ')) + 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/3rd/libuv-1.19.2/img/banner.png b/3rd/libuv-1.19.2/img/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..7187daa2e574daa7aa84d81fbddcf6ec3e571d24 GIT binary patch literal 44102 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

IlG||>&m()vh!j1bs%Xt$;1BU+W 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 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 a 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: - - :: - - void cb(uv_write_t* req, int status) { - /* Logic which handles the write result */ - } - - 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, cb); - uv_write(&req2, stream, b, 2, cb); - - .. note:: - The memory pointed to by the buffers must remain valid until the callback gets called. - This also holds for :c:func:`uv_write2`. - -.. 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. - -.. c:function:: size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) - - Returns `stream->write_queue_size`. - - .. versionadded:: 1.19.0 - -.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/tcp.rst b/3rd/libuv-1.19.2/docs/src/tcp.rst deleted file mode 100644 index e761b460..00000000 --- a/3rd/libuv-1.19.2/docs/src/tcp.rst +++ /dev/null @@ -1,115 +0,0 @@ - -.. _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 `TCP_NODELAY`, which disables 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``. - - On Windows if the `addr` is initialized to point to an unspecified address - (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. - This is done to match the behavior of Linux systems. - - The callback is made when the connection has been established or when a - connection error happened. - - .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` - mapping - -.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/threading.rst b/3rd/libuv-1.19.2/docs/src/threading.rst deleted file mode 100644 index 89bb4a6f..00000000 --- a/3rd/libuv-1.19.2/docs/src/threading.rst +++ /dev/null @@ -1,168 +0,0 @@ - -.. _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:: int uv_mutex_init_recursive(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:: - 1. Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` - and :c:func:`uv_cond_timedwait`. - 2. The timeout parameter for :c:func:`uv_cond_timedwait` is relative to the time - at which function is called. - 3. On z/OS, the timeout parameter for :c:func:`uv_cond_timedwait` is converted to an - absolute system time at which the wait expires. If the current system clock time - passes the absolute time calculated before the condition is signaled, an ETIMEDOUT - error results. After the wait begins, the wait time is not affected by changes - to the system clock. - -.. 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/3rd/libuv-1.19.2/docs/src/threadpool.rst b/3rd/libuv-1.19.2/docs/src/threadpool.rst deleted file mode 100644 index 93bd236d..00000000 --- a/3rd/libuv-1.19.2/docs/src/threadpool.rst +++ /dev/null @@ -1,67 +0,0 @@ - -.. _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 file system -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/3rd/libuv-1.19.2/docs/src/timer.rst b/3rd/libuv-1.19.2/docs/src/timer.rst deleted file mode 100644 index e163e288..00000000 --- a/3rd/libuv-1.19.2/docs/src/timer.rst +++ /dev/null @@ -1,81 +0,0 @@ - -.. _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. - - .. note:: - Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. - - If the timer is already active, it is simply updated. - -.. 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/3rd/libuv-1.19.2/docs/src/tty.rst b/3rd/libuv-1.19.2/docs/src/tty.rst deleted file mode 100644 index 01a05852..00000000 --- a/3rd/libuv-1.19.2/docs/src/tty.rst +++ /dev/null @@ -1,101 +0,0 @@ - -.. _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 determine the path of the fd of the terminal - using :man:`ttyname_r(3)`, open it, 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. - - This function is not thread safe on systems that don't support - ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. - - .. note:: - If reopening the TTY fails, libuv falls back to blocking writes for - non-readable TTY streams. - - .. versionchanged:: 1.9.0: the path of the TTY is determined by - :man:`ttyname_r(3)`. In earlier versions libuv opened - `/dev/tty` instead. - - .. 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/3rd/libuv-1.19.2/docs/src/udp.rst b/3rd/libuv-1.19.2/docs/src/udp.rst deleted file mode 100644 index 81488285..00000000 --- a/3rd/libuv-1.19.2/docs/src/udp.rst +++ /dev/null @@ -1,314 +0,0 @@ - -.. _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. - - On Windows if the `addr` is initialized to point to an unspecified address - (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. - This is done to match the behavior of Linux systems. - - :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. - - .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` - mapping - -.. 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. - -.. c:function:: size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) - - Returns `handle->send_queue_size`. - - .. versionadded:: 1.19.0 - -.. c:function:: size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) - - Returns `handle->send_queue_count`. - - .. versionadded:: 1.19.0 - -.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/upgrading.rst b/3rd/libuv-1.19.2/docs/src/upgrading.rst deleted file mode 100644 index 32840c26..00000000 --- a/3rd/libuv-1.19.2/docs/src/upgrading.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _upgrading: - -Upgrading -========= - -Migration guides for different libuv versions, starting with 1.0. - -.. toctree:: - :maxdepth: 1 - - migration_010_100 diff --git a/3rd/libuv-1.19.2/docs/src/version.rst b/3rd/libuv-1.19.2/docs/src/version.rst deleted file mode 100644 index e1715b2d..00000000 --- a/3rd/libuv-1.19.2/docs/src/version.rst +++ /dev/null @@ -1,60 +0,0 @@ - -.. _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/3rd/libuv-1.19.2/gyp_uv.py b/3rd/libuv-1.19.2/gyp_uv.py deleted file mode 100644 index c2add5ca..00000000 --- a/3rd/libuv-1.19.2/gyp_uv.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/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 == 'AMD64': return 'x64' - 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:] - args.extend('-I common.gypi test/test.gyp'.split(' ')) - 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/3rd/libuv-1.19.2/img/banner.png b/3rd/libuv-1.19.2/img/banner.png deleted file mode 100644 index 7187daa2e574daa7aa84d81fbddcf6ec3e571d24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44102 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

IlG||>&m()vh!j1bs%Xt$;1BU+W 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 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 a 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: + + :: + + void cb(uv_write_t* req, int status) { + /* Logic which handles the write result */ + } + + 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, cb); + uv_write(&req2, stream, b, 2, cb); + + .. note:: + The memory pointed to by the buffers must remain valid until the callback gets called. + This also holds for :c:func:`uv_write2`. + +.. 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. + +.. c:function:: size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) + + Returns `stream->write_queue_size`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/tcp.rst b/3rd/libuv-1.19.2/docs/src/tcp.rst new file mode 100644 index 00000000..e761b460 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/tcp.rst @@ -0,0 +1,115 @@ + +.. _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 `TCP_NODELAY`, which disables 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``. + + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + + The callback is made when the connection has been established or when a + connection error happened. + + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + +.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/threading.rst b/3rd/libuv-1.19.2/docs/src/threading.rst new file mode 100644 index 00000000..89bb4a6f --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/threading.rst @@ -0,0 +1,168 @@ + +.. _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:: int uv_mutex_init_recursive(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:: + 1. Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` + and :c:func:`uv_cond_timedwait`. + 2. The timeout parameter for :c:func:`uv_cond_timedwait` is relative to the time + at which function is called. + 3. On z/OS, the timeout parameter for :c:func:`uv_cond_timedwait` is converted to an + absolute system time at which the wait expires. If the current system clock time + passes the absolute time calculated before the condition is signaled, an ETIMEDOUT + error results. After the wait begins, the wait time is not affected by changes + to the system clock. + +.. 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/3rd/libuv-1.19.2/docs/src/threadpool.rst b/3rd/libuv-1.19.2/docs/src/threadpool.rst new file mode 100644 index 00000000..93bd236d --- /dev/null +++ b/3rd/libuv-1.19.2/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 file system +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/3rd/libuv-1.19.2/docs/src/timer.rst b/3rd/libuv-1.19.2/docs/src/timer.rst new file mode 100644 index 00000000..e163e288 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/timer.rst @@ -0,0 +1,81 @@ + +.. _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. + + .. note:: + Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. + + If the timer is already active, it is simply updated. + +.. 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/3rd/libuv-1.19.2/docs/src/tty.rst b/3rd/libuv-1.19.2/docs/src/tty.rst new file mode 100644 index 00000000..01a05852 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/tty.rst @@ -0,0 +1,101 @@ + +.. _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 determine the path of the fd of the terminal + using :man:`ttyname_r(3)`, open it, 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. + + This function is not thread safe on systems that don't support + ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. + + .. note:: + If reopening the TTY fails, libuv falls back to blocking writes for + non-readable TTY streams. + + .. versionchanged:: 1.9.0: the path of the TTY is determined by + :man:`ttyname_r(3)`. In earlier versions libuv opened + `/dev/tty` instead. + + .. 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/3rd/libuv-1.19.2/docs/src/udp.rst b/3rd/libuv-1.19.2/docs/src/udp.rst new file mode 100644 index 00000000..81488285 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/udp.rst @@ -0,0 +1,314 @@ + +.. _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. + + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + + :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. + + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + +.. 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. + +.. c:function:: size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) + + Returns `handle->send_queue_size`. + + .. versionadded:: 1.19.0 + +.. c:function:: size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) + + Returns `handle->send_queue_count`. + + .. versionadded:: 1.19.0 + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/3rd/libuv-1.19.2/docs/src/upgrading.rst b/3rd/libuv-1.19.2/docs/src/upgrading.rst new file mode 100644 index 00000000..32840c26 --- /dev/null +++ b/3rd/libuv-1.19.2/docs/src/upgrading.rst @@ -0,0 +1,11 @@ +.. _upgrading: + +Upgrading +========= + +Migration guides for different libuv versions, starting with 1.0. + +.. toctree:: + :maxdepth: 1 + + migration_010_100 diff --git a/3rd/libuv-1.19.2/docs/src/version.rst b/3rd/libuv-1.19.2/docs/src/version.rst new file mode 100644 index 00000000..e1715b2d --- /dev/null +++ b/3rd/libuv-1.19.2/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/3rd/libuv-1.19.2/gyp_uv.py b/3rd/libuv-1.19.2/gyp_uv.py new file mode 100644 index 00000000..c2add5ca --- /dev/null +++ b/3rd/libuv-1.19.2/gyp_uv.py @@ -0,0 +1,73 @@ +#!/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 == 'AMD64': return 'x64' + 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:] + args.extend('-I common.gypi test/test.gyp'.split(' ')) + 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/3rd/libuv-1.19.2/img/banner.png b/3rd/libuv-1.19.2/img/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..7187daa2e574daa7aa84d81fbddcf6ec3e571d24 GIT binary patch literal 44102 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