diff options
author | Fedor Indutny <fedor@indutny.com> | 2014-08-07 15:03:17 +0400 |
---|---|---|
committer | Fedor Indutny <fedor@indutny.com> | 2014-08-07 15:03:17 +0400 |
commit | e49429ebd2fe0b7c24e2ee533311dd97f6febd1f (patch) | |
tree | d958c7f24638bc13ce3f17211e914828bad2fc85 /deps/uv | |
parent | aa3b4b4d106415b3afbc31df0db2476a04c997f1 (diff) | |
download | node-new-e49429ebd2fe0b7c24e2ee533311dd97f6febd1f.tar.gz |
deps: update libuv to v0.11.28
Diffstat (limited to 'deps/uv')
60 files changed, 3243 insertions, 928 deletions
diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 89c1adec4d..2ca07c8381 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -1,3 +1,4 @@ +Aaron Bieber <qbit@deftly.net> <deftly@gmail.com> Alan Gutierrez <alan@prettyrobots.com> <alan@blogometer.com> Andrius Bentkus <andrius.bentkus@gmail.com> <toxedvirus@gmail.com> Bert Belder <bertbelder@gmail.com> <info@2bs.nl> @@ -5,6 +6,7 @@ Bert Belder <bertbelder@gmail.com> <user@ChrUbuntu.(none)> Brandon Philips <brandon.philips@rackspace.com> <brandon@ifup.org> Brian White <mscdex@mscdex.net> Brian White <mscdex@mscdex.net> <mscdex@gmail.com> +Caleb James DeLisle <cjd@hyperboria.ca> <cjd@cjdns.fr> Christoph Iserlohn <christoph.iserlohn@innoq.com> Fedor Indutny <fedor.indutny@gmail.com> <fedor@indutny.com> Frank Denis <github@pureftpd.org> @@ -15,6 +17,8 @@ Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu> Maciej MaĆecki <maciej.malecki@notimplemented.org> <me@mmalecki.com> Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com> Rasmus Christian Pedersen <ruysch@outlook.com> +Rasmus Christian Pedersen <ruysch@outlook.com> +Rasmus Christian Pedersen <ruysch@outlook.com> Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com> Rasmus Pedersen <ruysch@outlook.com> <zerhacken@yahoo.com> Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org> diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index e3de576233..19f911f113 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -146,3 +146,12 @@ HungMingWu <u9089000@gmail.com> Jay Satiro <raysatiro@yahoo.com> Leith Bade <leith@leithalweapon.geek.nz> Peter Atashian <retep998@gmail.com> +Tim Cooper <tim.cooper@layeh.com> +Caleb James DeLisle <cjd@hyperboria.ca> +Jameson Nash <vtjnash@gmail.com> +Graham Lee <ghmlee@ghmlee.com> +Andrew Low <Andrew_Low@ca.ibm.com> +Pavel Platto <hinidu@gmail.com> +Tony Kelman <tony@kelman.net> +John Firebaugh <john.firebaugh@gmail.com> +lilohuang <lilohuang@hotmail.com> diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 50d39893a2..db13f188c6 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,93 @@ -2014.06.28, Version 0.11.26 (Unstable) +2014.08.08, Version 0.11.28 (Unstable) + +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.06.28, Version 0.11.26 (Unstable), 115281a1058c4034d5c5ccedacb667fe3f6327ea Changes since version 0.11.25: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index ebcd8db2e2..861b632bbf 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -17,7 +17,7 @@ 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-version.h +include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h CLEANFILES = @@ -28,6 +28,7 @@ libuv_la_SOURCES = src/fs-poll.c \ src/heap-inl.h \ src/inet.c \ src/queue.h \ + src/threadpool.c \ src/uv-common.c \ src/uv-common.h \ src/version.c @@ -67,7 +68,6 @@ libuv_la_SOURCES += src/win/async.c \ src/win/stream-inl.h \ src/win/tcp.c \ src/win/thread.c \ - src/win/threadpool.c \ src/win/timer.c \ src/win/tty.c \ src/win/udp.c \ @@ -99,7 +99,6 @@ libuv_la_SOURCES += src/unix/async.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 @@ -197,6 +196,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-write-to-half-open-connection.c \ test/test-tcp-writealot.c \ test/test-tcp-try-write.c \ + test/test-tcp-write-queue-order.c \ test/test-thread.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ @@ -215,6 +215,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-open.c \ test/test-udp-options.c \ test/test-udp-send-and-recv.c \ + test/test-udp-send-immediate.c \ + test/test-udp-try-send.c \ test/test-walk-handles.c \ test/test-watcher-cross-stop.c test_run_tests_LDADD = libuv.la @@ -228,7 +230,7 @@ test_run_tests_SOURCES += test/runner-unix.c \ endif if AIX -test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 +test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT endif if SUNOS @@ -237,7 +239,7 @@ endif if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 +libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT libuv_la_SOURCES += src/unix/aix.c endif diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index a0b7cc941f..156f15dab1 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -26,6 +26,7 @@ CFLAGS += -Wall \ 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 \ @@ -42,6 +43,7 @@ INCLUDES = include/stdint-msvc2008.h \ OBJS = src/fs-poll.o \ src/inet.o \ + src/threadpool.o \ src/uv-common.o \ src/version.o \ src/win/async.o \ @@ -63,7 +65,6 @@ OBJS = src/fs-poll.o \ src/win/stream.o \ src/win/tcp.o \ src/win/thread.o \ - src/win/threadpool.o \ src/win/timer.o \ src/win/tty.o \ src/win/udp.o \ diff --git a/deps/uv/README.md b/deps/uv/README.md index e0e73591d5..364cf695c4 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -1,10 +1,12 @@ -# libuv +![libuv][libuv_banner] + +## Overview libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by [Node.js](http://nodejs.org), but it's also used by Mozilla's [Rust language](http://www.rust-lang.org/), [Luvit](http://luvit.io/), [Julia](http://julialang.org/), -[pyuv](https://crate.io/packages/pyuv/), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). +[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/joyent/libuv/wiki/Projects-that-use-libuv). ## Feature highlights @@ -141,3 +143,4 @@ See the [guidelines for contributing][]. [Python]: https://www.python.org/downloads/ [Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md +[libuv_banner]: https://raw.githubusercontent.com/joyent/libuv/master/img/banner.png diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 0423c8cea8..ac789524b5 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [0.11.26], [https://github.com/joyent/libuv/issues]) +AC_INIT([libuv], [0.11.28], [https://github.com/joyent/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index f0c59d0786..f5afc6da2d 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -6,6 +6,13 @@ import os import subprocess 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) @@ -94,6 +101,11 @@ if __name__ == '__main__': if not any(a.startswith('-Dcomponent=') for a in args): args.append('-Dcomponent=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/deps/uv/img/banner.png b/deps/uv/img/banner.png Binary files differnew file mode 100644 index 0000000000..7187daa2e5 --- /dev/null +++ b/deps/uv/img/banner.png diff --git a/deps/uv/img/logos.svg b/deps/uv/img/logos.svg new file mode 100644 index 0000000000..d6185f8b19 --- /dev/null +++ b/deps/uv/img/logos.svg @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="792pt" + height="612pt" + id="svg3069" + version="1.1" + inkscape:version="0.48.4 r9939" + sodipodi:docname="New document 3"> + <defs + id="defs3071"> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath70"> + <path + inkscape:connector-curvature="0" + d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z" + id="path72" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath70-6"> + <path + inkscape:connector-curvature="0" + d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z" + id="path72-5" /> + </clipPath> + </defs> + <sodipodi:namedview + inkscape:document-units="in" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.43415836" + inkscape:cx="508.42646" + inkscape:cy="359.27024" + inkscape:current-layer="layer1" + id="namedview3073" + showgrid="false" + inkscape:window-width="1010" + inkscape:window-height="702" + inkscape:window-x="441" + inkscape:window-y="267" + inkscape:window-maximized="0" /> + <metadata + id="metadata3075"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + transform="matrix(0.2288071,0,0,-0.2288071,130.84779,1169.4436)" + id="g66"> + <g + id="g68" + clip-path="url(#clipPath70)"> + <path + inkscape:connector-curvature="0" + d="m 3274.33,2372.2 c -42.27,-8.61 -87.28,-37.29 -122.12,-43.75 -77.01,-14.25 -122.4,-0.53 -81.76,16.27 59.03,24.45 253.75,30.55 274.1,175.05 20.36,144.5 6.1,209.66 -4.07,246.29 -4.87,17.57 -15.81,43.49 -25.9,65.76 -2.85,15.73 -6.59,29.07 -9.86,38.57 -1.82,4.29 -3.65,9.81 -5.46,16.78 0,0 -2.54,17.81 5.6,35.1 7.2,15.34 31.95,48.62 33.62,80.79 0.03,1.95 0.11,3.9 0.08,5.85 -0.1,2.18 -0.28,4.33 -0.63,6.48 l -0.18,1.9 c -3.17,18.05 -13.53,30.62 -27.6,39.98 -9.06,6.02 -21.4,7.92 -28.17,16.51 5.4,17.01 22.63,23.06 29.82,36.95 4.48,12.34 0.82,25.3 -5.99,37.08 -13.13,14.72 -38.92,27.49 -62.07,36.15 -28.97,10.87 -58.44,19.45 -78.35,35.06 -21.03,11.19 -35.17,32.83 -22.26,61.45 3.35,7.44 4.85,14.93 4.75,22.04 l -0.09,2.09 c -0.03,1.45 -0.23,2.76 -0.41,4.1 -0.15,1.04 -0.32,2.06 -0.55,3.08 l -0.47,1.77 -0.56,2.02 c -5.3,17.86 -33.44,22.88 -43.47,23.78 -22.72,2.04 -37.4,8.2 -49.46,12.01 9.7,-5.04 19.46,-11.78 31.9,-16.79 7.87,-3.21 19.17,-5.12 28.68,-8.29 l 0.09,0.02 c 0,0 17.55,-3.56 22.38,-15.78 4.84,-12.2 2.03,-22.9 0,-29.75 l -0.74,-1.99 c -1.75,-5.35 -3.72,-10.51 -4.13,-15.84 -1.65,-21.04 11.26,-32 18.12,-49.6 12.35,-11.73 29.93,-23.88 54.32,-34.88 21.92,-9.9 48.15,-15.89 64.4,-25.7 9.41,-5.68 26.55,-19.41 26.16,-29.4 -0.3,-7.65 -14.43,-18.09 -20.12,-25.7 -4.07,-5.42 -6.09,-12.62 -9.73,-17.74 -3.17,-5 -7.24,-8.22 -11.92,-8.22 -6.1,0 -20.01,-2.36 -10.86,-3.04 9.16,-0.68 32.91,-11.87 32.91,-11.87 l -0.02,-0.03 c 32.1,-13.28 53.67,-37.88 41.87,-72.96 -9.88,-29.39 -32.61,-53.97 -34.2,-86.3 -1.7,-34.4 14.07,-62.72 16.09,-90 3.41,-45.9 -3.18,-77.51 -12.06,-112.01 -4.17,-16.14 -6.39,-32.04 -10.06,-47.74 -15.68,-66.87 -56.09,-95.84 -110.68,-126.73 -23.67,-13.39 -49.07,-38.07 -74.45,-45.9 -4.09,-1.26 -10.39,0.66 -14.11,0 -23.38,-4.22 -44.42,-15.81 -68.41,-20.19 -22.59,-4.17 -46.27,-2.17 -73.08,-8.96 -13.6,-4.85 -31.03,-12.11 -41.21,-16.43 -15.74,-7.17 -31.16,-14.63 -46.55,-22.15 l -51.11,-29.2 c 0,0 -28.48,-16.49 3.06,-4.28 25.38,9.83 112.62,53.25 76.08,27.75 -25.2,-12.66 -38.87,-30.64 -61.16,-45.98 0,0 -74.99,-37.19 -86.24,-47.57 -12.37,-11.42 -27.49,-5.1 -37.41,-16.3 -11.65,-13.13 -25.94,-21.01 -36.13,-24.41 -10.17,-3.42 -21.7,-25.78 -37.31,-37.31 -15.61,-11.54 -49.52,-8.15 -79.38,-21.04 -29.85,-12.89 -60.79,-13.06 -60.79,-13.06 -2.96,-0.28 -5.83,-0.46 -8.58,-0.53 -1.18,-0.03 -2.27,-0.02 -3.4,-0.02 -17.46,-0.09 -30.81,3.32 -41.04,7.08 -12.47,4.58 -17.05,2.28 -14.25,0.76 2.8,-1.51 10.92,-9.11 10.92,-9.11 -34.83,0.04 -44.33,23.18 -60.37,40.37 7.29,1.04 28.08,-4.04 17.52,2.08 -20.85,9.97 -61.01,10.69 -61.8,34.67 -0.6,18.81 8.06,14.69 8.06,14.69 14.61,-25.44 59.69,-27.93 92.57,-27.57 61.24,0.74 102.68,34.32 142.82,53.32 13.01,7.82 28.21,18.1 28.21,18.1 l -0.08,-0.3 c 12.67,8.25 25.48,16.25 36.31,26.22 18.9,17.37 31.67,40.04 48.31,59.27 1.93,3.27 5.99,7.26 10.81,11.28 4.69,4.4 9.73,8.5 15.34,12.09 l 0.21,-0.45 2.18,1.46 -0.39,0.82 c 40.39,22.9 78.03,48.25 109.79,79.02 l 0.21,0.36 c 4.56,4.13 28.46,30.81 40,43.76 13.61,18.15 23.42,41.08 29.11,64.18 2.05,8.36 0.75,18.51 4.01,27.56 5.07,14.03 17.81,26.51 26.17,40.39 8.65,14.43 14.37,30.14 20.12,45.9 25.17,69.17 54.28,124.25 108.66,161.6 26.2,18.01 58.02,29.63 76.46,56.95 -13.39,-13.59 -30.82,-23.5 -51.87,-30.09 -59.79,-19.7 -98.68,-70.15 -118.23,-102.2 -15.01,-26.98 -26.61,-57.04 -35.14,-89.93 -2.83,40.54 -12.84,72.15 -26.17,102.84 -11.85,27.29 -22.33,56.15 -44.27,73.46 0,0 -0.84,-0.06 -4.25,1.99 -3.39,2.02 56.57,3.53 56.57,3.53 10.49,-0.38 21.17,-1.89 31.99,-3.29 2.03,0.22 4.51,0.1 7.56,-0.43 32.96,-5.82 67.21,6.45 88.55,21.98 11.08,8.06 30.34,14.52 46.32,18.89 0.26,0.69 1.82,1.47 5.81,2.23 0,0 24.42,7.63 50.37,14.76 17.58,4.81 30.38,8.5 39.27,12.89 5.15,3.28 10.05,7.22 13.85,11.91 7.61,9.39 7.76,20.66 14.1,36.73 6.31,16.03 15.96,28.49 16.1,42.24 0.45,45.08 -42.25,80.98 -88.54,56.95 45.58,11.75 77.9,-10.49 72.44,-53.28 -6.74,-52.87 -86.39,-92.05 -134.83,-112.01 -19.2,-7.91 -41.68,-17.9 -64.38,-20.19 -32.74,-3.32 -62.41,3.67 -90.56,1.84 -36.1,-2.38 -60.11,-21.47 -90.55,-23.89 -26.16,-2.07 -22.61,15.61 -45.31,17.62 -4.7,2.68 -18.98,0 -33.18,0.74 -39.25,-10.37 -64.5,7.57 -96.58,22.04 -23.14,10.45 -47.82,19.96 -72.44,22.04 -61.81,5.24 -99.39,-3.35 -149.91,2.01 -14.25,1.51 -43.81,3.31 -57.85,8.57 -43.71,16.35 -77.17,10.42 -124.65,11.1 -34.54,0.5 -66.59,2.31 -88.15,-1.47 -5.88,-1.06 -11.84,-2.57 -18.12,-3.67 -46.27,-8.09 -116.76,-12.28 -114.69,-53.26 3.44,2.35 2.48,8.74 8.04,9.18 -0.2,-7.53 -0.39,-15.05 2.01,-20.21 -26.91,0.7 -42.78,19.28 -42.25,40.41 0.9,35.93 58.71,50.95 98.59,60.61 39.98,9.64 81.5,20.94 110.69,25.7 -69.91,-10.27 -143.86,-16.88 -197.22,-42.25 -0.75,2.76 -1.23,5.42 -1.55,7.98 -4.22,19.4 -13.43,49.15 -19.91,78.07 -7.46,33.24 4.06,91.59 4.06,91.59 l 0.29,-0.34 c 4.81,29.66 10.94,42.88 16.88,60.61 12.65,37.82 53.52,49.69 82.13,53.28 -24.12,-17.04 -39.54,-38.17 -49.29,-66.46 -1.2,-10.04 -2.14,-19.46 -2.84,-27.77 21.65,67.41 82.07,92.64 82.07,92.64 l 19.34,20.86 -0.25,-0.95 c 33.36,32.26 77.42,57.26 133.43,58.83 28.22,0.79 62.32,-6.64 62.23,-34.32 -0.04,-15.65 -12.28,-28.93 -28.97,-36.27 4.91,-0.97 9.4,-0.29 13.47,1.39 l 17.34,19.41 c 5.74,14.18 5.23,32.1 -4.44,42.9 25.52,21.82 65.26,-2.65 62.36,-31.6 7.47,6.3 12.03,18.2 6.89,27.64 34.34,20.18 53.56,-28.74 88.11,-17.31 -3.25,9.79 -19.89,7.81 -24.95,15.97 45.17,6.46 84.78,-9.42 130.08,-5.82 2.84,-2.47 5.91,-4.93 9.19,-7.36 -84.73,-9.38 -15.9,-9.33 -15.9,-9.33 10.85,0.99 36.92,2.81 47.06,1.01 16.58,-3 27.29,1.04 41.95,6.77 0.35,-0.64 1.82,-0.58 2.71,1.08 7.6,3 16.35,6.31 27.47,9.31 4.31,0.61 8.64,1.72 12.84,3.09 l 1.81,0.37 0.26,0.29 c 5.8,2.02 11.27,4.44 15.96,6.71 42.69,20.52 78.1,68.84 114.56,94.19 60.42,41.99 117.63,-9.88 159.69,-43.54 l -0.27,-0.39 c 10.55,-7.2 24.46,-16.08 39.61,-25.35 39.58,-17.23 91.79,-32.28 119.67,-59.84 22.31,-22.04 29.9,-50.42 39.49,-79.88 8.96,-27.47 26.34,-51.77 36.12,-82.6 1.88,1.58 2.99,3.96 3.63,6.8 -0.27,2.63 -0.7,5.41 0.08,7.13 l 0.53,-0.48 c -0.11,5.38 -1.3,11.69 -3.14,18.33 -8.29,16.88 -22.78,36.11 -21,51.15 0,0 51.42,-26.57 109.76,-52.96 20.09,-9.09 38.48,-24.08 54.53,-41.21 l 4.69,0.1 c -0.55,-1.2 -0.5,-2.93 -0.33,-4.76 28.36,-31.78 48.46,-69.63 55.45,-91.51 1.44,-4.49 3.07,-9.04 4.83,-13.57 l 0.01,-0.05 c 2.2,-5.71 4.57,-11.35 7.02,-16.78 l 0.05,0.08 c 1.03,-1.85 1.68,-3.66 2.37,-5.49 8.42,-18.22 16.69,-33.01 18.99,-37.06 7.41,-9.21 13.39,-21.04 19.78,-31.05 2.22,-24.89 3.41,-50.09 3.41,-75.56 0,-199.46 -69.36,-382.69 -185.2,-527 -6.7,-0.78 -15.83,-2.33 -27.9,-4.8 z m -52.92,-82.53 c -40.52,-13.23 -81.83,-38.11 -108.21,-40.61 -79.4,-7.5 -93.63,27.79 -30.19,33.61 23.94,2.2 59.29,4.91 87.52,18.29 41.64,19.78 84.29,38.98 112.76,53.23 -19.47,-22.6 -40.15,-44.11 -61.88,-64.52 z m -865.53,-3.85 c -6.73,-2.26 -6.73,1.07 -6.73,1.07 0,0 -12.2,17.42 -14.09,33.64 -1.91,16.07 2.23,30.38 6.26,32.5 4.07,2.2 4.95,-7.16 8.26,-18.88 3.33,-11.84 19.78,-36.13 19.78,-36.13 2.34,-5 -6.65,-9.95 -13.48,-12.2 z m 42.43,-7.43 c -7.73,-2.57 -7.72,1.26 -7.72,1.26 0,0 -13.94,19.78 -16.06,38.24 -2.14,18.26 2.66,34.52 7.3,36.95 4.67,2.51 5.67,-8.16 9.42,-21.52 3.76,-13.43 22.6,-41.09 22.6,-41.09 2.67,-5.68 -7.71,-11.25 -15.54,-13.84 z m 14.34,51.42 c -2.66,23.12 3.53,43.78 9.47,46.91 5.98,3.19 7.21,-10.35 11.96,-27.27 4.76,-17.04 28.77,-52.08 28.77,-52.08 3.4,-7.18 -9.92,-14.29 -19.94,-17.55 -9.92,-3.24 -9.89,1.54 -9.89,1.54 0,0 -17.72,25.08 -20.37,48.45 z m 344.3,264.59 c 4.16,3.72 8.54,-4.1 16.65,-12.97 8.18,-8.98 36.92,-23.11 36.92,-23.11 4.63,-3.42 -4.59,-11.97 -12.08,-17.13 -7.47,-5.16 -8.66,-2.13 -8.66,-2.13 0,0 -21.16,9.99 -29.17,23.65 -7.97,13.46 -7.84,27.91 -3.66,31.69 z m -68.15,-36.32 c 5.11,4.79 10.57,-5.35 20.77,-16.86 10.31,-11.78 46.52,-30.52 46.52,-30.52 5.9,-4.44 -5.63,-15.55 -14.96,-22.21 -9.36,-6.66 -10.92,-2.72 -10.92,-2.72 0,0 -26.46,13.4 -36.55,31.17 -9.99,17.53 -10,36.37 -4.86,41.14 z m -60.8,-81.74 c -9,18.83 -8.22,38.34 -3.02,43.06 5.25,4.73 10.2,-6.14 19.69,-18.82 9.63,-12.88 44.35,-34.41 44.35,-34.41 5.56,-5 -6.19,-15.86 -15.65,-22.26 -9.41,-6.35 -10.8,-2.21 -10.8,-2.21 0,0 -25.38,15.51 -34.57,34.64 z m -55.66,-46.52 c -7.53,19.87 -5.51,39.81 -0.21,44.23 5.4,4.43 9.44,-7.08 17.74,-20.66 8.43,-13.86 40.51,-38.43 40.51,-38.43 5.09,-5.51 -6.92,-15.77 -16.52,-21.57 -9.48,-5.72 -10.46,-1.32 -10.46,-1.32 0,0 -23.45,17.66 -31.06,37.75 z m -75.01,-121.98 c -9.98,-3.02 -9.89,1.61 -9.89,1.61 0,0 -16.92,24.38 -18.9,46.94 -1.96,22.39 4.85,42.34 10.86,45.31 6.07,3.02 6.94,-10.05 11.14,-26.43 4.3,-16.56 27.21,-50.59 27.21,-50.59 3.18,-6.96 -10.3,-13.73 -20.42,-16.84 z m 20.3,78.13 c -4.88,22.44 -0.13,43.46 5.88,47.35 6.06,3.95 8.61,-9.17 15.12,-25.14 6.57,-16.04 35.41,-47.57 35.41,-47.57 4.31,-6.67 -9.23,-15.5 -19.66,-20.14 -10.27,-4.55 -10.72,0.28 -10.72,0.28 0,0 -21.1,22.52 -26.03,45.22 z m 271.98,527.71 c 0,0 5.87,-0.99 3.22,-9.29 -2.64,-8.28 -3.15,-33.94 4.88,-45 8.07,-11.09 -5.53,-6.88 -16.15,4.32 -10.63,11.15 -18.15,31.7 -15.86,45.66 0,0 -0.61,5.87 23.91,4.31 z m -37.52,-67.96 c 12.88,-14.37 -6.84,-10.53 -23.34,3.63 -16.48,14.11 -29.99,41.66 -28.75,61.54 0,0 -1.69,8.15 32.94,9.54 0,0 8.42,-0.53 5.81,-12.53 -2.47,-11.98 0.45,-47.93 13.34,-62.18 z m -87.89,-74.93 c 75.07,-4.92 128.89,21.11 167.01,47.73 10.04,7 23.31,24.05 40.27,12.85 -7.23,-14.98 -26.39,-24.85 -42.26,-33.04 -27.81,-14.37 -52.47,-26.94 -84.52,-34.9 54.02,8.26 92.4,30.76 132.81,51.42 4.95,-10.38 10.51,-31.21 14.16,-48.84 l 0.52,0.05 c 0,0 3.67,-9.88 2.58,-19.53 0.15,-4.6 -0.78,-8.56 -4.07,-10.74 -1.11,-1.42 -2.44,-2.73 -4.11,-3.82 -14.75,-9.67 -58.52,-31.04 -93.63,-33.58 -1.16,-0.07 -2.27,-0.22 -3.42,-0.33 l -2.59,-0.73 -0.07,0.48 c -31.84,-3.69 -52.44,-16.81 -11.72,-10.12 40.74,6.72 128,21.57 96.21,9.62 l 0.11,0.02 c -39.69,-15.51 -91.77,-30.69 -142.89,-25.71 -33.03,3.2 -67.2,19.4 -96.58,34.89 -29.34,15.45 -57.18,35.77 -88.54,42.22 -23.87,4.94 -43.59,-1.94 -64.39,-5.5 -13.85,-2.34 -33.15,-7.95 -41.54,0.7 -3.54,4.19 -0.72,8.49 -0.72,8.49 7.94,19.62 31.07,31.19 50.3,36.72 60.36,17.37 118.83,-14.55 177.08,-18.35 z m 17.01,65.76 c 12.62,-18.31 -9.29,-10.98 -26.04,7.72 -16.76,18.69 -28.07,52.35 -23.77,75.03 0,0 -0.73,9.53 38.96,5.89 0,0 9.52,-1.89 4.9,-15.19 -4.73,-13.42 -6.64,-55.1 5.95,-73.45 z m -79.92,8.72 c 12.44,-20.82 -10.82,-11.69 -27.75,9.78 -16.94,21.37 -27.09,59.1 -20.93,83.8 0,0 -0.14,10.62 42.73,4.68 0,0 10.14,-2.56 4.23,-17.09 -5.93,-14.48 -10.72,-60.33 1.72,-81.17 z m -82.62,11.5 c 12.72,-21.08 -10.85,-12.08 -28.06,9.58 -17.23,21.59 -27.69,59.9 -21.58,85.21 0,0 -0.23,10.74 43.13,5.29 0,0 10.28,-2.5 4.37,-17.35 -5.89,-14.84 -10.51,-61.7 2.14,-82.73 z m -75.72,-23.8 c 15.61,-27.27 -11.73,-15.72 -32.57,12.24 -20.82,27.97 -34.79,77.68 -29.28,110.62 0,0 -0.8,14.07 48.83,7.3 0,0 11.92,-3.09 6.02,-22.58 -5.92,-19.36 -8.62,-80.28 7,-107.58 z m -80.38,20.29 c 15.56,-23.8 -11.82,-14.71 -32.58,9.48 -20.74,24.17 -34.4,68.31 -28.65,98.18 0,0 -0.78,12.63 49.05,8.82 0,0 11.91,-2.29 5.83,-19.98 -6.03,-17.69 -9.15,-72.64 6.35,-96.5 z m -85.14,27.74 c 10.98,-20.46 -10.36,-11.36 -25.48,9.78 -15.12,21.03 -23.44,58.05 -17.05,82.25 0,0 0.14,10.39 39.73,4.3 0,0 9.4,-2.58 3.46,-16.71 -5.88,-14.2 -11.63,-59.14 -0.66,-79.62 z m -64.93,17.69 c 10.31,-16.32 -8.4,-9.23 -22.34,7.51 -13.92,16.76 -22.72,46.32 -18.28,65.79 0,0 -0.36,8.33 33.87,3.93 0,0 8.22,-1.94 3.71,-13.4 -4.32,-11.4 -7.32,-47.51 3.04,-63.83 z m -68.19,-11.78 c 12.6,-18.31 -9.3,-10.98 -26.05,7.74 -16.75,18.69 -28.06,52.34 -23.76,75.03 0,0 -0.74,9.51 38.95,5.89 0,0 9.52,-1.89 4.9,-15.21 -4.74,-13.41 -6.63,-55.07 5.96,-73.45 z m -55.02,4.85 c 12.88,-14.35 -6.83,-10.55 -23.32,3.6 -16.5,14.13 -30.01,41.69 -28.77,61.56 0,0 -1.68,8.15 32.94,9.54 0,0 8.42,-0.53 5.83,-12.55 -2.48,-11.98 0.43,-47.93 13.32,-62.15 z m 755.27,-755.37 c -38.14,-13.18 -105.91,-46.26 -160.35,-73.94 -13.01,-0.6 -26.11,-0.94 -39.29,-0.94 -465.3,0 -842.48,377.19 -842.48,842.49 0,360.48 226.45,668 544.82,788.29 1.61,-1.49 3.31,-2.93 5.11,-4.33 3.61,-2.81 9.58,-4.3 12.67,-8 4.11,-4.94 2.4,-14.97 4.19,-21.16 5.55,-19.11 17.35,-36.65 37,-50.99 2.87,-2.12 8.35,-3.14 10.85,-5.95 5.47,-6.21 3.88,-16.65 8.01,-23.83 4.35,-7.55 11.76,-16.67 20.9,-23.69 5.01,-3.86 12.5,-5.92 17.18,-10.52 3.79,-3.71 4.84,-10.39 7.55,-15.95 7.34,-15.01 26.73,-32.41 36.04,-48.12 1.23,-2.07 2.19,-4.27 3,-6.51 3.88,-7.99 13.26,-24.92 26.05,-32.75 0,0 1.33,-23.51 24.78,-50.31 -47.5,2.56 -93.32,29.42 -128.56,2.74 -10.17,11.1 -42.79,19.8 -56.75,4.23 -10.31,17.92 -64.99,29.36 -75.62,1.04 -77.73,34.87 -171.54,-14.85 -201.69,-64.76 -5.6,-2.67 -10.83,-5.48 -15.77,-8.37 -21.28,6.4 -50.1,8.67 -81.29,-13.82 -30.74,-22.18 -62.88,-121.66 -57.35,-190.53 0.6,-7.38 14.59,-24.8 19.62,-59.7 5,-34.62 8.81,-45.99 8.81,-45.99 -6.84,-11.93 -15,-17.26 -16.11,-31.22 -2.41,-30.21 23.42,-46.63 47.62,-62.1 8.61,-4.01 18.36,-6.89 28.94,-7.27 6.39,-10.12 31.01,-44.33 71.72,-44.33 1,0 2.03,0.07 3.03,0.13 15.54,-13.07 31.75,-16.58 20.56,-0.47 -0.92,1.33 -1.71,2.82 -2.45,4.35 7.48,-4.43 16.54,-8.77 24.61,-9.56 0.16,-0.01 3.96,-0.97 7.13,-0.97 1.12,0 4.46,0 5.64,2.57 1.17,2.58 -1.21,5.35 -1.99,6.23 -3.26,3.76 -6.93,13.54 -9.69,22.65 2.98,-5.46 6.23,-10.66 9.87,-15.13 19.37,-23.78 46.47,-35.02 31.34,-11.36 -4.86,7.58 -7.63,17.91 -8.98,28.88 7.5,-9.25 20.42,-19.99 41.43,-24.29 17.36,-16.51 38.94,-23.26 26.01,-5.71 -3.3,4.49 -5.46,10.27 -6.75,16.59 10.47,-12.55 28.17,-28.68 49.88,-28.68 l 1.58,0.04 0.44,0.02 c 14.89,-10.07 27.36,-11.75 16.22,2.77 -4.83,6.32 -7.46,15.08 -8.64,24.34 9.84,-20.08 28.82,-47.69 61.49,-56.57 0.24,-0.09 5.87,-1.65 10.52,-1.65 3.63,0 5.91,0.93 7,2.92 1.58,2.85 -0.5,6.17 -1.18,7.26 -2.11,3.38 -4.07,7.59 -5.77,11.74 14.67,-8.6 25.51,-9.33 14.1,4.68 -5.9,7.22 -9.05,17.42 -10.34,27.95 7.97,-21.31 24.22,-51.23 56.3,-70.83 0.24,-0.11 6.01,-2.84 12.42,-2.84 3.09,0 5.84,0.65 8.23,1.85 2.04,1.05 3.38,2.77 3.93,4.98 1.67,6.68 -4.67,16.16 -5.24,16.93 -2.64,5.2 -7.48,16.18 -9.86,25.78 l 0.24,-0.19 c 23.19,-18.71 53.29,-27.37 34.72,-8.72 -11.27,11.35 -15.62,30.79 -16,46.67 6.77,-19.01 23.24,-51.94 57.35,-58.45 0.23,-0.02 5.52,-1.04 9.42,-1.04 2.17,0 4.78,0.25 5.69,2.33 0.4,0.88 0.56,2.3 -0.99,4.04 -2.55,2.86 -6.18,11.52 -8.1,18.52 1.62,-1.24 3.19,-2.55 4.89,-3.63 16.54,-10.85 36.06,-16.54 38.61,-13.02 5.29,-4.34 13.57,-10.03 24.82,-14.99 1.05,-2.39 2.09,-4.82 2.93,-7.24 0,0 5.25,-14.59 7.27,-22.48 -26.76,6.93 -72.56,20.35 -106.65,12.83 -26.92,-5.92 -97.1,-44.72 -80.12,-71.99 1.13,-1.82 2.58,-3.09 4.24,-4.11 l 1.05,-0.4 c 6.7,-3.57 18.52,-5.67 30.95,-5.57 l 4.52,0.13 c 7.22,0.39 26.15,3.12 32.56,5.2 18.77,6.1 35.53,2.43 35.53,2.43 l -0.24,-0.17 c 13.34,-1.55 27.41,-6.24 41.94,-13.66 15.61,-7.94 36.85,-21.06 42.26,-27.53 9.76,-11.73 -5.19,-39.21 -10.76,-56.13 -0.27,-1 -0.61,-2.04 -0.93,-3.08 l -0.4,-1.4 -0.05,0.03 c -0.79,-2.37 -1.76,-4.86 -2.8,-7.4 -0.95,1.19 -1.79,2.34 -2.43,3.42 -5.34,8.98 -8.21,16.84 -10.97,13.23 -2.76,-3.62 -2.89,-17.96 2.36,-31.49 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.05,-11.06 -13.38,-22.64 -21.11,-33.75 -6.02,5.7 -12.11,12.11 -15.05,17.23 -6.87,11.76 -10.53,22.09 -14.04,17.35 -3.54,-4.72 -3.64,-23.77 3.09,-41.67 2.2,-5.83 5.55,-11.11 9.07,-15.73 -5.34,-6.74 -10.55,-12.95 -15.3,-18.23 -2.13,-2.34 -4.65,-4.99 -7.32,-7.74 -7.34,7.56 -16.63,17.94 -20.38,25.45 -6.54,13.12 -9.91,24.3 -13.63,19.54 -3.71,-4.8 -4.43,-24.95 1.75,-44.43 2.55,-7.98 6.93,-15.27 11.27,-21.19 -7.96,-7.58 -16.6,-15.59 -25.47,-23.67 -5.38,7.14 -10.69,14.98 -13.12,20.98 -5.83,14.19 -8.6,26.23 -12.54,21.61 -3.88,-4.63 -5.58,-25.57 -0.35,-46.44 1.29,-5.15 3.26,-10.09 5.5,-14.67 -8.79,-7.86 -17.3,-15.38 -25.11,-22.19 -2.29,4.97 -4.2,9.69 -5.26,13.58 -4.58,16.9 -6.3,30.85 -10.81,26.57 -4.51,-4.18 -8.35,-26.68 -5.05,-50.59 0.31,-2.3 0.76,-4.57 1.27,-6.85 l -2.2,-1.89 c -5.11,-4.41 -10.66,-9.72 -16.39,-15.56 -1.43,4.49 -2.54,8.7 -3.12,12.19 -2.91,17.61 -3.35,31.7 -7.98,28.33 -4.6,-3.31 -10.11,-25.03 -9,-49.33 0.17,-3.82 0.63,-7.68 1.27,-11.45 -6.74,-7.6 -13.41,-15.44 -19.69,-23.09 -3.64,9.35 -6.93,19.01 -8.2,26 -3.33,18.42 -4.03,33.23 -8.74,29.6 -4.31,-3.29 -9.05,-23.01 -8.53,-45.96 -4.7,-3.44 -10.79,-19.44 -10.99,-37.57 -0.09,-6.17 1.01,-12.49 2.51,-18.2 -3.05,-4.3 -8.38,-7.28 -12.11,-12.52 -19.24,-26.91 -11.39,-58.98 30.18,-66.11 12.74,-39.25 45.04,-58.31 94.58,-58.76 6.65,-0.06 13.6,2.26 20.12,1.85 7.36,-0.49 13.42,-3.48 20.13,-3.69 36.11,-1.1 55.04,10.39 82.49,18.39 20.47,5.94 41.6,7.84 54.34,12.84 19.51,7.65 28.78,28.62 44.26,38.56 5.77,3.7 16.64,5.44 26.17,11.01 8.04,4.73 15,13.32 22.13,16.53 6.23,2.82 16.6,2.26 24.14,5.51 12.64,5.48 26.6,17.31 42.27,25.73 32.81,17.55 59.51,30.53 94.57,45.89 16.75,7.34 34.47,24.6 44.27,25.71 11.62,1.34 25.15,-8.36 34.21,-7.34 18.46,-21.95 24.89,-52.62 24.12,-92.06 1.09,-0.11 0.29,-9.78 0.29,-9.78 0,0 6.45,-84.66 -125.77,-130.38 z M 2319.1,3773.92 c 13.83,-3.85 29.29,-11.71 14.56,-35.21 -9.06,9.68 -12.13,22.44 -14.56,35.21 z m 26.38,-30.96 c 4.42,7.74 0.02,11.68 2.36,16.37 39.74,-5.12 43.17,-33.03 26,-72.62 -26.49,8.95 -33.54,26.66 -38.58,44.64 4.25,4.61 7.55,6.9 10.22,11.61 z m 43.39,-7.87 c 36.99,-16.3 42.8,-57.19 17.22,-110.53 -8.74,5.74 -15.55,12.62 -20.46,20.22 -3.89,6.03 -9.35,15.9 -8.18,24.01 0.82,5.58 5.24,13.07 7.5,19.31 6.47,17.93 8.99,34.11 3.92,46.99 z m 177.23,-155.25 c -0.64,1.95 0.67,1.89 2.28,3.33 55.29,-11.22 59.69,-65.17 35.95,-105.83 -11.26,-19.25 -22.27,-29.38 -39.55,-24.01 -14.3,4.46 -16.25,15.95 -23.14,23.85 28.17,41.04 27.62,71.27 24.46,102.66 z m -63.91,40.61 c -0.24,5.01 -1.15,10.58 0.87,15.52 4.77,-0.4 13.12,-1.61 19.95,-5.23 31.05,-16.4 43.9,-75.07 25.85,-109.56 -7.75,-14.78 -15.59,-21.96 -30.09,-17.81 -23.4,6.72 -30.19,33.21 -39.62,44.17 25.51,27.2 24.04,51.08 23.04,72.91 z m -74.76,73.65 1.52,0.74 c 60.84,-21.44 95.74,-61.97 40.45,-136.4 -21.08,10.57 -32.94,24.68 -38.43,40.68 -3.23,9.38 -5.72,10.51 -3.53,22.15 4.69,25.14 6.27,52.87 -0.01,72.83 z m 236.11,-312.56 c -2.27,-1.01 -3.87,-1.76 -3.87,-1.76 -7.39,-3.78 -15.16,-6.03 -22.54,-7.31 -45.74,9.82 -59.56,61.95 -59.56,61.95 42.74,18.79 66.89,72.89 51.68,102.65 0.43,1.11 1.42,0.93 2.42,0.7 19.37,-8.54 39.75,-22.88 49.66,-38.41 18.83,-29.45 24.41,-73.75 8.73,-109.34 -6.98,-1.61 -11.46,-3.21 -17.08,-5.19 -0.95,-0.25 -1.94,-0.54 -2.92,-0.88 l -5.22,-1.92 -0.53,-0.21 -0.82,-0.27 0.05,-0.01 z m 73.78,36.96 c -3.13,-2.66 -6.21,-5.27 -9.06,-7.69 -2.62,-5.02 -10.66,-11.66 -20.93,-16.01 8.15,24.72 9.13,50.99 9.7,70.45 16.84,-8.75 28.08,-20.77 34.57,-34.43 -2.08,-1.8 -4.21,-3.66 -6.4,-5.55 -2.88,5.37 -6.87,10.23 -12.09,14.35 2.36,-6.86 3.71,-13.9 4.21,-21.12 z m -92.4,328 c 412.7,0 756.05,-296.74 828.41,-688.48 -7.89,5.56 -16.59,10.5 -26.45,14.61 -20.63,92.05 -65.01,150.17 -156.18,183.4 -30.56,11.13 -59.51,24.02 -89.66,37.15 1.74,97.97 -112.11,95.91 -183.06,146.34 -30.86,21.99 -65.84,62.56 -101.14,70.06 -68.27,14.52 -110.27,-33.06 -150.59,-66.3 -9.89,10.8 -24.72,21.35 -46.23,30.94 0,0 -38.48,54.88 -56.43,65.21 -1.19,0.68 -1.98,1.3 -2.5,1.92 -9.92,4.65 -22.34,7.27 -31.12,13.07 -8.67,5.7 -10.31,19.19 -18.99,25.7 -4.25,3.19 -10.84,6.65 -16.6,8.96 -6.96,2.79 -18.88,2.27 -25.88,6.1 -8.63,4.73 -9.32,20.11 -15.57,27.74 -6.89,8.43 -15.75,15.32 -30.08,20.14 -5.81,1.93 -14.59,2.06 -19.84,4.87 -5.86,3.17 -7.29,13.09 -11.83,19.17 -10.55,14.18 -28.36,25.18 -48.68,32.36 -4.37,1.54 -10.25,1.54 -13.45,3.69 -3.77,2.51 -4.21,8.78 -6.49,13.58 70.85,19.35 145.38,29.77 222.36,29.77 z m 836.59,-742.56 c -8.56,14.67 -16.48,28.78 -19.38,41.21 5.81,-3.84 10.91,-8.12 15.58,-12.68 1.44,-9.45 2.67,-18.97 3.8,-28.53 z m -836.59,785.09 c -91.12,0 -179,-13.85 -261.73,-39.43 -0.93,1.64 -1.92,3.24 -3.23,4.52 -7.64,7.44 -16.71,13.1 -35.56,8.27 -6.68,8.65 -15.49,15.6 -29.86,18.55 l -0.45,-0.77 c 1.82,-17.15 4.28,-34.48 17.33,-46.35 l -0.19,-2.08 C 1997.3,3605.11 1759.91,3282.33 1759.91,2904 c 0,-488.79 396.23,-885.02 885.01,-885.02 488.78,0 885.04,396.23 885.04,885.02 0,488.81 -396.26,885.03 -885.04,885.03 z M 2195.1,3323.54 c 0,0 -34.81,-7.93 -44.29,-69.48 0,0 -1.65,-31.07 8.08,-24.19 -8.2,37.31 27.27,54.21 35.41,58.01 11.45,5.09 20.91,3.38 21.63,-6.34 0.78,-10.49 -11.21,-15.13 -14.8,-25.94 12.73,7.18 41.2,24 38.24,45.9 -2.18,16.1 -17.34,30.4 -44.27,22.04 z m 457.68,-37.78 c -59.82,35.02 -214.44,28.94 -250.75,31.75 -35.74,2.72 -53.6,-42.72 -53.6,-42.72 -0.47,-9.62 7.4,1.41 7.4,1.41 23.35,42.08 43.88,34.38 43.88,34.38 73.99,-21.61 87.17,-130.29 90.25,-155.48 3.06,-25 9.38,-8.72 9.38,-8.72 7.19,62.54 -38.41,138.76 -48,148.55 -9.58,9.73 -0.43,15.23 30.13,6.68 92.03,-25.84 100.65,-173.22 106.2,-191.09 5.54,-17.8 9,-0.68 9,-0.68 -12.45,135.51 -63.96,168.92 -77.69,187.56 -5.7,7.73 40.82,8.9 61.31,-4.43 115.64,-74.71 102.66,-217.79 113.07,-197.37 10.55,20.85 -29.1,150.34 -84.81,194.41 -11.15,8.79 38.66,-6.58 57.02,-23.49 87,-80.41 97.7,-167.53 104.39,-192.7 6.57,-25 9.78,-16.53 9.78,-16.53 1.21,85.15 -66.26,193.01 -126.96,228.47 z m 167.67,59.29 c 12.83,6.96 27.96,52.1 59.04,33.35 23.1,-13.93 34.1,-17.46 34.1,-17.46 0,0 -16.13,-4.53 -23.47,-16.63 -7.34,-12.1 -16.14,-21.41 -41.81,-17.62 -26.95,4.02 -31.88,-0.21 -45.46,-2.42 0,0 4.76,13.79 17.6,20.78 z m -49.59,-36.2 c 19.79,-4.3 38.04,-11.99 56.34,-23.86 20.27,-13.17 42.21,-37.36 72.44,-34.91 9.64,0.77 27.16,10.1 34.21,14.7 8.82,5.75 29.74,19.45 24.15,40.39 -2.48,9.3 -13.54,10.78 -20.13,18.37 -9.13,10.56 -8.78,20.93 -16.09,33.05 15.93,-3.2 25.06,-12.64 42.24,-14.7 -27.07,24.28 -58.26,44.78 -96.58,58.78 2.88,1.63 4.71,8.31 14.09,11.01 8.45,2.44 35.7,-1.72 18.11,1.85 -17.66,4.94 -28.62,-0.09 -40.23,-7.36 -26.68,-16.67 -48.41,-54.95 -76.48,-71.6 -12.18,-7.27 -24.09,-5.6 -34.22,-18.39 6.56,-13.1 13.21,-5.39 22.15,-7.33 z m 209.28,23.88 c -6.66,-3.87 4.19,-7.38 6.03,-9.19 7.67,-7.55 24.8,-21.4 30.18,-33.05 11,-23.83 7.62,-60.3 -12.08,-73.48 -13.27,-8.86 -78.22,-33.08 -106.63,-33.05 -79.93,0.11 -88.04,87.86 -136.84,117.54 0.87,-8.4 7,-25.99 13.98,-35.11 27.44,-35.83 53.66,-109.66 130.81,-97.33 27.26,4.36 78.26,23.19 98.72,35.98 22.22,13.85 38.72,67.03 16.08,96.46 -10.14,13.18 -34.41,29.88 -40.25,31.23" + style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none" + id="path76" /> + </g> + </g> + <path + inkscape:connector-curvature="0" + d="m 376.40655,56.024215 0,23.8525 24.42625,0 0,-23.8525 -24.42625,0 z m 0.09,131.692505 24.24875,0 0,-96.436255 -24.24875,0 0,96.436255 z m 305.7425,-96.436255 -35.3525,96.436255 -18.88,0 -35.5375,-96.436255 25.3575,0 19.61875,59.602505 19.43625,-59.602505 25.3575,0 z m -97.74375,96.436255 -23.5075,0 0,-8.885 c -6.29375,6.66375 -14.31625,9.995 -24.06125,9.995 -9.505,0 -17.09375,-2.83625 -22.76875,-8.51375 -6.54125,-6.53875 -9.80875,-15.67 -9.80875,-27.39375 l 0,-61.638755 24.2475,0 0,58.306255 c 0,6.04875 1.70625,10.61625 5.12125,13.6975 2.80625,2.5925 6.34375,3.8875 10.61125,3.8875 4.39,0 7.99,-1.295 10.79625,-3.8875 3.4125,-3.08125 5.12125,-7.64875 5.12125,-13.6975 l 0,-58.306255 24.24875,0 0,96.436255 z m -114.8675,-48.31 c 0,-8.51375 -0.67125,-14.6225 -2.0125,-18.32375 -2.44125,-6.17 -7.1375,-9.255 -14.09,-9.255 -6.95625,0 -11.6525,3.085 -14.09125,9.255 -1.34125,3.70125 -2.0125,9.81 -2.0125,18.32375 0,8.515 0.67125,14.62375 2.0125,18.32375 2.43875,6.295 7.135,9.44125 14.09125,9.44125 6.9525,0 11.64875,-3.14625 14.09,-9.44125 1.34125,-3.7 2.0125,-9.80875 2.0125,-18.32375 z m 24.24875,0 c 0,9.8725 -0.43375,17.2775 -1.29625,22.2125 -1.35875,8.02125 -4.1975,14.19125 -8.51375,18.5075 -5.80375,5.805 -13.63625,8.7 -23.50875,8.7 -9.8725,0 -17.8925,-3.3925 -24.06125,-10.18 l 0,9.07 -23.3225,0 0,-131.788755 24.2475,0 0,43.86875 c 5.77875,-6.415 13.53,-9.625 23.24625,-9.625 9.83875,0 17.64875,2.9 23.42875,8.7 4.305,4.318755 7.1325,10.488755 8.48625,18.508755 0.8625,4.93625 1.29375,12.28 1.29375,22.02625 z m -130.04375,48.31 -13.69625,0 c -9.255,0 -16.4125,-2.8975 -21.47125,-8.69875 -4.4425,-5.05875 -6.6625,-11.35125 -6.6625,-18.88 l 0,-104.210005 24.2475,0 0,102.730005 c 0,5.80125 2.8075,8.69875 8.42375,8.69875 l 9.15875,0 0,20.36" + style="fill:#403c3d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path74" /> + <g + transform="matrix(0.23169071,0,0,-0.23371708,-280.79355,1099.9435)" + id="g66-4"> + <g + id="g68-1" + clip-path="url(#clipPath70-6)"> + <g + id="g3197" + transform="translate(-350.10267,-350.10267)"> + <path + id="path76-6" + style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none" + d="m 3504.81,2908.41 c 0,-483.58 -391.32,-875.6 -874.02,-875.6 -482.71,0 -874,392.02 -874,875.6 0,483.61 391.29,875.63 874,875.63 482.7,0 874.02,-392.02 874.02,-875.63" + inkscape:connector-curvature="0" /> + <path + id="path78" + style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none" + d="m 3482.08,2908.41 c 0,-471 -381.13,-852.83 -851.29,-852.83 -470.16,0 -851.27,381.83 -851.27,852.83 0,471.02 381.11,852.85 851.27,852.85 470.16,0 851.29,-381.83 851.29,-852.85" + inkscape:connector-curvature="0" /> + <path + id="path80" + style="fill:#adda1a;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 3473.33,3029.95 c -6.42,7.53 -13.81,14.41 -22.76,20.33 3.77,-16.2 15.99,-35.21 27.12,-54.62 -1.18,11.52 -2.73,22.91 -4.36,34.29 z M 3070.25,2284 c -63.63,-5.85 -49.36,-41.32 30.29,-33.77 29.21,2.77 76.64,33.01 121.13,44.56 22.41,21.66 43.74,44.44 63.68,68.43 -27,-14.62 -77.9,-37.33 -127.3,-60.84 -28.31,-13.46 -63.77,-16.17 -87.8,-18.38 z m 409,691.11 c -9.21,11.12 -16.63,28.08 -26.56,40.46 -2.32,4.07 -10.61,18.92 -19.05,37.24 -0.7,1.84 -1.35,3.66 -2.39,5.51 l -0.05,-0.07 c -2.45,5.45 -4.83,11.12 -7.04,16.85 l -0.01,0.06 c -1.76,4.55 -3.39,9.12 -4.84,13.64 -7.01,21.99 -27.18,60.03 -55.62,91.97 -0.17,1.83 -0.23,3.57 0.33,4.78 l -4.7,-0.11 c -16.1,17.22 -34.56,32.28 -54.71,41.42 -58.53,26.53 -110.11,53.23 -110.11,53.23 -1.79,-15.12 12.75,-34.44 21.07,-51.41 1.85,-6.68 3.04,-13.01 3.15,-18.42 l -0.53,0.48 c -0.79,-1.72 -0.36,-4.51 -0.09,-7.16 -0.63,-2.86 -1.75,-5.25 -3.64,-6.83 -9.8,30.98 -27.24,55.39 -36.22,83.01 -9.63,29.6 -17.24,58.12 -39.62,80.27 -27.97,27.69 -80.34,42.83 -120.05,60.13 -15.2,9.33 -29.15,18.25 -39.73,25.48 l 0.27,0.4 c -42.2,33.83 -99.59,85.95 -160.2,43.76 -36.58,-25.48 -72.09,-74.05 -114.92,-94.66 -4.7,-2.29 -10.18,-4.72 -16.01,-6.75 l -0.25,-0.29 -1.82,-0.38 c -4.22,-1.37 -8.56,-2.48 -12.88,-3.09 -11.15,-3.02 -19.94,-6.36 -27.56,-9.36 -0.89,-1.67 -2.36,-1.72 -2.72,-1.08 -14.7,-5.76 -25.44,-9.82 -42.09,-6.82 -10.16,1.82 -36.31,-0.01 -47.19,-1.01 0,0 -69.05,-0.05 15.93,9.37 -3.27,2.46 -6.36,4.92 -9.21,7.4 -45.43,-3.61 -85.18,12.35 -130.49,5.85 5.09,-8.21 21.77,-6.21 25.04,-16.05 -34.67,-11.48 -53.95,37.68 -88.39,17.4 5.15,-9.48 0.58,-21.45 -6.91,-27.78 2.9,29.09 -36.96,53.69 -62.56,31.76 9.7,-10.86 10.2,-28.86 4.46,-43.12 l -17.4,-19.5 c -4.08,-1.69 -8.59,-2.37 -13.51,-1.4 16.74,7.37 29.01,20.73 29.06,36.46 0.09,27.81 -34.12,35.28 -62.43,34.49 -56.18,-1.59 -100.39,-26.71 -133.84,-59.13 l 0.24,0.95 -19.4,-20.96 c 0,0 -60.6,-25.35 -82.33,-93.09 0.7,8.35 1.64,17.81 2.85,27.9 9.79,28.43 25.25,49.66 49.44,66.79 -28.7,-3.61 -69.69,-15.54 -82.38,-53.55 -5.96,-17.81 -12.11,-31.1 -16.94,-60.9 l -0.29,0.34 c 0,0 -11.55,-58.65 -4.07,-92.05 6.5,-29.06 15.74,-58.97 19.98,-78.46 0.31,-2.57 0.8,-5.25 1.55,-8.02 53.53,25.5 127.71,32.14 197.84,42.47 -29.28,-4.79 -70.93,-16.14 -111.03,-25.84 -40.01,-9.7 -98.01,-24.8 -98.91,-60.92 -0.53,-21.23 15.39,-39.9 42.38,-40.6 -2.4,5.18 -2.21,12.74 -2.01,20.32 -5.57,-0.46 -4.61,-6.86 -8.07,-9.23 -2.07,41.18 68.63,45.39 115.05,53.52 6.31,1.1 12.28,2.63 18.18,3.7 21.63,3.79 53.78,1.97 88.43,1.46 47.63,-0.67 81.2,5.28 125.04,-11.15 14.08,-5.29 43.74,-7.09 58.03,-8.62 50.68,-5.38 88.38,3.26 150.38,-2.01 24.7,-2.09 49.47,-11.64 72.68,-22.15 32.18,-14.54 57.5,-32.58 96.88,-22.16 14.24,-0.73 28.56,1.95 33.28,-0.73 22.77,-2.03 19.21,-19.81 45.45,-17.71 30.54,2.43 54.62,21.61 90.84,24.01 28.24,1.84 57.99,-5.19 90.84,-1.86 22.77,2.31 45.33,12.35 64.59,20.29 48.59,20.07 128.49,59.45 135.25,112.57 5.48,43.01 -26.95,65.35 -72.67,53.55 46.44,24.15 89.27,-11.93 88.81,-57.23 -0.13,-13.82 -9.81,-26.35 -16.14,-42.45 -6.37,-16.16 -6.51,-27.48 -14.14,-36.9 -3.81,-4.74 -8.73,-8.7 -13.9,-11.99 -8.91,-4.41 -21.76,-8.11 -39.39,-12.95 -26.03,-7.17 -50.53,-14.82 -50.53,-14.82 -4,-0.78 -5.56,-1.56 -5.83,-2.26 -16.03,-4.39 -35.35,-10.88 -46.46,-18.98 -21.4,-15.61 -55.77,-27.94 -88.83,-22.1 -3.06,0.55 -5.56,0.66 -7.59,0.44 -10.86,1.42 -21.56,2.92 -32.09,3.3 0,0 -60.14,-1.51 -56.74,-3.53 3.41,-2.07 4.26,-2.02 4.26,-2.02 22.01,-17.39 32.52,-46.38 44.41,-73.8 13.37,-30.85 23.4,-62.63 26.25,-103.36 8.55,33.04 20.19,63.26 35.25,90.38 19.61,32.19 58.62,82.91 118.6,102.69 21.12,6.63 38.61,16.58 52.03,30.26 -18.49,-27.47 -50.41,-39.13 -76.7,-57.24 -54.55,-37.54 -83.75,-92.88 -109,-162.4 -5.76,-15.84 -11.5,-31.64 -20.18,-46.15 -8.38,-13.93 -21.17,-26.48 -26.25,-40.58 -3.28,-9.09 -1.97,-19.3 -4.03,-27.7 -5.7,-23.21 -15.54,-46.26 -29.19,-64.5 -11.59,-13.02 -35.57,-39.82 -40.13,-43.98 l -0.22,-0.36 c -31.85,-30.92 -69.62,-56.39 -110.13,-79.41 l 0.39,-0.82 -2.18,-1.47 -0.22,0.45 c -5.62,-3.61 -10.68,-7.72 -15.38,-12.15 -4.84,-4.03 -8.91,-8.05 -10.85,-11.33 -16.68,-19.34 -29.5,-42.11 -48.46,-59.56 -10.87,-10.02 -23.71,-18.07 -36.43,-26.37 l 0.09,0.31 c 0,0 -15.25,-10.33 -28.3,-18.19 -40.26,-19.09 -81.84,-52.85 -143.27,-53.58 -32.98,-0.36 -78.22,2.15 -92.87,27.71 0,0 -8.68,4.13 -8.07,-14.77 0.78,-24.11 41.07,-24.82 61.99,-34.85 10.59,-6.14 -10.26,-1.04 -17.57,-2.08 16.08,-17.27 25.62,-40.53 60.55,-40.57 0,0 -8.15,7.62 -10.95,9.16 -2.81,1.52 1.78,3.83 14.29,-0.78 10.26,-3.78 23.65,-7.19 41.17,-7.09 1.13,0 2.23,-0.02 3.41,0 2.76,0.08 5.63,0.26 8.61,0.54 0,0 31.03,0.17 60.97,13.12 29.96,12.96 63.98,9.55 79.64,21.14 15.66,11.58 27.23,34.07 37.43,37.5 10.22,3.42 24.55,11.33 36.24,24.55 9.96,11.24 25.12,4.89 37.52,16.37 11.29,10.44 86.52,47.81 86.52,47.81 22.36,15.41 36.07,33.48 61.35,46.2 36.66,25.62 -50.85,-18.01 -76.31,-27.89 -31.65,-12.26 -3.07,4.31 -3.07,4.31 l 51.26,29.33 c 15.44,7.57 30.91,15.07 46.7,22.26 10.21,4.35 27.69,11.65 41.34,16.53 26.89,6.81 50.65,4.82 73.31,8.99 24.06,4.41 45.17,16.05 68.63,20.3 3.73,0.66 10.05,-1.26 14.14,0 25.47,7.85 50.95,32.67 74.69,46.13 54.76,31.04 95.31,60.15 111.03,127.36 3.69,15.78 5.91,31.75 10.09,47.96 8.91,34.68 15.52,66.46 12.1,112.58 -2.02,27.41 -17.84,55.88 -16.14,90.44 1.6,32.49 24.4,57.21 34.31,86.74 11.84,35.26 -9.8,59.99 -42,73.32 l 0.02,0.03 c 0,0 -23.83,11.25 -33.01,11.93 -9.19,0.69 4.77,3.06 10.89,3.06 4.7,0 8.77,3.24 11.96,8.26 3.64,5.15 5.68,12.38 9.75,17.83 5.72,7.65 19.89,18.14 20.19,25.82 0.39,10.04 -16.8,23.84 -26.25,29.55 -16.3,9.86 -42.61,15.88 -64.59,25.84 -24.47,11.05 -42.11,23.26 -54.5,35.05 -6.87,17.68 -19.82,28.7 -18.17,49.84 0.41,5.36 2.38,10.54 4.14,15.93 l 0.74,1.99 c 2.04,6.89 4.85,17.63 0,29.9 -4.84,12.28 -22.46,15.85 -22.46,15.85 l -0.07,-0.01 c -9.55,3.18 -20.88,5.11 -28.78,8.33 -12.47,5.03 -22.27,11.8 -32.01,16.88 12.11,-3.84 26.84,-10.03 49.63,-12.08 10.06,-0.89 38.28,-5.95 43.6,-23.9 l 0.56,-2.02 0.47,-1.79 c 0.23,-1.02 0.4,-2.05 0.56,-3.09 0.18,-1.35 0.38,-2.66 0.41,-4.12 l 0.09,-2.09 c 0.1,-7.16 -1.4,-14.68 -4.77,-22.16 -12.95,-28.75 1.23,-50.51 22.34,-61.76 19.97,-15.69 49.52,-24.31 78.59,-35.23 23.22,-8.71 49.09,-21.54 62.26,-36.33 6.84,-11.84 10.51,-24.87 6.01,-37.26 -7.2,-13.97 -24.49,-20.05 -29.91,-37.14 6.8,-8.64 19.17,-10.55 28.26,-16.59 14.11,-9.41 24.5,-22.04 27.69,-40.18 l 0.18,-1.91 c 0.34,-2.16 0.53,-4.32 0.63,-6.51 0.03,-1.96 -0.05,-3.92 -0.08,-5.88 -1.68,-32.34 -26.5,-65.77 -33.73,-81.2 -8.16,-17.37 -5.61,-35.28 -5.61,-35.28 1.81,-7 3.64,-12.54 5.48,-16.85 3.27,-9.56 7.03,-22.96 9.88,-38.76 10.13,-22.39 21.09,-48.44 25.98,-66.09 10.22,-36.81 24.51,-102.3 4.09,-247.53 -20.41,-145.21 -215.75,-151.34 -274.96,-175.91 -40.77,-16.9 4.76,-30.67 82.01,-16.35 34.95,6.5 80.11,35.32 122.51,43.97 17.97,3.67 29.54,5.36 36.09,5.44 114.98,145.4 183.81,329.08 183.81,528.99 0,22.48 -1.13,44.67 -2.83,66.7" + inkscape:connector-curvature="0" /> + <path + id="path82" + style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2527.18,3484.46 c 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 -14.35,4.48 -16.31,16.03 -23.22,23.97 z m -22.94,26.32 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m 160.36,-21.48 c 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 z m 88.05,-72.17 c 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 z m -311.91,160.11 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37" + inkscape:connector-curvature="0" /> + <path + id="path84" + style="fill:#f6836c;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2529.01,2752.37 c -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42" + inkscape:connector-curvature="0" /> + <path + id="path86" + style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2326.23,2354.71 c 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 z m 40.64,1.81 c 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 z m 40.42,22 c 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 z m 57.45,25.09 c 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 z m 44.26,31.78 c 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 z m 48.77,40.94 c 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 z m 185.39,120.94 c 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 z m -83.83,-151.23 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m 15.48,114.75 c 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 z m 101.12,357.36 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m -37.63,-68.3 c 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 z m -71.11,-9.21 c 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 z m -108.01,18.58 c -16.99,21.48 -27.18,59.39 -21,84.23 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 z m -83.19,11.35 c -17.28,21.7 -27.77,60.21 -21.65,85.66 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 z m -80.49,-21.24 c -20.89,28.13 -34.89,78.07 -29.36,111.18 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 z m -80.64,17.63 c -20.8,24.29 -34.51,68.64 -28.73,98.66 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 z m -78.28,28.17 c -15.16,21.15 -23.52,58.34 -17.11,82.67 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 z m -61.99,15.5 c -13.96,16.84 -22.79,46.55 -18.34,66.13 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 z m -72.12,-11.61 c -16.8,18.79 -28.15,52.6 -23.84,75.42 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 z m -52.45,0.72 c -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63" + inkscape:connector-curvature="0" /> + <path + id="path88" + style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2806.87,3351.66 c 12.87,7 28.05,52.37 59.22,33.53 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87" + inkscape:connector-curvature="0" /> + <path + id="path90" + style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none" + d="m 2731.38,3432.29 c -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 z m -55.32,-35.43 c -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 z m -125.66,63.63 c -14.35,4.48 -16.31,16.03 -23.22,23.97 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 z m -46.16,50.29 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m -400.52,-594.93 c 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63 -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 z m 24.44,3.25 c 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 -16.8,18.79 -28.15,52.6 -23.84,75.42 z m 77.62,2.32 c 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 -13.96,16.84 -22.79,46.55 -18.34,66.13 z m 63.22,1.04 c 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 -15.16,21.15 -23.52,58.34 -17.11,82.67 z m 66.66,-12.18 c 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 -20.8,24.29 -34.51,68.64 -28.73,98.66 z m 80.01,-5.11 c 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 -20.89,28.13 -34.89,78.07 -29.36,111.18 z m 88.2,-4.28 c 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 -17.28,21.7 -27.77,60.21 -21.65,85.66 z m 83.84,-12.78 c 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 -16.99,21.48 -27.18,59.39 -21,84.23 z m 79.05,-19.65 c 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 z m 101.86,1.14 c 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 z m 98.58,-102.42 c 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42 -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 z m -41.74,95.63 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m 8.86,-374.35 c -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 z m -57.5,-52.94 c -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 z m -67.96,-44.82 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m -59.7,-50.77 c -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 z m -59.67,-53.19 c -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 z m -57.23,-32.78 c -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 z m -54.59,-28.17 c -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 z m -44.74,-1.44 c -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 z m -42.56,7.47 c -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 z m 50.37,1345.42 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37 z m 1173.75,-787.01 c -11.13,19.41 -23.35,38.42 -27.12,54.62 8.95,-5.92 16.34,-12.8 22.76,-20.33 -1.34,9.41 -2.92,18.74 -4.57,28.06 -9.71,7.73 -20.63,14.52 -33.49,19.89 -20.69,92.5 -65.21,150.91 -156.67,184.3 -30.66,11.19 -59.7,24.15 -89.94,37.34 1.75,98.46 -112.47,96.39 -183.64,147.07 -30.95,22.1 -66.05,62.87 -101.46,70.41 -68.48,14.6 -110.62,-33.23 -151.06,-66.63 -9.93,10.85 -24.8,21.45 -46.38,31.1 0,0 -38.6,55.15 -56.6,65.52 -1.19,0.69 -2,1.32 -2.52,1.93 -9.94,4.68 -22.41,7.31 -31.21,13.14 -8.7,5.73 -10.35,19.28 -19.05,25.84 -4.26,3.2 -10.87,6.67 -16.65,8.99 -6.98,2.81 -18.94,2.29 -25.97,6.14 -8.65,4.75 -9.34,20.2 -15.61,27.87 -6.91,8.47 -15.8,15.4 -30.18,20.24 -5.83,1.94 -14.63,2.07 -19.9,4.9 -5.88,3.18 -7.32,13.15 -11.87,19.26 -10.58,14.26 -28.45,25.31 -48.83,32.52 -4.39,1.55 -10.28,1.55 -13.49,3.71 -4.03,2.7 -4.19,9.73 -6.94,14.64 -4.25,7.58 -9.92,15.28 -19.06,19.99 -3.91,2.04 -9.92,1.85 -13.75,4.03 -4.5,2.58 -5.71,8.88 -9.5,12.57 -7.66,7.48 -16.76,13.16 -35.67,8.31 -6.7,8.69 -15.55,15.67 -29.96,18.64 l -0.44,-0.77 c 1.82,-17.24 4.29,-34.66 17.38,-46.59 -3.32,-19.81 5.98,-34.36 21.01,-46.08 3.62,-2.83 9.62,-4.32 12.72,-8.05 4.11,-4.96 2.41,-15.04 4.2,-21.26 5.56,-19.2 17.41,-36.84 37.11,-51.25 2.88,-2.12 8.38,-3.14 10.88,-5.97 5.5,-6.25 3.9,-16.74 8.05,-23.95 4.36,-7.59 11.79,-16.75 20.96,-23.81 5.03,-3.88 12.53,-5.95 17.23,-10.57 3.81,-3.73 4.86,-10.44 7.58,-16.02 7.35,-15.1 26.81,-32.59 36.15,-48.37 1.23,-2.08 2.2,-4.3 3.01,-6.54 3.89,-8.03 13.3,-25.05 26.13,-32.91 0,0 1.34,-23.63 24.86,-50.57 -47.65,2.58 -93.62,29.56 -128.96,2.76 -10.2,11.15 -42.93,19.9 -56.94,4.25 -10.33,18.01 -65.18,29.5 -75.85,1.04 -77.98,35.05 -172.08,-14.92 -202.33,-65.08 -5.61,-2.68 -10.86,-5.51 -15.82,-8.41 -21.34,6.43 -50.25,8.71 -81.54,-13.89 -30.84,-22.29 -63.08,-122.26 -57.53,-191.48 0.6,-7.41 14.64,-24.92 19.68,-59.99 5.02,-34.8 8.83,-46.22 8.83,-46.22 -6.86,-11.99 -15.04,-17.35 -16.15,-31.38 -2.42,-30.36 23.49,-46.85 47.76,-62.4 8.65,-4.04 18.42,-6.93 29.04,-7.32 6.41,-10.15 31.11,-44.55 71.94,-44.55 1.01,0 2.04,0.07 3.04,0.13 15.59,-13.13 31.86,-16.66 20.63,-0.47 -0.93,1.33 -1.72,2.83 -2.46,4.38 7.51,-4.47 16.59,-8.82 24.69,-9.61 0.16,-0.02 3.98,-0.98 7.14,-0.98 1.14,0 4.48,0 5.66,2.57 1.18,2.6 -1.2,5.38 -1.99,6.28 -3.27,3.77 -6.95,13.59 -9.72,22.76 3,-5.5 6.25,-10.71 9.9,-15.21 19.43,-23.89 46.63,-35.2 31.44,-11.41 -4.87,7.61 -7.65,17.99 -9.01,29.01 7.53,-9.28 20.49,-20.09 41.56,-24.4 17.42,-16.59 39.07,-23.38 26.1,-5.74 -3.32,4.51 -5.48,10.33 -6.77,16.68 10.5,-12.62 28.26,-28.83 50.03,-28.83 l 1.59,0.03 0.44,0.02 c 14.94,-10.11 27.45,-11.8 16.27,2.79 -4.84,6.36 -7.48,15.16 -8.67,24.45 9.87,-20.16 28.91,-47.92 61.69,-56.83 0.24,-0.1 5.89,-1.65 10.55,-1.65 3.63,0 5.93,0.93 7.02,2.92 1.59,2.87 -0.5,6.19 -1.19,7.28 -2.11,3.41 -4.08,7.64 -5.78,11.82 14.71,-8.64 25.59,-9.38 14.13,4.7 -5.91,7.26 -9.06,17.5 -10.36,28.08 8,-21.41 24.29,-51.48 56.48,-71.19 0.23,-0.11 6.03,-2.83 12.45,-2.83 3.1,0 5.87,0.64 8.26,1.84 2.05,1.07 3.39,2.8 3.94,5 1.68,6.71 -4.68,16.25 -5.25,17.03 -2.65,5.22 -7.5,16.25 -9.89,25.91 l 0.24,-0.2 c 23.26,-18.8 53.46,-27.51 34.83,-8.75 -11.31,11.4 -15.67,30.94 -16.06,46.89 6.8,-19.1 23.32,-52.18 57.54,-58.74 0.23,-0.02 5.53,-1.04 9.45,-1.04 2.17,0 4.79,0.24 5.71,2.34 0.39,0.88 0.55,2.32 -1,4.06 -2.56,2.89 -6.19,11.58 -8.12,18.61 1.62,-1.24 3.2,-2.56 4.89,-3.65 16.6,-10.91 36.19,-16.61 38.75,-13.08 5.3,-4.36 13.61,-10.09 24.89,-15.06 1.06,-2.42 2.1,-4.84 2.95,-7.27 0,0 5.26,-14.67 7.29,-22.61 -26.85,6.97 -72.8,20.47 -106.99,12.91 -27.01,-5.96 -97.4,-44.95 -80.38,-72.36 1.14,-1.83 2.59,-3.1 4.26,-4.14 l 1.05,-0.4 c 6.73,-3.59 18.58,-5.69 31.05,-5.59 l 4.53,0.13 c 7.25,0.4 26.23,3.13 32.67,5.22 18.82,6.13 35.64,2.45 35.64,2.45 l -0.25,-0.17 c 13.38,-1.57 27.5,-6.27 42.08,-13.73 15.66,-7.98 36.97,-21.16 42.4,-27.67 9.78,-11.78 -5.21,-39.4 -10.8,-56.41 -0.27,-1 -0.61,-2.05 -0.94,-3.09 l -0.39,-1.41 -0.06,0.04 c -0.79,-2.39 -1.76,-4.89 -2.81,-7.45 -0.95,1.2 -1.8,2.36 -2.43,3.44 -5.35,9.03 -8.24,16.93 -11,13.3 -2.77,-3.64 -2.9,-18.05 2.36,-31.66 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.06,-11.12 -13.42,-22.77 -21.18,-33.92 -6.03,5.72 -12.13,12.17 -15.09,17.31 -6.89,11.83 -10.56,22.21 -14.08,17.43 -3.56,-4.74 -3.65,-23.89 3.1,-41.86 2.2,-5.87 5.57,-11.18 9.09,-15.82 -5.35,-6.76 -10.57,-13.01 -15.34,-18.31 -2.14,-2.37 -4.66,-5.02 -7.34,-7.8 -7.36,7.62 -16.68,18.03 -20.45,25.58 -6.56,13.19 -9.94,24.43 -13.67,19.64 -3.72,-4.82 -4.45,-25.07 1.76,-44.65 2.55,-8.02 6.95,-15.34 11.3,-21.3 -7.98,-7.6 -16.65,-15.65 -25.55,-23.79 -5.4,7.18 -10.72,15.06 -13.16,21.1 -5.85,14.26 -8.62,26.35 -12.58,21.72 -3.89,-4.67 -5.6,-25.71 -0.35,-46.68 1.29,-5.17 3.26,-10.14 5.51,-14.74 -8.82,-7.89 -17.35,-15.45 -25.18,-22.31 -2.3,5.01 -4.22,9.75 -5.28,13.66 -4.6,16.98 -6.32,31 -10.84,26.71 -4.53,-4.2 -8.38,-26.82 -5.07,-50.86 0.31,-2.3 0.76,-4.59 1.27,-6.88 l -2.21,-1.9 c -5.11,-4.43 -10.68,-9.77 -16.44,-15.64 -1.43,4.52 -2.54,8.74 -3.13,12.25 -2.91,17.7 -3.36,31.85 -7.99,28.47 -4.62,-3.32 -10.15,-25.15 -9.04,-49.57 0.17,-3.84 0.64,-7.72 1.27,-11.52 -6.76,-7.62 -13.45,-15.51 -19.75,-23.18 -3.65,9.38 -6.95,19.1 -8.23,26.11 -3.34,18.53 -4.03,33.4 -8.76,29.75 -4.33,-3.29 -9.08,-23.12 -8.56,-46.19 -4.71,-3.45 -10.82,-19.53 -11.02,-37.76 -0.09,-6.2 1.01,-12.55 2.51,-18.29 -3.05,-4.31 -8.4,-7.29 -12.14,-12.57 -19.3,-27.05 -11.43,-59.27 30.28,-66.44 12.78,-39.46 45.17,-58.61 94.87,-59.05 6.68,-0.07 13.64,2.27 20.18,1.86 7.38,-0.5 13.46,-3.5 20.2,-3.71 36.22,-1.09 55.22,10.43 82.74,18.48 20.55,5.96 41.74,7.89 54.52,12.9 19.57,7.68 28.87,28.77 44.4,38.76 5.78,3.71 16.69,5.46 26.25,11.06 8.07,4.75 15.05,13.39 22.2,16.6 6.24,2.85 16.65,2.28 24.22,5.55 12.67,5.51 26.68,17.4 42.4,25.86 32.91,17.63 59.7,30.68 94.87,46.11 16.8,7.38 34.58,24.72 44.41,25.84 11.65,1.35 25.22,-8.4 34.31,-7.37 18.52,-22.06 24.98,-52.89 24.2,-92.52 1.1,-0.11 0.29,-9.83 0.29,-9.83 0,0 6.47,-85.09 -126.17,-131.03 -41.25,-14.28 -117.07,-51.81 -173.39,-80.72 218.91,6.81 416.91,96.33 564.01,238.52 -44.49,-11.55 -91.92,-41.79 -121.13,-44.56 -79.65,-7.55 -93.92,27.92 -30.29,33.77 24.03,2.21 59.49,4.92 87.8,18.38 49.4,23.51 100.3,46.22 127.3,60.84 4.41,5.31 8.63,10.78 12.92,16.2 -6.55,-0.08 -18.12,-1.77 -36.09,-5.44 -42.4,-8.65 -87.56,-37.47 -122.51,-43.97 -77.25,-14.32 -122.78,-0.55 -82.01,16.35 59.21,24.57 254.55,30.7 274.96,175.91 20.42,145.23 6.13,210.72 -4.09,247.53 -4.89,17.65 -15.85,43.7 -25.98,66.09 -2.85,15.8 -6.61,29.2 -9.88,38.76 -1.84,4.31 -3.67,9.85 -5.48,16.85 0,0 -2.55,17.91 5.61,35.28 7.23,15.43 32.05,48.86 33.73,81.2 0.03,1.96 0.11,3.92 0.08,5.88 -0.1,2.19 -0.29,4.35 -0.63,6.51 l -0.18,1.91 c -3.19,18.14 -13.58,30.77 -27.69,40.18 -9.09,6.04 -21.46,7.95 -28.26,16.59 5.42,17.09 22.71,23.17 29.91,37.14 4.5,12.39 0.83,25.42 -6.01,37.26 -13.17,14.79 -39.04,27.62 -62.26,36.33 -29.07,10.92 -58.62,19.54 -78.59,35.23 -21.11,11.25 -35.29,33.01 -22.34,61.76 3.37,7.48 4.87,15 4.77,22.16 l -0.09,2.09 c -0.03,1.46 -0.23,2.77 -0.41,4.12 -0.16,1.04 -0.33,2.07 -0.56,3.09 l -0.47,1.79 -0.56,2.02 c -5.32,17.95 -33.54,23.01 -43.6,23.9 -22.79,2.05 -37.52,8.24 -49.63,12.08 9.74,-5.08 19.54,-11.85 32.01,-16.88 7.9,-3.22 19.23,-5.15 28.78,-8.33 l 0.07,0.01 c 0,0 17.62,-3.57 22.46,-15.85 4.85,-12.27 2.04,-23.01 0,-29.9 l -0.74,-1.99 c -1.76,-5.39 -3.73,-10.57 -4.14,-15.93 -1.65,-21.14 11.3,-32.16 18.17,-49.84 12.39,-11.79 30.03,-24 54.5,-35.05 21.98,-9.96 48.29,-15.98 64.59,-25.84 9.45,-5.71 26.64,-19.51 26.25,-29.55 -0.3,-7.68 -14.47,-18.17 -20.19,-25.82 -4.07,-5.45 -6.11,-12.68 -9.75,-17.83 -3.19,-5.02 -7.26,-8.26 -11.96,-8.26 -6.12,0 -20.08,-2.37 -10.89,-3.06 9.18,-0.68 33.01,-11.93 33.01,-11.93 l -0.02,-0.03 c 32.2,-13.33 53.84,-38.06 42,-73.32 -9.91,-29.53 -32.71,-54.25 -34.31,-86.74 -1.7,-34.56 14.12,-63.03 16.14,-90.44 3.42,-46.12 -3.19,-77.9 -12.1,-112.58 -4.18,-16.21 -6.4,-32.18 -10.09,-47.96 -15.72,-67.21 -56.27,-96.32 -111.03,-127.36 -23.74,-13.46 -49.22,-38.28 -74.69,-46.13 -4.09,-1.26 -10.41,0.66 -14.14,0 -23.46,-4.25 -44.57,-15.89 -68.63,-20.3 -22.66,-4.17 -46.42,-2.18 -73.31,-8.99 -13.65,-4.88 -31.13,-12.18 -41.34,-16.53 -15.79,-7.19 -31.26,-14.69 -46.7,-22.26 L 2782.7,2380 c 0,0 -28.58,-16.57 3.07,-4.31 25.46,9.88 112.97,53.51 76.31,27.89 -25.28,-12.72 -38.99,-30.79 -61.35,-46.2 0,0 -75.23,-37.37 -86.52,-47.81 -12.4,-11.48 -27.56,-5.13 -37.52,-16.37 -11.69,-13.22 -26.02,-21.13 -36.24,-24.55 -10.2,-3.43 -21.77,-25.92 -37.43,-37.5 -15.66,-11.59 -49.68,-8.18 -79.64,-21.14 -29.94,-12.95 -60.97,-13.12 -60.97,-13.12 -2.98,-0.28 -5.85,-0.46 -8.61,-0.54 -1.18,-0.02 -2.28,0 -3.41,0 -17.52,-0.1 -30.91,3.31 -41.17,7.09 -12.51,4.61 -17.1,2.3 -14.29,0.78 2.8,-1.54 10.95,-9.16 10.95,-9.16 -34.93,0.04 -44.47,23.3 -60.55,40.57 7.31,1.04 28.16,-4.06 17.57,2.08 -20.92,10.03 -61.21,10.74 -61.99,34.85 -0.61,18.9 8.07,14.77 8.07,14.77 14.65,-25.56 59.89,-28.07 92.87,-27.71 61.43,0.73 103.01,34.49 143.27,53.58 13.05,7.86 28.3,18.19 28.3,18.19 l -0.09,-0.31 c 12.72,8.3 25.56,16.35 36.43,26.37 18.96,17.45 31.78,40.22 48.46,59.56 1.94,3.28 6.01,7.3 10.85,11.33 4.7,4.43 9.76,8.54 15.38,12.15 l 0.22,-0.45 2.18,1.47 -0.39,0.82 c 40.51,23.02 78.28,48.49 110.13,79.41 l 0.22,0.36 c 4.56,4.16 28.54,30.96 40.13,43.98 13.65,18.24 23.49,41.29 29.19,64.5 2.06,8.4 0.75,18.61 4.03,27.7 5.08,14.1 17.87,26.65 26.25,40.58 8.68,14.51 14.42,30.31 20.18,46.15 25.25,69.52 54.45,124.86 109,162.4 26.29,18.11 58.21,29.77 76.7,57.24 -13.42,-13.68 -30.91,-23.63 -52.03,-30.26 -59.98,-19.78 -98.99,-70.5 -118.6,-102.69 -15.06,-27.12 -26.7,-57.34 -35.25,-90.38 -2.85,40.73 -12.88,72.51 -26.25,103.36 -11.89,27.42 -22.4,56.41 -44.41,73.8 0,0 -0.85,-0.05 -4.26,2.02 -3.4,2.02 56.74,3.53 56.74,3.53 10.53,-0.38 21.23,-1.88 32.09,-3.3 2.03,0.22 4.53,0.11 7.59,-0.44 33.06,-5.84 67.43,6.49 88.83,22.1 11.11,8.1 30.43,14.59 46.46,18.98 0.27,0.7 1.83,1.48 5.83,2.26 0,0 24.5,7.65 50.53,14.82 17.63,4.84 30.48,8.54 39.39,12.95 5.17,3.29 10.09,7.25 13.9,11.99 7.63,9.42 7.77,20.74 14.14,36.9 6.33,16.1 16.01,28.63 16.14,42.45 0.46,45.3 -42.37,81.38 -88.81,57.23 45.72,11.8 78.15,-10.54 72.67,-53.55 -6.76,-53.12 -86.66,-92.5 -135.25,-112.57 -19.26,-7.94 -41.82,-17.98 -64.59,-20.29 -32.85,-3.33 -62.6,3.7 -90.84,1.86 -36.22,-2.4 -60.3,-21.58 -90.84,-24.01 -26.24,-2.1 -22.68,15.68 -45.45,17.71 -4.72,2.68 -19.04,0 -33.28,0.73 -39.38,-10.42 -64.7,7.62 -96.88,22.16 -23.21,10.51 -47.98,20.06 -72.68,22.15 -62,5.27 -99.7,-3.37 -150.38,2.01 -14.29,1.53 -43.95,3.33 -58.03,8.62 -43.84,16.43 -77.41,10.48 -125.04,11.15 -34.65,0.51 -66.8,2.33 -88.43,-1.46 -5.9,-1.07 -11.87,-2.6 -18.18,-3.7 -46.42,-8.13 -117.12,-12.34 -115.05,-53.52 3.46,2.37 2.5,8.77 8.07,9.23 -0.2,-7.58 -0.39,-15.14 2.01,-20.32 -26.99,0.7 -42.91,19.37 -42.38,40.6 0.9,36.12 58.9,51.22 98.91,60.92 40.1,9.7 81.75,21.05 111.03,25.84 -70.13,-10.33 -144.31,-16.97 -197.84,-42.47 -0.75,2.77 -1.24,5.45 -1.55,8.02 -4.24,19.49 -13.48,49.4 -19.98,78.46 -7.48,33.4 4.07,92.05 4.07,92.05 l 0.29,-0.34 c 4.83,29.8 10.98,43.09 16.94,60.9 12.69,38.01 53.68,49.94 82.38,53.55 -24.19,-17.13 -39.65,-38.36 -49.44,-66.79 -1.21,-10.09 -2.15,-19.55 -2.85,-27.9 21.73,67.74 82.33,93.09 82.33,93.09 l 19.4,20.96 -0.24,-0.95 c 33.45,32.42 77.66,57.54 133.84,59.13 28.31,0.79 62.52,-6.68 62.43,-34.49 -0.05,-15.73 -12.32,-29.09 -29.06,-36.46 4.92,-0.97 9.43,-0.29 13.51,1.4 l 17.4,19.5 c 5.74,14.26 5.24,32.26 -4.46,43.12 25.6,21.93 65.46,-2.67 62.56,-31.76 7.49,6.33 12.06,18.3 6.91,27.78 34.44,20.28 53.72,-28.88 88.39,-17.4 -3.27,9.84 -19.95,7.84 -25.04,16.05 45.31,6.5 85.06,-9.46 130.49,-5.85 2.85,-2.48 5.94,-4.94 9.21,-7.4 -84.98,-9.42 -15.93,-9.37 -15.93,-9.37 10.88,1 37.03,2.83 47.19,1.01 16.65,-3 27.39,1.06 42.09,6.82 0.36,-0.64 1.83,-0.59 2.72,1.08 7.62,3 16.41,6.34 27.56,9.36 4.32,0.61 8.66,1.72 12.88,3.09 l 1.82,0.38 0.25,0.29 c 5.83,2.03 11.31,4.46 16.01,6.75 42.83,20.61 78.34,69.18 114.92,94.66 60.61,42.19 118,-9.93 160.2,-43.76 l -0.27,-0.4 c 10.58,-7.23 24.53,-16.15 39.73,-25.48 39.71,-17.3 92.08,-32.44 120.05,-60.13 22.38,-22.15 29.99,-50.67 39.62,-80.27 8.98,-27.62 26.42,-52.03 36.22,-83.01 1.89,1.58 3.01,3.97 3.64,6.83 -0.27,2.65 -0.7,5.44 0.09,7.16 l 0.53,-0.48 c -0.11,5.41 -1.3,11.74 -3.15,18.42 -8.32,16.97 -22.86,36.29 -21.07,51.41 0,0 51.58,-26.7 110.11,-53.23 20.15,-9.14 38.61,-24.2 54.71,-41.42 l 4.7,0.11 c -0.56,-1.21 -0.5,-2.95 -0.33,-4.78 28.44,-31.94 48.61,-69.98 55.62,-91.97 1.45,-4.52 3.08,-9.09 4.84,-13.64 l 0.01,-0.06 c 2.21,-5.73 4.59,-11.4 7.04,-16.85 l 0.05,0.07 c 1.04,-1.85 1.69,-3.67 2.39,-5.51 8.44,-18.32 16.73,-33.17 19.05,-37.24 9.93,-12.38 17.35,-29.34 26.56,-40.46 -0.53,6.85 -0.88,13.75 -1.56,20.55 z m -826.19,277.09 c 87.27,-80.81 98.01,-168.37 104.71,-193.66 6.6,-25.12 9.82,-16.62 9.82,-16.62 1.21,85.58 -66.47,193.97 -127.36,229.62 -60,35.19 -215.11,29.07 -251.54,31.9 -35.85,2.74 -53.77,-42.93 -53.77,-42.93 -0.46,-9.67 7.43,1.42 7.43,1.42 23.42,42.28 44.01,34.55 44.01,34.55 74.22,-21.72 87.45,-130.94 90.54,-156.26 3.07,-25.11 9.41,-8.76 9.41,-8.76 7.21,62.85 -38.53,139.45 -48.15,149.3 -9.61,9.76 -0.43,15.3 30.23,6.7 92.32,-25.96 100.96,-174.08 106.52,-192.04 5.57,-17.89 9.03,-0.68 9.03,-0.68 -12.48,136.19 -64.16,169.77 -77.93,188.5 -5.72,7.77 40.96,8.94 61.5,-4.45 116.01,-75.08 102.99,-218.89 113.43,-198.36 10.58,20.95 -29.19,151.09 -85.08,195.37 -11.18,8.84 38.79,-6.6 57.2,-23.6 z m 214.59,112.44 c 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87 12.87,7 28.05,52.37 59.22,33.53 z m 2.05,33.45 c 8.47,2.44 35.81,-1.73 18.17,1.85 -17.72,4.96 -28.72,-0.09 -40.36,-7.4 -26.76,-16.75 -48.56,-55.22 -76.72,-71.95 -12.22,-7.31 -24.17,-5.63 -34.33,-18.48 6.58,-13.17 13.26,-5.42 22.22,-7.38 19.86,-4.32 38.16,-12.04 56.52,-23.96 20.33,-13.25 42.35,-37.56 72.67,-35.09 9.67,0.77 27.24,10.15 34.32,14.77 8.84,5.77 29.83,19.54 24.22,40.6 -2.49,9.33 -13.59,10.83 -20.2,18.46 -9.15,10.61 -8.8,21.03 -16.13,33.21 15.98,-3.22 25.13,-12.71 42.37,-14.77 -27.15,24.39 -58.44,45 -96.88,59.07 2.88,1.64 4.72,8.35 14.13,11.07 z M 2223.96,3307.9 c -2.19,16.18 -17.4,30.55 -44.41,22.16 0,0 -34.92,-7.98 -44.43,-69.84 0,0 -1.66,-31.21 8.1,-24.31 -8.22,37.5 27.37,54.49 35.53,58.3 11.48,5.13 20.97,3.4 21.69,-6.37 0.79,-10.54 -11.24,-15.2 -14.84,-26.07 12.77,7.22 41.33,24.13 38.36,46.13 z m 668.31,-133.09 c 27.34,4.37 78.51,23.3 99.04,36.15 22.28,13.93 38.84,67.36 16.13,96.94 -10.17,13.24 -34.52,30.03 -40.38,31.38 -6.68,-3.88 4.2,-7.41 6.05,-9.22 7.7,-7.6 24.88,-21.51 30.28,-33.22 11.03,-23.95 7.65,-60.6 -12.12,-73.85 -13.32,-8.9 -78.47,-33.25 -106.97,-33.21 -80.17,0.11 -88.31,88.29 -137.27,118.12 0.87,-8.43 7.02,-26.13 14.02,-35.28 27.53,-36 53.83,-110.21 131.22,-97.81" + inkscape:connector-curvature="0" /> + <path + id="path92" + style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2433.33,2370.61 c 0.44,-4.18 2.32,-8.2 3.64,-12.03 0.27,19.49 1.09,47.95 21.49,59.93 3.2,1.86 6.38,2.84 9.52,2.84 8.01,0 13.14,-5.65 16.36,-12.02 -0.35,15.85 1.93,31.07 12.45,38.27 5.18,3.59 10,5.32 14.61,5.32 13.21,0 18.54,-13.65 21.4,-20.98 0.47,-1.15 0.86,-2.18 1.27,-3.11 5.43,-12.42 19.9,-37.76 26.67,-43.33 2.68,2.13 6.03,4.9 7.08,6.42 -0.37,0.5 -0.99,1.17 -1.78,2.1 -42.06,48.68 -29.05,81.43 -10.7,100.35 1.31,1.51 4.77,4.85 9.87,4.85 6.26,0 11.15,-4.56 14.53,-13.49 5.33,-14.1 26.51,-41.61 30.55,-44.43 l 0.99,-0.49 c 2.07,-1.05 4.66,-2.36 6.14,-2.36 l 1.2,0.74 c 1.32,1.41 2.02,2.65 2.41,3.58 -8.82,10.66 -39.16,50.51 -27.93,82.65 1.66,4.78 6.74,19.34 18.65,19.34 10.99,0 18.37,-13.19 20.89,-18.44 6.44,-8.21 23.48,-28.51 32.54,-33.85 2.24,-1.27 4.78,-1.95 7.56,-1.95 4.48,0 8.36,1.68 10.27,2.81 -10.65,8.04 -31.32,39.91 -24.68,67.59 2.94,12.3 13.27,17.81 22.2,17.81 4.37,0 8.25,-1.27 10.93,-3.61 1.01,-0.87 3.11,-3.14 5.94,-6.27 7.87,-8.61 26.27,-28.86 37.27,-32.77 2.14,-0.75 4.09,-1.15 5.87,-1.15 4.13,0 6.86,2.09 9.5,4.82 -0.73,0.56 -1.66,1.22 -2.86,2.02 -4.97,3.36 -29.76,28.79 -19.55,60.6 3.72,11.63 12.01,12.88 15.4,12.88 7.95,0 15.18,-5.84 18.19,-9.31 5.35,-6.09 26.76,-24.07 32.16,-24.45 4.01,0.71 2.25,2.71 8.31,10.37 5,11.5 -10.48,12.08 -25.14,16.79 -8.01,2.57 -25.83,21.87 -41.9,14.16 -16.06,-7.69 -172.23,-113.68 -103.34,-29.72 28.99,35.32 66.68,50.35 63.89,59.45 -4.26,13.83 -48.2,14.69 -60.75,23.8 -6.53,4.73 -12.16,-5.39 -16.07,-14.7 -39.01,-152.94 -175.78,-233.82 -188.79,-242.48 0,0 -35.95,-22.04 -26.53,-21.68 9.43,0.34 27.02,3.64 30.27,-26.87" + inkscape:connector-curvature="0" /> + <path + id="path94" + style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none" + d="m 2747.21,2810.08 c -62.51,-19.99 -119.08,-11.38 -119.08,-11.38 -22.18,0.52 -23.98,27.54 -27.27,49.98 -3.36,23 22.07,-23.5 53.19,-30.48 29.63,-6.74 40.8,-4.57 37.8,18.39 -3.21,24.06 27.8,-3.65 46.52,-7.14 0,0 2.3,-1.48 12,-0.96 9.68,0.53 27.48,-6.91 -3.16,-18.41" + inkscape:connector-curvature="0" /> + </g> + </g> + </g> + </g> +</svg> diff --git a/deps/uv/include/uv-aix.h b/deps/uv/include/uv-aix.h new file mode 100644 index 0000000000..7dc992fa6d --- /dev/null +++ b/deps/uv/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/deps/uv/include/uv-threadpool.h b/deps/uv/include/uv-threadpool.h new file mode 100644 index 0000000000..9708ebdd53 --- /dev/null +++ b/deps/uv/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/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index d59d743ef2..bbaaefc3ed 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -42,8 +42,12 @@ #endif #include <signal.h> +#include "uv-threadpool.h" + #if defined(__linux__) # include "uv-linux.h" +#elif defined(_AIX) +# include "uv-aix.h" #elif defined(__sun) # include "uv-sunos.h" #elif defined(__APPLE__) @@ -96,13 +100,6 @@ struct uv__async { int wfd; }; -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]; -}; - #ifndef UV_PLATFORM_SEM_T # define UV_PLATFORM_SEM_T sem_t #endif @@ -218,7 +215,7 @@ typedef struct { #define UV_UDP_SEND_PRIVATE_FIELDS \ void* queue[2]; \ - struct sockaddr_in6 addr; \ + struct sockaddr_storage addr; \ unsigned int nbufs; \ uv_buf_t* bufs; \ ssize_t status; \ diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index 6f8e080a46..d33c8f8bde 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,7 +32,7 @@ #define UV_VERSION_MAJOR 0 #define UV_VERSION_MINOR 11 -#define UV_VERSION_PATCH 26 +#define UV_VERSION_PATCH 28 #define UV_VERSION_IS_RELEASE 1 #endif /* UV_VERSION_H */ diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 2f24dfe890..136b0b45de 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -30,6 +30,15 @@ typedef intptr_t ssize_t; #endif #include <winsock2.h> + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; +#endif + #include <mswsock.h> #include <ws2tcpip.h> #include <windows.h> @@ -45,6 +54,7 @@ typedef intptr_t ssize_t; #endif #include "tree.h" +#include "uv-threadpool.h" #define MAX_PIPENAME_LEN 256 @@ -307,7 +317,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); /* Counter to keep track of active udp streams */ \ unsigned int active_udp_streams; \ /* Counter to started timer */ \ - uint64_t timer_counter; + 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 */ \ @@ -395,7 +409,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_TCP_PRIVATE_FIELDS \ SOCKET socket; \ - int bind_error; \ + int delayed_error; \ union { \ struct { uv_tcp_server_fields }; \ struct { uv_tcp_connection_fields }; \ @@ -520,6 +534,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); unsigned int flags; #define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ uv_getaddrinfo_cb getaddrinfo_cb; \ void* alloc; \ WCHAR* node; \ @@ -529,6 +544,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); int retcode; #define UV_GETNAMEINFO_PRIVATE_FIELDS \ + struct uv__work work_req; \ uv_getnameinfo_cb getnameinfo_cb; \ struct sockaddr_storage storage; \ int flags; \ @@ -547,6 +563,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); volatile char exit_cb_pending; #define UV_FS_PRIVATE_FIELDS \ + struct uv__work work_req; \ int flags; \ DWORD sys_errno_; \ union { \ @@ -572,6 +589,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); }; #define UV_WORK_PRIVATE_FIELDS \ + struct uv__work work_req; #define UV_FS_EVENT_PRIVATE_FIELDS \ struct uv_fs_event_req_s { \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index ef2f840d76..df6d9549c1 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -258,7 +258,8 @@ UV_EXTERN const char* uv_version_string(void); */ /* - * Returns the default loop. + * Returns the initialized default loop. It may return NULL in case of + * allocation failture. */ UV_EXTERN uv_loop_t* uv_default_loop(void); @@ -276,20 +277,24 @@ UV_EXTERN int uv_loop_close(uv_loop_t* loop); /* * Allocates and initializes a new loop. - * NOTE: This function is DEPRECATED (to be removed after 0.12), users should - * allocate the loop manually and use uv_loop_init instead. + * + * 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); /* * Cleans up a loop once it has finished executio and frees its memory. - * NOTE: This function is DEPRECATED (to be removed after 0.12). Users should use - * uv_loop_close and free the memory manually instead. + * + * 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*); /* - * Returns size of the loop struct, useful for dynamic lookup with FFI + * Returns size of the loop struct, useful for dynamic lookup with FFI. */ UV_EXTERN size_t uv_loop_size(void); @@ -316,10 +321,10 @@ UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); /* - * This function will stop the event loop by forcing uv_run to end - * as soon as possible, but 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. + * This function will stop the event loop by forcing uv_run to end as soon as + * possible, but 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. */ UV_EXTERN void uv_stop(uv_loop_t*); @@ -398,12 +403,12 @@ typedef void (*uv_alloc_cb)(uv_handle_t* handle, * `nread` is > 0 if there is data available, 0 if libuv is done reading for * now, or < 0 on error. * - * The callee is responsible for closing the stream when an error happens. - * Trying to read from the stream again is undefined. + * The callee is responsible for closing the stream when an error happens + * by calling 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 - * EOF or error. + * error. */ typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, @@ -505,17 +510,17 @@ struct uv_req_s { }; -/* Platform-specific request types */ +/* Platform-specific request types. */ UV_PRIVATE_REQ_TYPES /* - * uv_shutdown_t is a subclass of uv_req_t + * uv_shutdown_t is a subclass of uv_req_t. * - * 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. + * 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. */ UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, @@ -540,20 +545,19 @@ struct uv_shutdown_s { void* handle_queue[2]; \ UV_HANDLE_PRIVATE_FIELDS \ -/* The abstract base class of all handles. */ +/* The abstract base class of all handles. */ struct uv_handle_s { UV_HANDLE_FIELDS }; /* - * Returns size of various handle types, useful for FFI - * bindings to allocate correct memory without copying struct - * definitions + * Returns size of various handle types, useful for FFI bindings to allocate + * correct memory without copying struct definitions. */ UV_EXTERN size_t uv_handle_size(uv_handle_type type); /* - * Returns size of request types, useful for dynamic lookup with FFI + * Returns size of request types, useful for dynamic lookup with FFI. */ UV_EXTERN size_t uv_req_size(uv_req_type type); @@ -566,7 +570,7 @@ UV_EXTERN size_t uv_req_size(uv_req_type type); * 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, + * 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 @@ -601,6 +605,7 @@ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); /* * Constructor for 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. @@ -617,7 +622,7 @@ UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); UV_STREAM_PRIVATE_FIELDS /* - * uv_stream_t is a subclass of uv_handle_t + * uv_stream_t is a subclass of uv_handle_t. * * uv_stream is an abstract class. * @@ -636,16 +641,16 @@ UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); * the connection. Before calling uv_accept use uv_*_init() must be * called on the client. Non-zero return value indicates an error. * - * When the uv_connection_cb is called it is guaranteed that uv_accept will + * When the uv_connection_cb is called it is guaranteed that uv_accept() will * complete successfully the first time. If you attempt to use it more than - * once, it may fail. It is suggested to only call uv_accept once per + * once, it may fail. It is suggested to only call uv_accept() once per * uv_connection_cb call. */ UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); /* * Read data from an incoming stream. The callback will be made several - * times until there is no more data to read or uv_read_stop is called. + * times until there is no more data to read or uv_read_stop() is called. * 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; @@ -704,17 +709,19 @@ UV_EXTERN int uv_write2(uv_write_t* req, uv_write_cb cb); /* - * Same as `uv_write()`, but won't queue write request if it can't be completed + * Same as uv_write(), but won't queue 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 + * - > 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). */ 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 */ +/* uv_write_t is a subclass of uv_req_t. */ struct uv_write_s { UV_REQ_FIELDS uv_write_cb cb; @@ -755,15 +762,14 @@ UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking); /* * Used to determine whether a stream is closing or closed. * - * N.B. is only valid between the initialization of the handle - * and the arrival of the close callback, and cannot be used - * to validate the handle. + * N.B. is only valid between the initialization of the handle and the arrival + * of the close callback, and cannot be used to validate the handle. */ UV_EXTERN int uv_is_closing(const uv_handle_t* handle); /* - * uv_tcp_t is a subclass of uv_stream_t + * uv_tcp_t is a subclass of uv_stream_t. * * Represents a TCP stream or TCP server. */ @@ -795,15 +801,16 @@ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, /* * 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. + * 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. */ 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 */ + /* Used with uv_tcp_bind, when an IPv6 address is used. */ UV_TCP_IPV6ONLY = 1 }; @@ -811,11 +818,11 @@ enum uv_tcp_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 uv_tcp_bind(), uv_listen() or uv_tcp_connect(). + * When the port is already taken, you can expect to see an UV_EADDRINUSE error + * from either uv_tcp_bind(), uv_listen() or uv_tcp_connect(). * - * That is, a successful call to uv_tcp_bind() does not guarantee that - * the call to uv_listen() or uv_tcp_connect() will succeed as well. + * That is, a successful call to uv_tcp_bind() does not guarantee that the call + * to uv_listen() or uv_tcp_connect() will succeed as well. */ UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, @@ -829,7 +836,7 @@ UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle, /* * Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle - * and an uninitialized uv_connect_t*. `addr` should point to an initialized + * and an uninitialized uv_connect_t*. `addr` should point to an initialized * struct sockaddr_in or struct sockaddr_in6. * * The callback is made when the connection has been established or when a @@ -840,7 +847,7 @@ UV_EXTERN int uv_tcp_connect(uv_connect_t* req, const struct sockaddr* addr, uv_connect_cb cb); -/* uv_connect_t is a subclass of uv_req_t */ +/* uv_connect_t is a subclass of uv_req_t. */ struct uv_connect_s { UV_REQ_FIELDS uv_connect_cb cb; @@ -861,9 +868,10 @@ enum uv_udp_flags { * 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. + /* + * 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 + * 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. @@ -872,8 +880,7 @@ enum uv_udp_flags { }; /* - * Called after uv_udp_send(). status 0 indicates - * success otherwise error. + * Called after uv_udp_send(). status 0 indicates success otherwise error. */ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); @@ -882,14 +889,20 @@ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); * * 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. - * < 0 if a transmission error was detected. + * - 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 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. + * 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. */ typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, @@ -897,13 +910,23 @@ typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags); -/* uv_udp_t is a subclass of uv_handle_t */ +/* 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 */ +/* uv_udp_send_t is a subclass of uv_req_t. */ struct uv_udp_send_s { UV_REQ_FIELDS uv_udp_t* handle; @@ -921,16 +944,16 @@ UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); * Opens an existing file descriptor or 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. - * - * 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. + * 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. + * + * 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. * This behavior is something of an anomaly and may be replaced by an explicit * opt-in mechanism in future versions of libuv. */ @@ -940,7 +963,7 @@ UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); * Bind to an IP address and port. * * Arguments: - * handle UDP handle. Should have been initialized with `uv_udp_init`. + * handle UDP handle. Should have been initialized with uv_udp_init(). * addr struct sockaddr_in or struct sockaddr_in6 with the address and * port to bind to. * flags Indicate how the socket will be bound, UV_UDP_IPV6ONLY and @@ -953,7 +976,7 @@ UV_EXTERN int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags); -UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, +UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen); @@ -962,10 +985,10 @@ UV_EXTERN int uv_udp_getsockname(uv_udp_t* handle, * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * multicast_addr multicast address to set membership for - * interface_addr interface address - * membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP + * uv_udp_init(). + * multicast_addr multicast address to set membership for. + * interface_addr interface address. + * membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -981,8 +1004,8 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * on 1 for on, 0 for off + * uv_udp_init(). + * on 1 for on, 0 for off. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -990,12 +1013,12 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); /* - * Set the multicast ttl + * Set the multicast ttl. * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * ttl 1 through 255 + * uv_udp_init(). + * ttl 1 through 255. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -1004,12 +1027,12 @@ UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); /* - * Set the multicast interface to send on + * Set the multicast interface to send on. * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * interface_addr interface address + * uv_udp_init(). + * interface_addr interface address. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -1018,12 +1041,12 @@ UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr); /* - * Set broadcast on or off + * Set broadcast on or off. * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * on 1 for on, 0 for off + * uv_udp_init(). + * on 1 for on, 0 for off. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -1031,12 +1054,12 @@ UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); /* - * Set the time to live + * Set the time to live. * * Arguments: * handle UDP handle. Should have been initialized with - * `uv_udp_init`. - * ttl 1 through 255 + * uv_udp_init(). + * ttl 1 through 255. * * Returns: * 0 on success, or an error code < 0 on failure. @@ -1044,13 +1067,12 @@ 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); /* - * Send data. If the socket has not previously been bound with `uv_udp_bind,` - * it is bound to 0.0.0.0 (the "all interfaces" address) and a random - * port number. + * Send data. If the socket has not previously been bound with uv_udp_bind() it + * is bound to 0.0.0.0 (the "all interfaces" address) and a random port number. * * Arguments: * req UDP request handle. Need not be initialized. - * handle UDP handle. Should have been initialized with `uv_udp_init`. + * handle UDP handle. Should have been initialized with uv_udp_init(). * bufs List of buffers to send. * nbufs Number of buffers in `bufs`. * addr struct sockaddr_in or struct sockaddr_in6 with the address and @@ -1068,12 +1090,25 @@ UV_EXTERN int uv_udp_send(uv_udp_send_t* req, uv_udp_send_cb send_cb); /* - * Receive data. If the socket has not previously been bound with `uv_udp_bind` - * it is bound to 0.0.0.0 (the "all interfaces" address) and a random - * port number. + * Same as uv_udp_send(), but won't queue a send request if it can't be completed + * immediately. + * + * Will return either: + * - >= 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). + */ +UV_EXTERN int uv_udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr); +/* + * Receive data. If the socket has not previously been bound with uv_udp_bind() + * it is bound to 0.0.0.0 (the "all interfaces" address) and a random port + * number. * * Arguments: - * handle UDP handle. Should have been initialized with `uv_udp_init`. + * handle UDP handle. Should have been initialized with uv_udp_init(). * alloc_cb Callback to invoke when temporary storage is needed. * recv_cb Callback to invoke with received data. * @@ -1088,7 +1123,7 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, * Stop listening for incoming datagrams. * * Arguments: - * handle UDP handle. Should have been initialized with `uv_udp_init`. + * handle UDP handle. Should have been initialized with uv_udp_init(). * * Returns: * 0 on success, or an error code < 0 on failure. @@ -1097,7 +1132,7 @@ UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); /* - * uv_tty_t is a subclass of uv_stream_t + * uv_tty_t is a subclass of uv_stream_t. * * Representing a stream for the console. */ @@ -1109,12 +1144,12 @@ struct uv_tty_s { /* * Initialize a new TTY stream with the given file descriptor. Usually the - * file descriptor will be + * file descriptor will be: * 0 = stdin * 1 = stdout * 2 = stderr * The last argument, readable, specifies if you plan on calling - * uv_read_start with this stream. stdin is readable, stdout is not. + * uv_read_start() with this stream. stdin is readable, stdout is not. * * TTY streams which are not readable have blocking writes. */ @@ -1129,7 +1164,7 @@ UV_EXTERN int uv_tty_set_mode(uv_tty_t*, int mode); * 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 + * 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 uv_tty_set_mode(). */ UV_EXTERN int uv_tty_reset_mode(void); @@ -1143,15 +1178,16 @@ UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height); * 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 isatty() functionality use this function and test for UV_TTY. */ UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); /* - * uv_pipe_t is a subclass of uv_stream_t + * 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. + * Pipe. On Unix this is a Unix domain socket. */ struct uv_pipe_s { UV_HANDLE_FIELDS @@ -1172,17 +1208,17 @@ 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); /* - * Bind the pipe to a file path (UNIX) or a name (Windows.) + * Bind the pipe to a file path (Unix) or a name (Windows). * - * Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, + * Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes, * typically between 92 and 108 bytes. */ UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); /* - * Connect to the UNIX domain socket or the named pipe. + * Connect to the Unix domain socket or the named pipe. * - * Paths on UNIX get truncated to `sizeof(sockaddr_un.sun_path)` bytes, + * Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes, * typically between 92 and 108 bytes. */ UV_EXTERN void uv_pipe_connect(uv_connect_t* req, @@ -1191,12 +1227,12 @@ UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_connect_cb cb); /* - * Get the name of the UNIX domain socket or the named pipe. + * Get the name of the Unix domain socket or the named pipe. * - * A preallocated buffer must be provided. The len 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. + * A preallocated buffer must be provided. The len 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. */ UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, @@ -1204,17 +1240,18 @@ UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, /* * This setting applies to Windows only. - * Set the number of pending pipe instance handles when the pipe server - * is waiting for connections. + * + * Set the number of pending pipe instance handles when the pipe server is + * waiting for connections. */ UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); /* * Used to receive handles over ipc pipes. * - * First - call `uv_pipe_pending_count`, if it is > 0 - initialize handle - * using type, returned by `uv_pipe_pending_type` and call - * `uv_accept(pipe, handle)`. + * First - call uv_pipe_pending_count(), if it is > 0 - initialize handle + * using type, returned by uv_pipe_pending_type() and call + * uv_accept(pipe, handle). */ UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); @@ -1227,10 +1264,10 @@ UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); * * The purpose of uv_poll 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 other purpose is not - * recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is - * much faster and more scalable than what can be achieved with uv_poll_t, - * especially on Windows. + * c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended; + * uv_tcp_t, uv_udp_t, etc. provide an implementation that is much faster and + * more scalable than what can be achieved with uv_poll_t, especially on + * Windows. * * It is possible that uv_poll occasionally signals that a file descriptor is * readable or writable even when it isn't. The user should therefore always @@ -1245,7 +1282,7 @@ UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); * but it might also start polling another socket. However the fd can be safely * closed immediately after a call to uv_poll_stop() or uv_close(). * - * On windows only sockets can be polled with uv_poll. On unix any file + * On windows only sockets can be polled with uv_poll. On Unix any file * descriptor that would be accepted by poll(2) can be used with uv_poll. */ struct uv_poll_s { @@ -1262,8 +1299,10 @@ enum uv_poll_event { /* Initialize the poll watcher using a file descriptor. */ UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); -/* Initialize the poll watcher using a socket descriptor. On unix this is */ -/* identical to uv_poll_init. On windows it takes a SOCKET handle. */ +/* + * Initialize the poll watcher using a socket descriptor. On Unix this is + * identical to uv_poll_init. On windows it takes a SOCKET handle. + */ UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket); @@ -1347,11 +1386,15 @@ UV_EXTERN int uv_idle_stop(uv_idle_t* idle); /* * uv_async_t is a subclass of uv_handle_t. * - * uv_async_send wakes up the event loop and calls the async handle's callback. - * There is no guarantee that every uv_async_send call leads to exactly one - * invocation of the callback; the only guarantee is that the callback function - * is called at least once after the call to async_send. Unlike all other - * libuv functions, uv_async_send can be called from another thread. + * uv_async_send() wakes up the event loop and calls the async handle's callback. + * + * Unlike all other libuv functions, uv_async_send() can be called from another + * thread. + * + * NOTE: + * There is no guarantee that every uv_async_send() call leads to exactly one + * invocation of the callback; the only guarantee is that the callback + * function is called at least once after the call to async_send. */ struct uv_async_s { UV_HANDLE_FIELDS @@ -1420,7 +1463,7 @@ UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); /* - * uv_getaddrinfo_t is a subclass of uv_req_t + * uv_getaddrinfo_t is a subclass of uv_req_t. * * Request object for uv_getaddrinfo. */ @@ -1464,7 +1507,7 @@ UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai); /* -* uv_getnameinfo_t is a subclass of uv_req_t +* uv_getnameinfo_t is a subclass of uv_req_t. * * Request object for uv_getnameinfo. */ @@ -1490,14 +1533,15 @@ UV_EXTERN int uv_getnameinfo(uv_loop_t* loop, int flags); -/* uv_spawn() options */ +/* 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 + /* + * 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. */ @@ -1578,7 +1622,7 @@ enum uv_process_flags { /* * 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. + * only meaningful on Windows systems. On Unix it is silently ignored. */ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), /* @@ -1591,14 +1635,14 @@ enum uv_process_flags { 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 + * 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 + * uv_process_t is a subclass of uv_handle_t. */ struct uv_process_s { UV_HANDLE_FIELDS @@ -1625,7 +1669,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop, /* * Kills the process with the specified signal. The user must still - * call uv_close on the process. + * call uv_close() on the process. * * Emulates some aspects of Unix exit status on Windows, in that while the * underlying process will be terminated with a status of `1`, @@ -1651,7 +1695,7 @@ UV_EXTERN int uv_kill(int pid, int signum); /* - * uv_work_t is a subclass of uv_req_t + * uv_work_t is a subclass of uv_req_t. */ struct uv_work_s { UV_REQ_FIELDS @@ -1686,7 +1730,7 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop, * - A uv_work_t or uv_getaddrinfo_t request has its callback invoked with * status == UV_ECANCELED. * - * This function is currently only implemented on UNIX platforms. On Windows, + * This function is currently only implemented on Unix platforms. On Windows, * it always returns UV_ENOSYS. */ UV_EXTERN int uv_cancel(uv_req_t* req); @@ -1755,15 +1799,15 @@ typedef struct { UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); /* - * This allocates cpu_infos array, and sets count. The array - * is freed using uv_free_cpu_info(). + * This allocates cpu_infos array, and sets count. The array is freed + * using uv_free_cpu_info(). */ 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); /* - * This allocates addresses array, and sets count. The array - * is freed using uv_free_interface_addresses(). + * This allocates addresses array, and sets count. The array is freed + * using uv_free_interface_addresses(). */ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, int* count); @@ -1805,6 +1849,7 @@ typedef enum { UV_FS_UNLINK, UV_FS_RMDIR, UV_FS_MKDIR, + UV_FS_MKDTEMP, UV_FS_RENAME, UV_FS_READDIR, UV_FS_LINK, @@ -1814,7 +1859,7 @@ typedef enum { UV_FS_FCHOWN } uv_fs_type; -/* uv_fs_t is a subclass of uv_req_t */ +/* uv_fs_t is a subclass of uv_req_t. */ struct uv_fs_s { UV_REQ_FIELDS uv_fs_type fs_type; @@ -1823,7 +1868,7 @@ struct uv_fs_s { ssize_t result; void* ptr; const char* path; - uv_stat_t statbuf; /* Stores the result of uv_fs_stat and uv_fs_fstat. */ + uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */ UV_FS_PRIVATE_FIELDS }; @@ -1847,6 +1892,9 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, 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); @@ -1890,14 +1938,14 @@ 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. + * 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. + * 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 @@ -1975,7 +2023,7 @@ UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len); /* - * UNIX signal handling on a per-event loop basis. The implementation is not + * Unix signal handling on a per-event loop basis. The implementation is not * ultra efficient so don't go creating a million event loops with a million * signal watchers. * @@ -2030,14 +2078,16 @@ UV_EXTERN int uv_signal_stop(uv_signal_t* handle); /* * Gets load average. + * * See: http://en.wikipedia.org/wiki/Load_(computing) + * * Returns [0,0,0] on Windows. */ UV_EXTERN void uv_loadavg(double avg[3]); /* - * Flags to be passed to uv_fs_event_start. + * Flags to be passed to uv_fs_event_start(). */ enum uv_fs_event_flags { /* @@ -2088,32 +2138,34 @@ UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle, size_t* len); -/* Utility */ +/* Utilities. */ -/* Convert string ip addresses to binary structures */ +/* Convert string ip addresses to binary structures. */ 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); -/* Convert binary addresses to strings */ +/* Convert binary addresses to strings. */ 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); -/* Cross-platform IPv6-capable implementation of the 'standard' inet_ntop */ -/* and inet_pton functions. On success they return 0. If an error */ -/* the target of the `dst` pointer is unmodified. */ +/* + * Cross-platform IPv6-capable implementation of the 'standard' inet_ntop() and + * inet_pton() functions. On success they return 0. If an error the target of + * the `dst` pointer is unmodified. + */ 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); -/* Gets the executable path */ +/* Gets the executable path. */ UV_EXTERN int uv_exepath(char* buffer, size_t* size); -/* Gets the current working directory */ +/* Gets the current working directory. */ UV_EXTERN int uv_cwd(char* buffer, size_t* size); -/* Changes the current working directory */ +/* Changes the current working directory. */ UV_EXTERN int uv_chdir(const char* dir); -/* Gets memory info in bytes */ +/* Gets memory info in bytes. */ UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); @@ -2139,13 +2191,13 @@ UV_EXTERN extern uint64_t uv_hrtime(void); * * Note that 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. + * it does a better job on Windows than it does on Unix. */ UV_EXTERN void uv_disable_stdio_inheritance(void); /* * Opens a shared library. The filename is in utf-8. Returns 0 on success and - * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message. + * -1 on error. Call uv_dlerror(uv_lib_t*) to get the error message. */ UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); @@ -2166,8 +2218,8 @@ 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); /* - * The mutex functions return 0 on success or an error code < 0 - * (unless the return type is void, of course). + * The mutex functions return 0 on success or an error code < 0 (unless the + * return type is void, of course). */ UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); @@ -2216,31 +2268,35 @@ 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); -/* Waits on a condition variable without a timeout. +/* + * Waits on a condition variable without a timeout. * - * Note: - * 1. callers should be prepared to deal with spurious wakeups. + * NOTE: + * 1. callers should be prepared to deal with spurious wakeups. */ UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex); -/* Waits on a condition variable with a timeout in nano seconds. +/* + * Waits on a condition variable with a timeout in nano seconds. * Returns 0 for success or UV_ETIMEDOUT on timeout, It aborts when other * errors happen. * - * Note: - * 1. callers should be prepared to deal with spurious wakeups. - * 2. the granularity of timeout on Windows is never less than one millisecond. - * 3. uv_cond_timedwait takes a relative timeout, not an absolute time. + * NOTE: + * 1. callers should be prepared to deal with spurious wakeups. + * 2. the granularity of timeout on Windows is never less than one millisecond. + * 3. uv_cond_timedwait() takes a relative timeout, not an absolute time. */ UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout); -/* Runs a function once and only once. Concurrent calls to uv_once() with the +/* + * Runs a function once and only once. Concurrent calls to 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. */ UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void)); -/* Thread-local storage. These functions largely follow the semantics of +/* + * Thread-local storage. These functions largely follow the semantics of * pthread_key_create(), pthread_key_delete(), pthread_getspecific() and * pthread_setspecific(). * @@ -2278,11 +2334,11 @@ union uv_any_req { struct uv_loop_s { /* User data - use this for whatever. */ void* data; - /* Loop reference counting */ + /* Loop reference counting. */ unsigned int active_handles; void* handle_queue[2]; void* active_reqs[2]; - /* Internal flag to signal loop stop */ + /* Internal flag to signal loop stop. */ unsigned int stop_flag; UV_LOOP_PRIVATE_FIELDS }; diff --git a/deps/uv/src/unix/threadpool.c b/deps/uv/src/threadpool.c index 18687249b1..33890f02b5 100644 --- a/deps/uv/src/unix/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -19,7 +19,24 @@ * IN THE SOFTWARE. */ -#include "internal.h" +#include "uv-common.h" + +#if !defined(_WIN32) +# include "unix/internal.h" +#else +# include "win/req-inl.h" +/* TODO(saghul): unify internal req functions */ +static void uv__req_init(uv_loop_t* loop, + uv_req_t* req, + uv_req_type type) { + uv_req_init(loop, req); + req->type = type; + uv__req_register(loop, req); +} +# define uv__req_init(loop, req, type) \ + uv__req_init((loop), (uv_req_t*)(req), (type)) +#endif + #include <stdlib.h> #define MAX_THREADPOOL_SIZE 128 @@ -91,6 +108,32 @@ static void post(QUEUE* q) { } +#ifndef _WIN32 +UV_DESTRUCTOR(static void cleanup(void)) { + unsigned int i; + + if (initialized == 0) + return; + + post(&exit_message); + + for (i = 0; i < nthreads; i++) + if (uv_thread_join(threads + i)) + abort(); + + if (threads != default_threads) + free(threads); + + uv_mutex_destroy(&mutex); + uv_cond_destroy(&cond); + + threads = NULL; + nthreads = 0; + initialized = 0; +} +#endif + + static void init_once(void) { unsigned int i; const char* val; @@ -129,30 +172,6 @@ static void init_once(void) { } -UV_DESTRUCTOR(static void cleanup(void)) { - unsigned int i; - - if (initialized == 0) - return; - - post(&exit_message); - - for (i = 0; i < nthreads; i++) - if (uv_thread_join(threads + i)) - abort(); - - if (threads != default_threads) - free(threads); - - uv_mutex_destroy(&mutex); - uv_cond_destroy(&cond); - - threads = NULL; - nthreads = 0; - initialized = 0; -} - - void uv__work_submit(uv_loop_t* loop, struct uv__work* w, void (*work)(struct uv__work* w), @@ -179,7 +198,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { uv_mutex_unlock(&mutex); if (!cancelled) - return -EBUSY; + return UV_EBUSY; w->work = uv__cancelled; uv_mutex_lock(&loop->wq_mutex); @@ -213,7 +232,7 @@ void uv__work_done(uv_async_t* handle) { QUEUE_REMOVE(q); w = container_of(q, struct uv__work, wq); - err = (w->work == uv__cancelled) ? -ECANCELED : 0; + err = (w->work == uv__cancelled) ? UV_ECANCELED : 0; w->done(w, err); } } @@ -244,7 +263,7 @@ int uv_queue_work(uv_loop_t* loop, uv_work_cb work_cb, uv_after_work_cb after_work_cb) { if (work_cb == NULL) - return -EINVAL; + return UV_EINVAL; uv__req_init(loop, req, UV_WORK); req->loop = loop; @@ -277,7 +296,7 @@ int uv_cancel(uv_req_t* req) { wreq = &((uv_work_t*) req)->work_req; break; default: - return -EINVAL; + return UV_EINVAL; } return uv__work_cancel(loop, req, wreq); diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 2521681305..eb90111345 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -39,12 +39,235 @@ #include <unistd.h> #include <fcntl.h> #include <utmp.h> +#include <libgen.h> #include <sys/protosw.h> #include <libperfstat.h> #include <sys/proc.h> #include <sys/procfs.h> +#include <sys/poll.h> + +#include <sys/pollset.h> +#include <ctype.h> +#include <sys/ahafs_evProds.h> + +#include <sys/mntctl.h> +#include <sys/vmount.h> +#include <limits.h> +#include <strings.h> +#include <sys/vnode.h> + +#define RDWR_BUF_SIZE 4096 +#define EQ(a,b) (strcmp(a,b) == 0) + +int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { + loop->fs_fd = -1; + + /* Passing maxfd of -1 should mean the limit is determined + * by the user's ulimit or the global limit as per the doc */ + loop->backend_fd = pollset_create(-1); + + if (loop->backend_fd == -1) + return -1; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->fs_fd != -1) { + uv__close(loop->fs_fd); + loop->fs_fd = -1; + } + + if (loop->backend_fd != -1) { + pollset_destroy(loop->backend_fd); + loop->backend_fd = -1; + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct pollfd events[1024]; + struct pollfd pqry; + struct pollfd* pe; + struct poll_ctl pc; + QUEUE* q; + uv__io_t* w; + uint64_t base; + uint64_t diff; + int nevents; + int count; + int nfds; + int i; + int rc; + int add_failed; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + pc.events = w->pevents; + pc.fd = w->fd; + + add_failed = 0; + if (w->events == 0) { + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + if (errno != EINVAL) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + /* Check if the fd is already in the pollset */ + pqry.fd = pc.fd; + rc = pollset_query(loop->backend_fd, &pqry); + switch (rc) { + case -1: + assert(0 && "Failed to query pollset for file descriptor"); + abort(); + case 0: + assert(0 && "Pollset does not contain file descriptor"); + abort(); + } + /* If we got here then the pollset already contained the file descriptor even though + * we didn't think it should. This probably shouldn't happen, but we can continue. */ + add_failed = 1; + } + } + if (w->events != 0 || add_failed) { + /* Modify, potentially removing events -- need to delete then add. + * Could maybe mod if we knew for sure no events are removed, but + * content of w->events is handled above as not reliable (falls back) + * so may require a pollset_query() which would have to be pretty cheap + * compared to a PS_DELETE to be worth optimising. Alternatively, could + * lazily remove events, squelching them in the mean time. */ + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to delete file descriptor (pc.fd) from pollset"); + abort(); + } + pc.cmd = PS_ADD; + if (pollset_ctl(loop->backend_fd, &pc, 1)) { + assert(0 && "Failed to add file descriptor (pc.fd) to pollset"); + abort(); + } + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + for (;;) { + nfds = pollset_poll(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + if (nfds == -1) { + if (errno != EINTR) { + abort(); + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + + for (i = 0; i < nfds; i++) { + pe = events + i; + pc.cmd = PS_DELETE; + pc.fd = pe->fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (pc.fd == -1) + continue; + + assert(pc.fd >= 0); + assert((unsigned) pc.fd < loop->nwatchers); + + w = loop->watchers[pc.fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + pollset_ctl(loop->backend_fd, &pc, 1); + continue; + } + + w->cb(loop, w, pe->revents); + nevents++; + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + uint64_t uv__hrtime(uv_clocktype_t type) { uint64_t G = 1000000000; timebasestruct_t t; @@ -58,28 +281,24 @@ uint64_t uv__hrtime(uv_clocktype_t type) { * 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) { ssize_t res; - char pp[64], cwdl[PATH_MAX]; + char cwd[PATH_MAX], cwdl[PATH_MAX]; + char symlink[PATH_MAX], temp_buffer[PATH_MAX]; + char pp[64]; struct psinfo ps; int fd; + char **argv; - if (buffer == NULL) - return (-1); - - if (size == NULL) - return (-1); - - (void) snprintf(pp, sizeof(pp), "/proc/%lu/cwd", (unsigned long) getpid()); - - res = readlink(pp, cwdl, sizeof(cwdl) - 1); - if (res < 0) - return res; + if ((buffer == NULL) || (size == NULL)) + return -EINVAL; - cwdl[res] = '\0'; + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); - (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); fd = open(pp, O_RDONLY); if (fd < 0) return fd; @@ -89,9 +308,163 @@ int uv_exepath(char* buffer, size_t* size) { if (res < 0) return res; - (void) snprintf(buffer, *size, "%s%s", cwdl, ps.pr_fname); - *size = strlen(buffer); - return 0; + if (ps.pr_argv == 0) + return -EINVAL; + + argv = (char **) *((char ***) (intptr_t) ps.pr_argv); + + if ((argv == NULL) || (argv[0] == NULL)) + return -EINVAL; + + /* + * Three possibilities for argv[0]: + * 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 #1, absolute path. */ + if (argv[0][0] == '/') { + snprintf(symlink, PATH_MAX-1, "%s", argv[0]); + + /* This could or could not be a symlink. */ + res = readlink(symlink, temp_buffer, PATH_MAX-1); + + /* if readlink fails, it is a normal file just copy symlink to the + * outbut buffer. + */ + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + + /* If it is a link, the resolved filename is again a relative path, + * make it absolute. + */ + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + + /* case #2, relative path with usage of '.' */ + } else if (argv[0][0] == '.') { + char *relative = strchr(argv[0], '/'); + if (relative == NULL) + return -EINVAL; + + /* Get the current working directory to resolve the relative path. */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + + /* This is always a symlink, resolve it. */ + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, relative + 1); + + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + + /* case #3, relative path without usage of '.', such as invocations in Node test suite. */ + } else if (strchr(argv[0], '/') != NULL) { + /* Get the current working directory to resolve the relative path. */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + + /* This is always a symlink, resolve it. */ + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, argv[0]); + + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + /* Usage of absolute filename with location exported in PATH */ + } else { + char clonedpath[8192]; /* assume 8k buffer will fit PATH */ + char *token = NULL; + struct stat statstruct; + + /* Get the paths. */ + char *path = getenv("PATH"); + if(sizeof(clonedpath) <= strlen(path)) + return -EINVAL; + + /* Get a local copy. */ + strcpy(clonedpath, path); + + /* Tokenize. */ + token = strtok(clonedpath, ":"); + + /* Get current working directory. (may be required in the loop). */ + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, cwdl, sizeof(cwdl) - 1); + if (res < 0) + return -errno; + /* Run through the tokens, append our executable file name with each, + * and see which one succeeds. Exit on first match. */ + while(token != NULL) { + if (token[0] == '.') { + /* Path contains a token relative to current directory. */ + char *relative = strchr(token, '/'); + if (relative != NULL) + /* A path which is not current directory. */ + snprintf(symlink, PATH_MAX-1, "%s%s/%s", cwdl, relative+1, ps.pr_fname); + else + snprintf(symlink, PATH_MAX-1, "%s%s", cwdl, ps.pr_fname); + if (stat(symlink, &statstruct) != -1) { + /* File exists. Resolve if it is a link. */ + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + } + + /* Absolute path names. */ + } else { + snprintf(symlink, PATH_MAX-1, "%s/%s", token, ps.pr_fname); + if (stat(symlink, &statstruct) != -1) { + res = readlink(symlink, temp_buffer, PATH_MAX-1); + if (res < 0) { + assert(*size > strlen(symlink)); + strcpy(buffer, symlink); + } else { + assert(*size > (strlen(symlink) + 1 + strlen(temp_buffer))); + snprintf(buffer, *size-1, "%s/%s", dirname(symlink), temp_buffer); + } + *size = strlen(buffer); + return 0; + } + } + token = strtok(NULL, ":"); + } + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } } @@ -128,8 +501,369 @@ void uv_loadavg(double avg[3]) { } +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 = malloc(siz); + if (p == NULL) + return -errno; + + /* Retrieve all mounted filesystems */ + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + if (rv == 0) { + /* buffer was not large enough, reallocate to correct size */ + siz = *(int*)p; + free(p); + p = malloc(siz); + if (p == NULL) + return -errno; + rv = mntctl(MCTL_QUERY, siz, (char*)p); + if (rv < 0) + return -errno; + } + + /* Look for dev in filesystems mount info */ + for(vmt = p, i = 0; i < rv; i++) { + obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ + stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ + + if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + free(p); /* Found a match */ + return 0; + } + vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length); + } + + /* /aha is required for monitoring filesystem changes */ + return -1; +} + +/* + * Recursive call to mkdir() to create intermediate folders, if any + * Returns code from mkdir call + */ +static int uv__makedir_p(const char *dir) { + char tmp[256]; + char *p = NULL; + size_t len; + int err; + + snprintf(tmp, sizeof(tmp),"%s",dir); + len = strlen(tmp); + if (tmp[len - 1] == '/') + tmp[len - 1] = 0; + for (p = tmp + 1; *p; p++) { + if (*p == '/') { + *p = 0; + err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if(err != 0) + return err; + *p = '/'; + } + } + return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} + +/* + * Creates necessary subdirectories in the AIX Event Infrastructure + * file system for monitoring the object specified. + * Returns code from mkdir call + */ +static int uv__make_subdirs_p(const char *filename) { + char cmd[2048]; + char *p; + int rc = 0; + + /* Strip off the monitor file name */ + p = strrchr(filename, '/'); + + if (p == NULL) + return 0; + + if (uv__path_is_a_directory((char*)filename) == 0) { + sprintf(cmd, "/aha/fs/modDir.monFactory"); + } else { + sprintf(cmd, "/aha/fs/modFile.monFactory"); + } + + strncat(cmd, filename, (p - filename)); + rc = uv__makedir_p(cmd); + + if (rc == -1 && errno != EEXIST){ + return -errno; + } + + return rc; +} + + +/* + * Checks if /aha is mounted, then proceeds to set up the monitoring + * objects for the specified file. + * Returns 0 on success, or an error code < 0 on failure + */ +static int uv__setup_ahafs(const char* filename, int *fd) { + int rc = 0; + char mon_file_write_string[RDWR_BUF_SIZE]; + char mon_file[PATH_MAX]; + int file_is_directory = 0; /* -1 == NO, 0 == YES */ + + /* Create monitor file name for object */ + file_is_directory = uv__path_is_a_directory((char*)filename); + + if (file_is_directory == 0) + sprintf(mon_file, "/aha/fs/modDir.monFactory"); + else + sprintf(mon_file, "/aha/fs/modFile.monFactory"); + + if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) + return -ENAMETOOLONG; + + /* Make the necessary subdirectories for the monitor file */ + rc = uv__make_subdirs_p(filename); + if (rc == -1 && errno != EEXIST) + return rc; + + strcat(mon_file, filename); + strcat(mon_file, ".mon"); + + *fd = 0; errno = 0; + + /* Open the monitor file, creating it if necessary */ + *fd = open(mon_file, O_CREAT|O_RDWR); + if (*fd < 0) + return -errno; + + /* Write out the monitoring specifications. + * In this case, we are monitoring for a state change event type + * CHANGED=YES + * We will be waiting in select call, rather than a read: + * WAIT_TYPE=WAIT_IN_SELECT + * We only want minimal information for files: + * INFO_LVL=1 + * For directories, we want more information to track what file + * caused the change + * INFO_LVL=2 + */ + + if (file_is_directory == 0) + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2"); + else + sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); + + rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); + if (rc < 0) + return -errno; + + return 0; +} + +/* + * Skips a specified number of lines in the buffer passed in. + * Walks the buffer pointed to by p and attempts to skip n lines. + * Returns the total number of lines skipped + */ +static int uv__skip_lines(char **p, int n) { + int lines = 0; + + while(n > 0) { + *p = strchr(*p, '\n'); + if (!p) + return lines; + + (*p)++; + n--; + lines++; + } + return lines; +} + + +/* + * Parse the event occurrence data to figure out what event just occurred + * and take proper action. + * + * The buf is a pointer to the buffer containing the event occurrence data + * Returns 0 on success, -1 if unrecoverable error in parsing + * + */ +static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) { + int evp_rc, i; + char *p; + char filename[PATH_MAX]; /* To be used when handling directories */ + + p = buf; + *events = 0; + + /* Clean the filename buffer*/ + for(i = 0; i < PATH_MAX; i++) { + filename[i] = 0; + } + i = 0; + + /* Check for BUF_WRAP */ + if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) { + assert(0 && "Buffer wrap detected, Some event occurrences lost!"); + return 0; + } + + /* Since we are using the default buffer size (4K), and have specified + * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications + * should check for this keyword if they are using an INFO_LVL of 2 or + * higher, and have a buffer size of <= 4K + */ + + /* Skip to RC_FROM_EVPROD */ + if (uv__skip_lines(&p, 9) != 9) + return -1; + + if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) { + if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */ + if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) { + /* The directory is no longer available for monitoring */ + *events = UV_RENAME; + handle->dir_filename = NULL; + } else { + /* A file was added/removed inside the directory */ + *events = UV_CHANGE; + + /* Get the EVPROD_INFO */ + if (uv__skip_lines(&p, 1) != 1) + return -1; + + /* Scan out the name of the file that triggered the event*/ + if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) { + handle->dir_filename = strdup((const char*)&filename); + } else + return -1; + } + } else { /* Regular File */ + if (evp_rc == AHAFS_MODFILE_RENAME) + *events = UV_RENAME; + else + *events = UV_CHANGE; + } + } + else + return -1; + + return 0; +} + + +/* This is the internal callback */ +static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { + char result_data[RDWR_BUF_SIZE]; + int bytes, rc = 0; + uv_fs_event_t* handle; + int events = 0; + int i = 0; + char fname[PATH_MAX]; + char *p; + + handle = container_of(event_watch, uv_fs_event_t, event_watcher); + + /* Clean all the buffers*/ + for(i = 0; i < PATH_MAX; i++) { + fname[i] = 0; + } + i = 0; + + /* At this point, we assume that polling has been done on the + * file descriptor, so we can just read the AHAFS event occurrence + * data and parse its results without having to block anything + */ + bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); + + assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file"); + + /* Parse the data */ + if(bytes > 0) + rc = uv__parse_data(result_data, &events, handle); + + /* For directory changes, the name of the files that triggered the change + * are never absolute pathnames + */ + if (uv__path_is_a_directory(handle->path) == 0) { + p = handle->dir_filename; + while(*p != NULL){ + fname[i]= *p; + i++; + p++; + } + } else { + /* For file changes, figure out whether filename is absolute or not */ + if (handle->path[0] == '/') { + p = strrchr(handle->path, '/'); + p++; + + while(*p != NULL) { + fname[i]= *p; + i++; + p++; + } + } + } + + /* Unrecoverable error */ + if (rc == -1) + return; + else /* Call the actual JavaScript callback function */ + handle->cb(handle, (const char*)&fname, events, 0); +} + + int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; } @@ -137,17 +871,99 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + int fd, rc, i = 0, res = 0; + char cwd[PATH_MAX]; + char absolute_path[PATH_MAX]; + char fname[PATH_MAX]; + char *p; + + /* Clean all the buffers*/ + for(i = 0; i < PATH_MAX; i++) { + cwd[i] = 0; + absolute_path[i] = 0; + fname[i] = 0; + } + i = 0; + + /* Figure out whether filename is absolute or not */ + if (filename[0] == '/') { + /* We have absolute pathname, create the relative pathname*/ + sprintf(absolute_path, filename); + p = strrchr(filename, '/'); + p++; + } else { + if (filename[0] == '.' && filename[1] == '/') { + /* We have a relative pathname, compose the absolute pathname */ + sprintf(fname, filename); + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); + if (res < 0) + return res; + p = strrchr(absolute_path, '/'); + p++; + p++; + } else { + /* We have a relative pathname, compose the absolute pathname */ + sprintf(fname, filename); + snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); + res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); + if (res < 0) + return res; + p = strrchr(absolute_path, '/'); + p++; + } + /* Copy to filename buffer */ + while(filename[i] != NULL) { + *p = filename[i]; + i++; + p++; + } + } + + if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ + return UV_ENOSYS; + + /* Setup ahafs */ + rc = uv__setup_ahafs((const char *)absolute_path, &fd); + if (rc != 0) + return rc; + + /* Setup/Initialize all the libuv routines */ + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); + handle->path = strdup((const char*)&absolute_path); + handle->cb = cb; + + uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + + return 0; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + + 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) { + free(handle->dir_filename); + handle->dir_filename = NULL; + } + + free(handle->path); + handle->path = NULL; + uv__close(handle->event_watcher.fd); + handle->event_watcher.fd = -1; + + return 0; } void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); + uv_fs_event_stop(handle); } @@ -175,7 +991,7 @@ int uv_resident_set_memory(size_t* rss) { int err; int fd; - (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); + snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); fd = open(pp, O_RDONLY); if (fd == -1) @@ -397,3 +1213,21 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, free(addresses); } + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct pollfd* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + + events = (struct pollfd*) 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].fd == fd) + events[i].fd = -1; +} diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 402bb00eb2..4770d8d8c6 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -70,6 +70,10 @@ # endif #endif +#ifdef _AIX +#include <sys/ioctl.h> +#endif + static void uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -444,7 +448,8 @@ int uv__close(int fd) { } -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(_AIX) int uv__nonblock(int fd, int set) { int r; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 8a4edcbc0a..47f667229d 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -214,9 +214,23 @@ skip: } +static ssize_t uv__fs_mkdtemp(uv_fs_t* req) { + return mkdtemp((char*) req->path) ? 0 : -1; +} + + static ssize_t uv__fs_read(uv_fs_t* req) { 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); @@ -683,7 +697,8 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec; dst->st_flags = src->st_flags; dst->st_gen = src->st_gen; -#elif defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) +#elif !defined(_AIX) && \ + (defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_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; @@ -779,6 +794,7 @@ static void uv__fs_work(struct uv__work* w) { 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(READ, uv__fs_read(req)); X(READDIR, uv__fs_readdir(req)); X(READLINK, uv__fs_readlink(req)); @@ -991,6 +1007,18 @@ int uv_fs_mkdir(uv_loop_t* loop, } +int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb) { + INIT(MKDTEMP); + req->path = strdup(tpl); + if (req->path == NULL) + return -ENOMEM; + POST; +} + + int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index fd29b88d42..114cb696ee 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -42,6 +42,12 @@ # include <port.h> #endif /* __sun */ +#if defined(_AIX) +#define reqevents events +#define rtnevents revents +#include <sys/poll.h> +#endif /* _AIX */ + #if defined(__APPLE__) && !TARGET_OS_IPHONE # include <CoreServices/CoreServices.h> #endif @@ -89,7 +95,7 @@ # define UV__POLLHUP UV__EPOLLHUP #endif -#if defined(__sun) +#if defined(__sun) || defined(_AIX) # define UV__POLLIN POLLIN # define UV__POLLOUT POLLOUT # define UV__POLLERR POLLERR @@ -210,13 +216,6 @@ void uv__signal_close(uv_signal_t* handle); void uv__signal_global_once_init(void); void uv__signal_loop_cleanup(uv_loop_t* loop); -/* thread pool */ -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); - /* platform specific */ uint64_t uv__hrtime(uv_clocktype_t type); int uv__kqueue_init(uv_loop_t* loop); diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 52c9328e75..aa74be6455 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -89,8 +89,10 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { uv_loop_t* default_loop; + int err; default_loop = default_loop_ptr; - assert(uv_loop_close(loop) == 0); + err = uv_loop_close(loop); + assert(err == 0); if (loop != default_loop) free(loop); } diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 75ba921637..cde8d4d0c9 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -180,29 +180,23 @@ int uv_get_process_title(char* buffer, size_t size) { int uv_resident_set_memory(size_t* rss) { - kvm_t *kd = NULL; - struct kinfo_proc *kinfo = NULL; - pid_t pid; - int nprocs, max_size = sizeof(struct kinfo_proc); + struct kinfo_proc kinfo; size_t page_size = getpagesize(); + size_t size = sizeof(struct kinfo_proc); + int mib[6]; - pid = getpid(); + 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; - kd = kvm_open(NULL, _PATH_MEM, NULL, O_RDONLY, "kvm_open"); - if (kd == NULL) goto error; - - kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, max_size, &nprocs); - if (kinfo == NULL) goto error; - - *rss = kinfo->p_vm_rssize * page_size; - - kvm_close(kd); + if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0) + return -errno; + *rss = kinfo.p_vm_rssize * page_size; return 0; - -error: - if (kd) kvm_close(kd); - return -EPERM; } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 43334f0efb..ae7880c33f 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -60,21 +60,10 @@ 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); -static 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 += bufs[i].len; - - return bytes; -} - - void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, uv_handle_type type) { @@ -390,33 +379,12 @@ void uv__stream_destroy(uv_stream_t* stream) { QUEUE_REMOVE(q); req = QUEUE_DATA(q, uv_write_t, queue); - uv__req_unregister(stream->loop, req); + req->error = -ECANCELED; - if (req->bufs != req->bufsml) - free(req->bufs); - req->bufs = NULL; - - if (req->cb != NULL) - req->cb(req, -ECANCELED); + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); } - while (!QUEUE_EMPTY(&stream->write_completed_queue)) { - q = QUEUE_HEAD(&stream->write_completed_queue); - QUEUE_REMOVE(q); - - req = QUEUE_DATA(q, uv_write_t, queue); - uv__req_unregister(stream->loop, req); - - if (req->bufs != NULL) { - stream->write_queue_size -= uv__write_req_size(req); - if (req->bufs != req->bufsml) - free(req->bufs); - req->bufs = NULL; - } - - if (req->cb) - req->cb(req, req->error); - } + uv__write_callbacks(stream); if (stream->shutdown_req) { /* The ECANCELED error code is a lie, the shutdown(2) syscall is a @@ -428,6 +396,8 @@ void uv__stream_destroy(uv_stream_t* stream) { stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); stream->shutdown_req = NULL; } + + assert(stream->write_queue_size == 0); } @@ -660,8 +630,8 @@ 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); + size = uv__count_bufs(req->bufs + req->write_index, + req->nbufs - req->write_index); assert(req->handle->write_queue_size >= size); return size; @@ -903,10 +873,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { } assert(QUEUE_EMPTY(&stream->write_completed_queue)); - - /* Write queue drained. */ - if (QUEUE_EMPTY(&stream->write_queue)) - uv__drain(stream); } @@ -1223,6 +1189,10 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { uv__write(stream); uv__write_callbacks(stream); + + /* Write queue drained. */ + if (QUEUE_EMPTY(&stream->write_queue)) + uv__drain(stream); } } @@ -1327,7 +1297,7 @@ int uv_write2(uv_write_t* req, memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); req->nbufs = nbufs; req->write_index = 0; - stream->write_queue_size += uv_count_bufs(bufs, nbufs); + stream->write_queue_size += uv__count_bufs(bufs, nbufs); /* Append the request to write_queue. */ QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); @@ -1386,7 +1356,7 @@ int uv_try_write(uv_stream_t* stream, /* Connecting or already writing some data */ if (stream->connect_req != NULL || stream->write_queue_size != 0) - return 0; + return -EAGAIN; has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); @@ -1395,7 +1365,7 @@ int uv_try_write(uv_stream_t* stream, return r; /* Remove not written bytes from write queue size */ - written = uv_count_bufs(bufs, nbufs); + written = uv__count_bufs(bufs, nbufs); if (req.bufs != NULL) req_size = uv__write_req_size(&req); else @@ -1416,7 +1386,10 @@ int uv_try_write(uv_stream_t* stream, uv__stream_osx_interrupt_select(stream); } - return (int) written; + if (written == 0) + return -EAGAIN; + else + return written; } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 9556bd7e3b..bf91cbdf9f 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -38,10 +38,9 @@ static void uv__udp_run_completed(uv_udp_t* handle); -static void uv__udp_run_pending(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_loop_t* loop, uv__io_t* w, unsigned int revents); -static void uv__udp_sendmsg(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); @@ -65,22 +64,19 @@ void uv__udp_finish_close(uv_udp_t* handle) { assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); assert(handle->io_watcher.fd == -1); - uv__udp_run_completed(handle); - while (!QUEUE_EMPTY(&handle->write_queue)) { q = QUEUE_HEAD(&handle->write_queue); QUEUE_REMOVE(q); req = QUEUE_DATA(q, uv_udp_send_t, queue); - uv__req_unregister(handle->loop, req); + req->status = -ECANCELED; + QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + } - if (req->bufs != req->bufsml) - free(req->bufs); - req->bufs = NULL; + uv__udp_run_completed(handle); - if (req->send_cb != NULL) - req->send_cb(req, -ECANCELED); - } + assert(handle->send_queue_size == 0); + assert(handle->send_queue_count == 0); /* Now tear down the handle. */ handle->recv_cb = NULL; @@ -89,50 +85,6 @@ void uv__udp_finish_close(uv_udp_t* handle) { } -static void uv__udp_run_pending(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.sin6_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); - - /* TODO try to write once or twice more in the - * hope that the socket becomes readable again? - */ - if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - break; - - req->status = (size == -1 ? -errno : size); - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - QUEUE_REMOVE(&req->queue); - QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); - } -} - - static void uv__udp_run_completed(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; @@ -144,6 +96,9 @@ static void uv__udp_run_completed(uv_udp_t* handle) { 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) free(req->bufs); req->bufs = NULL; @@ -159,33 +114,40 @@ static void uv__udp_run_completed(uv_udp_t* handle) { else req->send_cb(req, req->status); } + + if (QUEUE_EMPTY(&handle->write_queue)) { + /* Pending queue and completion queue empty, stop watcher. */ + uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT); + if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) + uv__handle_stop(handle); + } } static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { + uv_udp_t* handle; + + handle = container_of(w, uv_udp_t, io_watcher); + assert(handle->type == UV_UDP); + if (revents & UV__POLLIN) - uv__udp_recvmsg(loop, w, revents); + uv__udp_recvmsg(handle); - if (revents & UV__POLLOUT) - uv__udp_sendmsg(loop, w, revents); + if (revents & UV__POLLOUT) { + uv__udp_sendmsg(handle); + uv__udp_run_completed(handle); + } } -static void uv__udp_recvmsg(uv_loop_t* loop, - uv__io_t* w, - unsigned int revents) { +static void uv__udp_recvmsg(uv_udp_t* handle) { struct sockaddr_storage peer; struct msghdr h; - uv_udp_t* handle; ssize_t nread; uv_buf_t buf; int flags; int count; - handle = container_of(w, uv_udp_t, io_watcher); - assert(handle->type == UV_UDP); - assert(revents & UV__POLLIN); - assert(handle->recv_cb != NULL); assert(handle->alloc_cb != NULL); @@ -242,34 +204,43 @@ static void uv__udp_recvmsg(uv_loop_t* loop, } -static void uv__udp_sendmsg(uv_loop_t* loop, - uv__io_t* w, - unsigned int revents) { - uv_udp_t* handle; +static void uv__udp_sendmsg(uv_udp_t* handle) { + uv_udp_send_t* req; + QUEUE* q; + struct msghdr h; + ssize_t size; - handle = container_of(w, uv_udp_t, io_watcher); - assert(handle->type == UV_UDP); - assert(revents & UV__POLLOUT); + 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); - assert(!QUEUE_EMPTY(&handle->write_queue) - || !QUEUE_EMPTY(&handle->write_completed_queue)); + 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; - /* Write out pending data first. */ - uv__udp_run_pending(handle); + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); - /* Drain 'request completed' queue. */ - uv__udp_run_completed(handle); + if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + break; - if (!QUEUE_EMPTY(&handle->write_completed_queue)) { - /* Schedule completion callbacks. */ - uv__io_feed(handle->loop, &handle->io_watcher); - } - else if (QUEUE_EMPTY(&handle->write_queue)) { - /* Pending queue and completion queue empty, stop watcher. */ - uv__io_stop(loop, &handle->io_watcher, UV__POLLOUT); + req->status = (size == -1 ? -errno : size); - if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) - uv__handle_stop(handle); + /* 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); } } @@ -410,6 +381,7 @@ int uv__udp_send(uv_udp_send_t* req, unsigned int addrlen, uv_udp_send_cb send_cb) { int err; + int empty_queue; assert(nbufs > 0); @@ -417,8 +389,13 @@ int uv__udp_send(uv_udp_send_t* req, if (err) return err; - uv__req_init(handle->loop, req, UV_UDP_SEND); + /* 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; @@ -433,14 +410,60 @@ int uv__udp_send(uv_udp_send_t* req, return -ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); + handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); + handle->send_queue_count++; QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); uv__handle_start(handle); + if (empty_queue) + uv__udp_sendmsg(handle); + else + uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + return 0; } +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + int err; + struct msghdr h; + ssize_t size; + + assert(nbufs > 0); + + /* already sending a message */ + if (handle->send_queue_count != 0) + return -EAGAIN; + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + memset(&h, 0, sizeof h); + h.msg_name = (struct sockaddr*) addr; + h.msg_namelen = addrlen; + h.msg_iov = (struct iovec*) bufs; + h.msg_iovlen = nbufs; + + do { + size = sendmsg(handle->io_watcher.fd, &h, 0); + } while (size == -1 && errno == EINTR); + + if (size == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return -EAGAIN; + else + return -errno; + } + + return size; +} + + static int uv__udp_set_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, const char* interface_addr, @@ -531,6 +554,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { 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, -1); QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_completed_queue); @@ -579,7 +604,7 @@ int uv_udp_set_membership(uv_udp_t* handle, static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) { -#if defined(__sun) +#if defined(__sun) || defined(_AIX) char arg = val; #else int arg = val; @@ -678,7 +703,9 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) } -int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) { +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { socklen_t socklen; if (handle->io_watcher.fd == -1) diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index d9553c9162..4e3968cb44 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -233,6 +233,26 @@ int uv_udp_send(uv_udp_send_t* req, } +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) { @@ -446,6 +466,19 @@ int uv__getaddrinfo_translate_error(int sys_err) { return 0; /* Pacify compiler. */ } + +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_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) { size_t required_len; diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 3bcdcef3d4..34c287898c 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -83,6 +83,12 @@ int uv__udp_send(uv_udp_send_t* req, 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); @@ -92,6 +98,15 @@ 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); + #define uv__has_active_reqs(loop) \ (QUEUE_EMPTY(&(loop)->active_reqs) == 0) diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 540fb5fa0d..c39597561d 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -26,7 +26,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#if !defined(__MINGW32__) +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) #include <crtdbg.h> #endif @@ -44,19 +44,21 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT; -#if defined(_DEBUG) && !defined(__MINGW32__) -/* Our crt debug report handler allows us to temporarily disable asserts */ -/* just for the current thread. */ +#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. + */ -__declspec( thread ) int uv__crt_assert_enabled = TRUE; +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. */ + /* Set ret_val to 0 to continue with normal execution. + * Set ret_val to 1 to trigger a breakpoint. + */ if(IsDebuggerPresent()) *ret_val = 1; @@ -67,6 +69,8 @@ static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_v /* Don't call _CrtDbgReport. */ return TRUE; } +#else +UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE; #endif @@ -84,21 +88,24 @@ static void uv_init(void) { 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. */ + /* 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(__MINGW32__) + /* We also need to setup our debug report handler because some CRT + * functions (eg _get_osfhandle) raise an assert when called with invalid + * FDs even though they return the proper error code in the release build. + */ +#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) _CrtSetReportHook(uv__crt_dbg_report_handler); #endif - /* Fetch winapi function pointers. This must be done first because other */ - /* intialization code might need these function pointers to be loaded. */ + /* Fetch winapi function pointers. This must be done first because other + * intialization code might need these function pointers to be loaded. + */ uv_winapi_init(); /* Initialize winsock */ @@ -127,12 +134,14 @@ int uv_loop_init(uv_loop_t* loop) { if (loop->iocp == NULL) return uv_translate_sys_error(GetLastError()); - /* To prevent uninitialized memory access, loop->time must be intialized */ - /* to zero before calling uv_update_time for the first time. */ + /* To prevent uninitialized memory access, loop->time must be intialized + * to zero before calling uv_update_time for the first time. + */ loop->time = 0; loop->last_tick_count = 0; uv_update_time(loop); + QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); QUEUE_INIT(&loop->active_reqs); loop->active_handles = 0; @@ -159,6 +168,15 @@ int uv_loop_init(uv_loop_t* loop) { loop->timer_counter = 0; loop->stop_flag = 0; + if (uv_mutex_init(&loop->wq_mutex)) + abort(); + + if (uv_async_init(loop, &loop->wq_async, uv__work_done)) + abort(); + + uv__handle_unref(&loop->wq_async); + loop->wq_async.flags |= UV__HANDLE_INTERNAL; + return 0; } @@ -183,6 +201,31 @@ uv_loop_t* uv_default_loop(void) { } +static void uv__loop_close(uv_loop_t* loop) { + /* close the async handle without needeing 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); + + if (loop != &uv_default_loop_) { + size_t i; + 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); + } + } + /* TODO: cleanup default loop*/ + + 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); +} + + int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; @@ -193,15 +236,13 @@ int uv_loop_close(uv_loop_t* loop) { if (!(h->flags & UV__HANDLE_INTERNAL)) return UV_EBUSY; } - if (loop != &uv_default_loop_) { - size_t i; - 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); - } - } - /* TODO: cleanup default loop*/ + + uv__loop_close(loop); + +#ifndef NDEBUG + memset(loop, -1, sizeof(*loop)); +#endif + return 0; } @@ -224,7 +265,8 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { - assert(uv_loop_close(loop) == 0); + int err = uv_loop_close(loop); + assert(err == 0); if (loop != &uv_default_loop_) free(loop); } @@ -236,22 +278,31 @@ int uv_backend_fd(const uv_loop_t* loop) { int uv_backend_timeout(const uv_loop_t* loop) { - return 0; + 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, int block) { - DWORD bytes, timeout; +static void uv_poll(uv_loop_t* loop, DWORD timeout) { + DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; - if (block) { - timeout = uv_get_poll_timeout(loop); - } else { - timeout = 0; - } - GetQueuedCompletionStatus(loop->iocp, &bytes, &key, @@ -266,28 +317,22 @@ static void uv_poll(uv_loop_t* loop, int block) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); } else { - /* We're sure that at least `timeout` milliseconds have expired, but */ - /* this may not be reflected yet in the GetTickCount() return value. */ - /* Therefore we ensure it's taken into account here. */ + /* We're sure that at least `timeout` milliseconds have expired, but + * this may not be reflected yet in the GetTickCount() return value. + * Therefore we ensure it's taken into account here. + */ uv__time_forward(loop, timeout); } } -static void uv_poll_ex(uv_loop_t* loop, int block) { +static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { BOOL success; - DWORD timeout; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; - if (block) { - timeout = uv_get_poll_timeout(loop); - } else { - timeout = 0; - } - success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), @@ -305,9 +350,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } else if (timeout > 0) { - /* We're sure that at least `timeout` milliseconds have expired, but */ - /* this may not be reflected yet in the GetTickCount() return value. */ - /* Therefore we ensure it's taken into account here. */ + /* We're sure that at least `timeout` milliseconds have expired, but + * this may not be reflected yet in the GetTickCount() return value. + * Therefore we ensure it's taken into account here. + */ uv__time_forward(loop, timeout); } } @@ -326,8 +372,9 @@ int uv_loop_alive(const uv_loop_t* loop) { int uv_run(uv_loop_t *loop, uv_run_mode mode) { + DWORD timeout; int r; - void (*poll)(uv_loop_t* loop, int block); + void (*poll)(uv_loop_t* loop, DWORD timeout); if (pGetQueuedCompletionStatusEx) poll = &uv_poll_ex; @@ -346,13 +393,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv_idle_invoke(loop); uv_prepare_invoke(loop); - (*poll)(loop, loop->idle_handles == NULL && - loop->pending_reqs_tail == NULL && - loop->endgame_handles == NULL && - !loop->stop_flag && - (loop->active_handles > 0 || - !QUEUE_EMPTY(&loop->active_reqs)) && - !(mode & UV_RUN_NOWAIT)); + timeout = 0; + if ((mode & UV_RUN_NOWAIT) == 0) + timeout = uv_backend_timeout(loop); + + (*poll)(loop, timeout); uv_check_invoke(loop); uv_process_endgames(loop); diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 3162bc787f..5c5514736e 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -133,6 +133,7 @@ int uv_translate_sys_error(int sys_errno) { 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; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index f31c0a2999..8b52e610f4 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -44,12 +44,8 @@ #define QUEUE_FS_TP_JOB(loop, req) \ do { \ - if (!QueueUserWorkItem(&uv_fs_thread_proc, \ - req, \ - WT_EXECUTEDEFAULT)) { \ - return uv_translate_sys_error(GetLastError()); \ - } \ uv__req_register(loop, req); \ + uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ } while (0) #define SET_REQ_RESULT(req, result_value) \ @@ -232,11 +228,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, req->result = 0; req->ptr = NULL; req->path = NULL; - - if (cb != NULL) { - req->cb = cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); - } + req->cb = cb; } @@ -729,6 +721,78 @@ void fs__mkdir(uv_fs_t* req) { } +/* Some parts of the implementation were borrowed from glibc. */ +void fs__mkdtemp(uv_fs_t* req) { + static const WCHAR letters[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + size_t len; + WCHAR* template_part; + static uint64_t value; + unsigned int count; + int fd; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to + give the system administrator the chance to remove the problems. */ +#define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To + conform to POSIX, this must be no smaller than TMP_MAX. */ +#if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; +#else + unsigned int attempts = ATTEMPTS_MIN; +#endif + + len = wcslen(req->pathw); + if (len < 6 || wcsncmp(&req->pathw[len - 6], L"XXXXXX", 6)) { + SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); + return; + } + + /* This is where the Xs start. */ + template_part = &req->pathw[len - 6]; + + /* Get some random data. */ + value += uv_hrtime() ^ _getpid(); + + for (count = 0; count < attempts; value += 7777, ++count) { + uint64_t v = value; + + /* Fill in the random bits. */ + template_part[0] = letters[v % 62]; + v /= 62; + template_part[1] = letters[v % 62]; + v /= 62; + template_part[2] = letters[v % 62]; + v /= 62; + template_part[3] = letters[v % 62]; + v /= 62; + template_part[4] = letters[v % 62]; + v /= 62; + template_part[5] = letters[v % 62]; + + fd = _wmkdir(req->pathw); + + if (fd >= 0) { + len = strlen(req->path); + wcstombs((char*) req->path + len - 6, template_part, 6); + SET_REQ_RESULT(req, 0); + return; + } else if (errno != EEXIST) { + SET_REQ_RESULT(req, -1); + return; + } + } + + /* We got out of the loop because we ran out of combinations to try. */ + SET_REQ_RESULT(req, -1); +} + + void fs__readdir(uv_fs_t* req) { WCHAR* pathw = req->pathw; size_t len = wcslen(pathw); @@ -1401,7 +1465,7 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, /* Open the directory */ handle = CreateFileW(new_path, - GENERIC_ALL, + GENERIC_WRITE, 0, NULL, OPEN_EXISTING, @@ -1510,11 +1574,10 @@ static void fs__fchown(uv_fs_t* req) { } -static DWORD WINAPI uv_fs_thread_proc(void* parameter) { - uv_fs_t* req = (uv_fs_t*) parameter; - uv_loop_t* loop = req->loop; +static void uv__fs_work(struct uv__work* w) { + uv_fs_t* req; - assert(req != NULL); + 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; @@ -1537,6 +1600,7 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { XX(UNLINK, unlink) XX(RMDIR, rmdir) XX(MKDIR, mkdir) + XX(MKDTEMP, mkdtemp) XX(RENAME, rename) XX(READDIR, readdir) XX(LINK, link) @@ -1547,9 +1611,41 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { default: assert(!"bad uv_fs_type"); } +} - POST_COMPLETION_FOR_REQ(loop, req); - return 0; + +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; + } + + if (req->cb != NULL) + req->cb(req); +} + + +void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->flags & UV_FS_CLEANEDUP) + return; + + if (req->flags & UV_FS_FREE_PATHS) + free(req->pathw); + + if (req->flags & UV_FS_FREE_PTR) + free(req->ptr); + + req->path = NULL; + req->pathw = NULL; + req->new_pathw = NULL; + req->ptr = NULL; + + req->flags |= UV_FS_CLEANEDUP; } @@ -1701,6 +1797,26 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, } +int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, + uv_fs_cb cb) { + int err; + + uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb); + + err = fs__capture_path(loop, req, tpl, NULL, TRUE); + if (err) + return uv_translate_sys_error(err); + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__mkdtemp(req); + return req->result; + } +} + + int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; @@ -2064,30 +2180,3 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, return req->result; } } - - -void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { - assert(req->cb); - uv__req_unregister(loop, req); - req->cb(req); -} - - -void uv_fs_req_cleanup(uv_fs_t* req) { - if (req->flags & UV_FS_CLEANEDUP) - return; - - if (req->flags & UV_FS_FREE_PATHS) - free(req->pathw); - - if (req->flags & UV_FS_FREE_PTR) - free(req->ptr); - - req->path = NULL; - req->pathw = NULL; - req->new_pathw = NULL; - req->ptr = NULL; - - req->flags |= UV_FS_CLEANEDUP; -} - diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index b87a933f0f..086200a9ea 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -56,25 +56,13 @@ #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) -/* getaddrinfo worker thread implementation */ -static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { - uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; - uv_loop_t* loop = req->loop; - int ret; - - assert(req != NULL); - - /* call OS function on this thread */ - ret = GetAddrInfoW(req->node, - req->service, - req->hints, - &req->res); - req->retcode = ret; - - /* post getaddrinfo completed */ - POST_COMPLETION_FOR_REQ(loop, req); +static void uv__getaddrinfo_work(struct uv__work* w) { + uv_getaddrinfo_t* req; + int err; - return 0; + req = container_of(w, uv_getaddrinfo_t, work_req); + err = GetAddrInfoW(req->node, req->service, req->hints, &req->res); + req->retcode = uv__getaddrinfo_translate_error(err); } @@ -87,7 +75,8 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { +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)); @@ -95,7 +84,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { struct addrinfo* addrinfo_ptr; char* alloc_ptr = NULL; char* cur_ptr = NULL; - int err = 0; + + req = container_of(w, uv_getaddrinfo_t, work_req); /* release input parameter memory */ if (req->alloc != NULL) { @@ -103,6 +93,16 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { req->alloc = NULL; } + if (status == UV_ECANCELED) { + assert(req->retcode == 0); + req->retcode = UV_EAI_CANCELED; + if (req->res != NULL) { + FreeAddrInfoW(req->res); + req->res = NULL; + } + goto complete; + } + if (req->retcode == 0) { /* convert addrinfoW to addrinfo */ /* first calculate required length */ @@ -113,7 +113,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { if (addrinfow_ptr->ai_canonname != NULL) { name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); if (name_len == 0) { - err = uv_translate_sys_error(GetLastError()); + req->retcode = uv_translate_sys_error(GetLastError()); goto complete; } addrinfo_len += ALIGNED_SIZE(name_len); @@ -178,11 +178,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { } } } else { - err = UV_EAI_MEMORY; + req->retcode = UV_EAI_MEMORY; } - } else { - /* GetAddrInfo failed */ - err = uv__getaddrinfo_translate_error(req->retcode); } /* return memory to system */ @@ -192,10 +189,10 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { } complete: - uv__req_unregister(loop, req); + uv__req_unregister(req->loop, req); /* finally do callback with converted result */ - req->getaddrinfo_cb(req, err, (struct addrinfo*)alloc_ptr); + req->getaddrinfo_cb(req, req->retcode, (struct addrinfo*)alloc_ptr); } @@ -246,6 +243,7 @@ int uv_getaddrinfo(uv_loop_t* loop, req->res = NULL; req->type = UV_GETADDRINFO; req->loop = loop; + req->retcode = 0; /* calculate required memory size for all input values */ if (node != NULL) { @@ -323,13 +321,10 @@ int uv_getaddrinfo(uv_loop_t* loop, req->hints = NULL; } - /* Ask thread to run. Treat this as a long operation */ - if (QueueUserWorkItem(&getaddrinfo_thread_proc, - req, - WT_EXECUTELONGFUNCTION) == 0) { - err = GetLastError(); - goto error; - } + uv__work_submit(loop, + &req->work_req, + uv__getaddrinfo_work, + uv__getaddrinfo_done); uv__req_register(loop, req); diff --git a/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c index 48eb16d8ca..45608dae85 100644 --- a/deps/uv/src/win/getnameinfo.c +++ b/deps/uv/src/win/getnameinfo.c @@ -27,23 +27,31 @@ #include "internal.h" #include "req-inl.h" - -/* getnameinfo worker thread implementation */ -static DWORD WINAPI getnameinfo_thread_proc(void* parameter) { - uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter; - uv_loop_t* loop = req->loop; +#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; - assert(req != NULL); - + req = container_of(w, uv_getnameinfo_t, work_req); ret = GetNameInfoW((struct sockaddr*)&req->storage, sizeof(req->storage), host, - sizeof(host), + ARRAY_SIZE(host), service, - sizeof(service), + ARRAY_SIZE(service), req->flags); req->retcode = uv__getaddrinfo_translate_error(ret); @@ -65,30 +73,29 @@ static DWORD WINAPI getnameinfo_thread_proc(void* parameter) { sizeof(req->service), NULL, NULL); - - /* post getnameinfo completed */ - POST_COMPLETION_FOR_REQ(loop, req); - - return 0; } /* * Called from uv_run when complete. */ -void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req) { +static void uv__getnameinfo_done(struct uv__work* w, int status) { + uv_getnameinfo_t* req; char* host; char* service; - if (req->retcode == 0) { + 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; - } else { - host = NULL; - service = NULL; } - uv__req_unregister(loop, req); req->getnameinfo_cb(req, req->retcode, host, service); } @@ -119,20 +126,18 @@ int uv_getnameinfo(uv_loop_t* loop, } uv_req_init(loop, (uv_req_t*)req); + uv__req_register(loop, req); req->getnameinfo_cb = getnameinfo_cb; req->flags = flags; req->type = UV_GETNAMEINFO; req->loop = loop; + req->retcode = 0; - /* Ask thread to run. Treat this as a long operation. */ - if (QueueUserWorkItem(&getnameinfo_thread_proc, - req, - WT_EXECUTELONGFUNCTION) == 0) { - return uv_translate_sys_error(GetLastError()); - } - - uv__req_register(loop, req); + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); return 0; } diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 83c4a66893..9eadb71235 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -31,13 +31,16 @@ #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 __declspec( thread ) int uv__crt_assert_enabled; + +extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #define UV_BEGIN_DISABLE_CRT_ASSERT() \ { \ @@ -72,7 +75,6 @@ extern __declspec( thread ) int uv__crt_assert_enabled; /* Used by streams and UDP handles. */ #define UV_HANDLE_READING 0x00000100 #define UV_HANDLE_BOUND 0x00000200 -#define UV_HANDLE_BIND_ERROR 0x00000400 #define UV_HANDLE_LISTENING 0x00000800 #define UV_HANDLE_CONNECTION 0x00001000 #define UV_HANDLE_CONNECTED 0x00002000 @@ -122,6 +124,12 @@ extern __declspec( thread ) int uv__crt_assert_enabled; /* * 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, @@ -140,7 +148,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, 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, WSAPROTOCOL_INFOW* socket_protocol_info, +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, @@ -231,7 +239,7 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); */ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); -DWORD uv_get_poll_timeout(uv_loop_t* loop); +DWORD uv__next_timeout(const uv_loop_t* loop); void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv_process_timers(uv_loop_t* loop); @@ -286,28 +294,9 @@ int uv_translate_sys_error(int sys_errno); /* - * Getaddrinfo - */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req); - - -/* -* Getnameinfo -*/ -void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req); - - -/* * FS */ void uv_fs_init(); -void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req); - - -/* - * Threadpool - */ -void uv_process_work_req(uv_loop_t* loop, uv_work_t* req); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 2fcedde369..3bf2a220d0 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -35,10 +35,10 @@ 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 to be the first field, + * 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 */ - WSAPROTOCOL_INFOW socket_info; + uv__ipc_socket_info_ex socket_info_ex; QUEUE member; int tcp_connection; }; @@ -73,7 +73,7 @@ typedef struct { /* IPC frame, which contains an imported TCP socket stream. */ typedef struct { uv_ipc_frame_header_t header; - WSAPROTOCOL_INFOW socket_info; + uv__ipc_socket_info_ex socket_info_ex; } uv_ipc_frame_uv_stream; static void eof_timer_init(uv_pipe_t* pipe); @@ -230,7 +230,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop, NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_MODE_INFORMATION mode_info; - DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; + DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT; DWORD current_mode = 0; DWORD err = 0; @@ -246,11 +246,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop, if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL, NULL, NULL, 0)) { return -1; - } else if (current_mode != mode) { + } else if (current_mode & PIPE_NOWAIT) { SetLastError(ERROR_ACCESS_DENIED); return -1; - } else { - duplex_flags &= ~UV_HANDLE_WRITABLE; } } else { /* If this returns ERROR_INVALID_PARAMETER we probably opened @@ -410,7 +408,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { socket = WSASocketW(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &item->socket_info, + &item->socket_info_ex.socket_info, 0, WSA_FLAG_OVERLAPPED); free(item); @@ -789,7 +787,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); err = uv_tcp_import((uv_tcp_t*)client, - &item->socket_info, + &item->socket_info_ex, item->tcp_connection); if (err != 0) return err; @@ -1134,10 +1132,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop, tcp_send_handle = (uv_tcp_t*)send_handle; err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid, - &ipc_frame.socket_info); + &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) { @@ -1254,7 +1255,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } /* Request queued by the kernel. */ - req->queued_bytes = uv_count_bufs(bufs, nbufs); + req->queued_bytes = uv__count_bufs(bufs, nbufs); handle->write_queue_size += req->queued_bytes; } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { /* Using overlapped IO, but wait for completion before returning */ @@ -1311,7 +1312,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, req->queued_bytes = 0; } else { /* Request queued by the kernel. */ - req->queued_bytes = uv_count_bufs(bufs, nbufs); + req->queued_bytes = uv__count_bufs(bufs, nbufs); handle->write_queue_size += req->queued_bytes; } @@ -1397,7 +1398,7 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, void uv__pipe_insert_pending_socket(uv_pipe_t* handle, - WSAPROTOCOL_INFOW* info, + uv__ipc_socket_info_ex* info, int tcp_connection) { uv__ipc_queue_item_t* item; @@ -1405,7 +1406,7 @@ void uv__pipe_insert_pending_socket(uv_pipe_t* handle, if (item == NULL) uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - memcpy(&item->socket_info, info, sizeof(item->socket_info)); + memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex)); item->tcp_connection = tcp_connection; QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member); handle->pending_ipc_info.queue_len++; @@ -1471,11 +1472,11 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { assert(avail - sizeof(ipc_frame.header) >= - sizeof(ipc_frame.socket_info)); + sizeof(ipc_frame.socket_info_ex)); /* Read the TCP socket info. */ if (!ReadFile(handle->handle, - &ipc_frame.socket_info, + &ipc_frame.socket_info_ex, sizeof(ipc_frame) - sizeof(ipc_frame.header), &bytes, NULL)) { @@ -1489,7 +1490,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, /* Store the pending socket info. */ uv__pipe_insert_pending_socket( handle, - &ipc_frame.socket_info, + &ipc_frame.socket_info_ex, ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); } @@ -1772,7 +1773,34 @@ static void eof_timer_close_cb(uv_handle_t* handle) { int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { HANDLE os_handle = uv__get_osfhandle(file); - DWORD duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + NTSTATUS nt_status; + IO_STATUS_BLOCK io_status; + FILE_ACCESS_INFORMATION access; + DWORD duplex_flags = 0; + + /* 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, duplex_flags) == -1) { diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 7a85858c56..40023e5572 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -25,6 +25,8 @@ #include <stdlib.h> #include <signal.h> #include <limits.h> +#include <malloc.h> +#include <wchar.h> #include "uv.h" #include "internal.h" @@ -36,14 +38,27 @@ typedef struct env_var { - const char* narrow; - const WCHAR* wide; - size_t len; /* including null or '=' */ - DWORD value_len; - int supplied; + const WCHAR* const wide; + const WCHAR* const wide_eq; + const size_t len; /* including null or '=' */ } env_var_t; -#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } +#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_; @@ -587,25 +602,56 @@ error: } -/* - * If we learn that people are passing in huge environment blocks - * then we should probably qsort() the array and then bsearch() - * to see if it contains this variable. But there are ownership - * issues associated with that solution; this is the caller's - * char**, and modifying it is rude. - */ -static void check_required_vars_contains_var(env_var_t* required, int count, - const char* var) { - int i; - for (i = 0; i < count; ++i) { - if (_strnicmp(required[i].narrow, var, required[i].len) == 0) { - required[i].supplied = 1; - return; +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 @@ -616,95 +662,171 @@ static void check_required_vars_contains_var(env_var_t* required, int count, * 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 = 1; /* room for closing null */ + 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*)); - env_var_t required_vars[] = { - E_V("SYSTEMROOT"), - E_V("SYSTEMDRIVE"), - E_V("TEMP"), - }; - + /* first pass: determine size in UTF-16 */ for (env = env_block; *env; env++) { int len; - check_required_vars_contains_var(required_vars, - ARRAY_SIZE(required_vars), - *env); - - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - NULL, - 0); - if (len <= 0) { - return GetLastError(); + if (strchr(*env, '=')) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + NULL, + 0); + if (len <= 0) { + return GetLastError(); + } + env_len += len; + env_block_count++; } + } - env_len += len; + /* second pass: copy to UTF-16 environment block */ + dst_copy = _malloca(env_len * sizeof(WCHAR)); + if (!dst_copy) { + return ERROR_OUTOFMEMORY; } + env_copy = alloca(env_block_count * sizeof(WCHAR*)); - for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { - if (!required_vars[i].supplied) { - env_len += required_vars[i].len; + 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(); + _freea(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); - if (var_size == 0) { - return GetLastError(); + required_vars_value_len[i] = var_size; + if (var_size != 0) { + env_len += required_vars[i].len; + env_len += var_size; } - required_vars[i].value_len = var_size; - env_len += var_size; + i++; + } else { + ptr_copy++; + if (cmp == 0) + i++; } } - dst = malloc(env_len * sizeof(WCHAR)); + /* final pass: copy, in sort order, and inserting required variables */ + dst = malloc((1+env_len) * sizeof(WCHAR)); if (!dst) { + _freea(dst_copy); return ERROR_OUTOFMEMORY; } - ptr = dst; - - for (env = env_block; *env; env++, ptr += len) { - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - ptr, - (int) (env_len - (ptr - dst))); - if (len <= 0) { - free(dst); - return GetLastError(); + 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); } - } - - for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { - if (!required_vars[i].supplied) { - wcscpy(ptr, required_vars[i].wide); - ptr += required_vars[i].len - 1; - *ptr++ = L'='; - var_size = GetEnvironmentVariableW(required_vars[i].wide, - ptr, - required_vars[i].value_len); - if (var_size == 0) { - uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); + 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"); + } } - ptr += required_vars[i].value_len; + i++; + } else { + /* copy var from env_block */ + DWORD r; + len = wcslen(*ptr_copy) + 1; + r = wmemcpy_s(ptr, (env_len - (ptr - dst)), *ptr_copy, len); + assert(!r); + ptr_copy++; + if (cmp == 0) + i++; } } /* Terminate with an extra NULL. */ + assert(env_len == (ptr - dst)); *ptr = L'\0'; + _freea(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 @@ -802,7 +924,7 @@ int uv_spawn(uv_loop_t* loop, const uv_process_options_t* options) { int i; int err = 0; - WCHAR* path = NULL; + WCHAR* path = NULL, *alloc_path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; @@ -876,7 +998,8 @@ int uv_spawn(uv_loop_t* loop, } /* Get PATH environment variable. */ - { + path = find_path(env); + if (path == NULL) { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); @@ -885,11 +1008,12 @@ int uv_spawn(uv_loop_t* loop, goto done; } - path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); - if (path == NULL) { + alloc_path = (WCHAR*) 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) { @@ -1023,7 +1147,7 @@ int uv_spawn(uv_loop_t* loop, free(arguments); free(cwd); free(env); - free(path); + free(alloc_path); if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h index cbc2ba8e18..97342e5c7e 100644 --- a/deps/uv/src/win/req-inl.h +++ b/deps/uv/src/win/req-inl.h @@ -195,26 +195,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) { uv_process_poll_req(loop, (uv_poll_t*) req->data, req); break; - case UV_GETADDRINFO: - uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); - break; - - case UV_GETNAMEINFO: - uv_process_getnameinfo_req(loop, (uv_getnameinfo_t*)req); - break; - case UV_PROCESS_EXIT: uv_process_proc_exit(loop, (uv_process_t*) req->data); break; - case UV_FS: - uv_process_fs_req(loop, (uv_fs_t*) req); - break; - - case UV_WORK: - uv_process_work_req(loop, (uv_work_t*) req); - break; - case UV_FS_EVENT_REQ: uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); break; diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h index e4bf086368..97a6b90b50 100644 --- a/deps/uv/src/win/stream-inl.h +++ b/deps/uv/src/win/stream-inl.h @@ -53,15 +53,4 @@ INLINE static void uv_connection_init(uv_stream_t* handle) { } -INLINE static 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; -} - #endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index ccd7a11e2c..a213ad63e7 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -156,6 +156,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { handle->func_acceptex = NULL; handle->func_connectex = NULL; handle->processed_accepts = 0; + handle->delayed_error = 0; return 0; } @@ -235,6 +236,17 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } +/* 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 cehck 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, @@ -291,8 +303,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle, err = WSAGetLastError(); if (err == WSAEADDRINUSE) { /* Some errors are not to be reported until connect() or listen() */ - handle->bind_error = err; - handle->flags |= UV_HANDLE_BIND_ERROR; + handle->delayed_error = err; } else { return err; } @@ -517,8 +528,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { return WSAEISCONN; } - if (handle->flags & UV_HANDLE_BIND_ERROR) { - return handle->bind_error; + if (handle->delayed_error) { + return handle->delayed_error; } if (!(handle->flags & UV_HANDLE_BOUND)) { @@ -528,6 +539,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { 0); if (err) return err; + if (handle->delayed_error) + return handle->delayed_error; } if (!handle->func_acceptex) { @@ -699,8 +712,8 @@ static int uv_tcp_try_connect(uv_connect_t* req, DWORD bytes; int err; - if (handle->flags & UV_HANDLE_BIND_ERROR) { - return handle->bind_error; + if (handle->delayed_error) { + return handle->delayed_error; } if (!(handle->flags & UV_HANDLE_BOUND)) { @@ -714,6 +727,8 @@ static int uv_tcp_try_connect(uv_connect_t* req, err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); if (err) return err; + if (handle->delayed_error) + return handle->delayed_error; } if (!handle->func_connectex) { @@ -762,8 +777,8 @@ int uv_tcp_getsockname(const uv_tcp_t* handle, return UV_EINVAL; } - if (handle->flags & UV_HANDLE_BIND_ERROR) { - return uv_translate_sys_error(handle->bind_error); + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); } result = getsockname(handle->socket, name, namelen); @@ -784,8 +799,8 @@ int uv_tcp_getpeername(const uv_tcp_t* handle, return UV_EINVAL; } - if (handle->flags & UV_HANDLE_BIND_ERROR) { - return uv_translate_sys_error(handle->bind_error); + if (handle->delayed_error) { + return uv_translate_sys_error(handle->delayed_error); } result = getpeername(handle->socket, name, namelen); @@ -839,7 +854,7 @@ int uv_tcp_write(uv_loop_t* loop, uv_insert_pending_req(loop, (uv_req_t*) req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ - req->queued_bytes = uv_count_bufs(bufs, nbufs); + req->queued_bytes = uv__count_bufs(bufs, nbufs); handle->reqs_pending++; handle->write_reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); @@ -1009,8 +1024,12 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } if (req->cb) { - err = GET_REQ_SOCK_ERROR(req); - req->cb(req, uv_translate_sys_error(err)); + 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->write_reqs_pending--; @@ -1102,14 +1121,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, } -int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, +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_protocol_info, + &socket_info_ex->socket_info, 0, WSA_FLAG_OVERLAPPED); @@ -1126,7 +1144,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, err = uv_tcp_set_socket(tcp->loop, tcp, socket, - socket_protocol_info->iAddressFamily, + socket_info_ex->socket_info.iAddressFamily, 1); if (err) { closesocket(socket); @@ -1141,6 +1159,8 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, 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; } @@ -1201,13 +1221,10 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, return ERROR_INVALID_PARAMETER; } - /* Report any deferred bind errors now. */ - if (handle->flags & UV_HANDLE_BIND_ERROR) { - return handle->bind_error; - } - - if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { - return WSAGetLastError(); + if (!(handle->delayed_error)) { + if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + handle->delayed_error = WSAGetLastError(); + } } } } diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c deleted file mode 100644 index 9539844c66..0000000000 --- a/deps/uv/src/win/threadpool.c +++ /dev/null @@ -1,81 +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 <assert.h> - -#include "uv.h" -#include "internal.h" -#include "req-inl.h" - - -static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req, - uv_work_cb work_cb, uv_after_work_cb after_work_cb) { - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_WORK; - req->loop = loop; - req->work_cb = work_cb; - req->after_work_cb = after_work_cb; - memset(&req->overlapped, 0, sizeof(req->overlapped)); -} - - -static DWORD WINAPI uv_work_thread_proc(void* parameter) { - uv_work_t* req = (uv_work_t*)parameter; - uv_loop_t* loop = req->loop; - - assert(req != NULL); - assert(req->type == UV_WORK); - assert(req->work_cb); - - req->work_cb(req); - - POST_COMPLETION_FOR_REQ(loop, req); - - return 0; -} - - -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_work_req_init(loop, req, work_cb, after_work_cb); - - if (!QueueUserWorkItem(&uv_work_thread_proc, req, WT_EXECUTELONGFUNCTION)) { - return uv_translate_sys_error(GetLastError()); - } - - uv__req_register(loop, req); - return 0; -} - - -int uv_cancel(uv_req_t* req) { - return UV_ENOSYS; -} - - -void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) { - uv__req_unregister(loop, req); - if(req->after_work_cb) - req->after_work_cb(req, 0); -} diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 16a2fc5f5f..c229d4c897 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -36,10 +36,11 @@ void uv_update_time(uv_loop_t* loop) { time.QuadPart = loop->time; - /* GetTickCount() can conceivably wrap around, so when the current tick */ - /* count is lower than the last tick count, we'll assume it has wrapped. */ - /* uv_poll must make sure that the timer can never overflow more than */ - /* once between two subsequent uv_update_time calls. */ + /* GetTickCount() can conceivably wrap around, so when the current tick + * count is lower than the last tick count, we'll assume it has wrapped. + * uv_poll must make sure that the timer can never overflow more than + * once between two subsequent uv_update_time calls. + */ time.LowPart = ticks; if (ticks < loop->last_tick_count) time.HighPart++; @@ -47,13 +48,14 @@ void uv_update_time(uv_loop_t* loop) { /* Remember the last tick count. */ loop->last_tick_count = ticks; - /* The GetTickCount() resolution isn't too good. Sometimes it'll happen */ - /* that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has */ - /* waited for a couple of ms but this is not reflected in the GetTickCount */ - /* result yet. Therefore whenever GetQueuedCompletionStatus times out */ - /* we'll add the number of ms that it has waited to the current loop time. */ - /* When that happened the loop time might be a little ms farther than what */ - /* we've just computed, and we shouldn't update the loop time. */ + /* The GetTickCount() resolution isn't too good. Sometimes it'll happen + * that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has + * waited for a couple of ms but this is not reflected in the GetTickCount + * result yet. Therefore whenever GetQueuedCompletionStatus times out + * we'll add the number of ms that it has waited to the current loop time. + * When that happened the loop time might be a little ms farther than what + * we've just computed, and we shouldn't update the loop time. + */ if (loop->time < time.QuadPart) loop->time = time.QuadPart; } @@ -193,24 +195,26 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { } -DWORD uv_get_poll_timeout(uv_loop_t* loop) { +DWORD uv__next_timeout(const uv_loop_t* loop) { uv_timer_t* timer; int64_t delta; - /* Check if there are any running timers */ - timer = RB_MIN(uv_timer_tree_s, &loop->timers); + /* 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) { - uv_update_time(loop); - delta = timer->due - loop->time; if (delta >= UINT_MAX >> 1) { - /* A timeout value of UINT_MAX means infinite, so that's no good. But */ - /* more importantly, there's always the risk that GetTickCount wraps. */ - /* uv_update_time can detect this, but we must make sure that the */ - /* tick counter never overflows twice between two subsequent */ - /* uv_update_time calls. We do this by never sleeping more than half */ - /* the time it takes to wrap the counter - which is huge overkill, */ - /* but hey, it's not so bad to wake up every 25 days. */ + /* A timeout value of UINT_MAX means infinite, so that's no good. But + * more importantly, there's always the risk that GetTickCount wraps. + * uv_update_time can detect this, but we must make sure that the + * tick counter never overflows twice between two subsequent + * uv_update_time calls. We do this by never sleeping more than half + * the time it takes to wrap the counter - which is huge overkill, + * but hey, it's not so bad to wake up every 25 days. + */ return UINT_MAX >> 1; } else if (delta < 0) { /* Negative timeout values are not allowed */ diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 87e3eb5d8a..6b8297cbd9 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -30,6 +30,10 @@ # include <stdint.h> #endif +#ifndef COMMON_LVB_REVERSE_VIDEO +# define COMMON_LVB_REVERSE_VIDEO 0x4000 +#endif + #include "uv.h" #include "internal.h" #include "handle-inl.h" diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 865890455a..ef63dd73df 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -37,8 +37,9 @@ 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(uv_udp_t* handle, struct sockaddr* name, - int* namelen) { +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { int result; if (!(handle->flags & UV_HANDLE_BOUND)) { @@ -129,6 +130,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { handle->activecnt = 0; handle->func_wsarecv = WSARecv; handle->func_wsarecvfrom = WSARecvFrom; + handle->send_queue_size = 0; + handle->send_queue_count = 0; uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); handle->recv_req.type = UV_UDP_RECV; @@ -396,12 +399,16 @@ static int uv__send(uv_udp_send_t* req, /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; + handle->send_queue_size += req->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->queued_bytes = uv_count_bufs(bufs, nbufs); + req->queued_bytes = uv__count_bufs(bufs, nbufs); handle->reqs_pending++; + handle->send_queue_size += req->queued_bytes; + handle->send_queue_count++; REGISTER_HANDLE_REQ(loop, handle, req); } else { /* Send failed due to an error. */ @@ -524,6 +531,11 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, assert(handle->type == UV_UDP); + assert(handle->send_queue_size >= req->queued_bytes); + assert(handle->send_queue_count >= 1); + handle->send_queue_size -= req->queued_bytes; + handle->send_queue_count--; + UNREGISTER_HANDLE_REQ(loop, handle, req); if (req->cb) { @@ -860,3 +872,12 @@ int uv__udp_send(uv_udp_send_t* req, return 0; } + + +int uv__udp_try_send(uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + unsigned int addrlen) { + return UV_ENOSYS; +} diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index cd50ee09f3..d8f3cda540 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -39,6 +39,7 @@ int ipc_helper(int listen_after_write); int ipc_helper_tcp_connection(void); int ipc_send_recv_helper(void); +int ipc_helper_bind_twice(void); int stdio_over_pipes_helper(void); static int maybe_run_test(int argc, char **argv); @@ -82,6 +83,10 @@ static int maybe_run_test(int argc, char **argv) { return ipc_helper_tcp_connection(); } + if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) { + return ipc_helper_bind_twice(); + } + if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { return stdio_over_pipes_helper(); } diff --git a/deps/uv/test/test-barrier.c b/deps/uv/test/test-barrier.c index 25a55d6cfe..dfd2dbdef1 100644 --- a/deps/uv/test/test-barrier.c +++ b/deps/uv/test/test-barrier.c @@ -41,10 +41,6 @@ static void worker(void* arg) { uv_sleep(c->delay); c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier); - if (c->worker_barrier_wait_rval == 1) { - uv_barrier_destroy(&c->barrier); - ASSERT(c->main_barrier_wait_rval == 0); - } } @@ -53,21 +49,16 @@ TEST_IMPL(barrier_1) { worker_config wc; memset(&wc, 0, sizeof(wc)); - wc.main_barrier_wait_rval = -1; - wc.worker_barrier_wait_rval = -1; 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); - if (wc.main_barrier_wait_rval == 1) { - uv_barrier_destroy(&wc.barrier); - ASSERT(wc.worker_barrier_wait_rval == 0); - } 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; @@ -80,19 +71,15 @@ TEST_IMPL(barrier_2) { memset(&wc, 0, sizeof(wc)); wc.delay = 100; - wc.main_barrier_wait_rval = -1; - wc.worker_barrier_wait_rval = -1; 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); - if (wc.main_barrier_wait_rval == 1) { - uv_barrier_destroy(&wc.barrier); - ASSERT(wc.worker_barrier_wait_rval == 0); - } 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; @@ -104,19 +91,15 @@ TEST_IMPL(barrier_3) { worker_config wc; memset(&wc, 0, sizeof(wc)); - wc.main_barrier_wait_rval = -1; - wc.worker_barrier_wait_rval = -1; 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); - if (wc.main_barrier_wait_rval == 1) { - uv_barrier_destroy(&wc.barrier); - ASSERT(wc.worker_barrier_wait_rval == 0); - } 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/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 40c7726cad..4c6ccfab2c 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -65,6 +65,7 @@ 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 readdir_cb_count; static int stat_cb_count; @@ -93,6 +94,8 @@ 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 readdir_req; static uv_fs_t stat_req; @@ -376,6 +379,32 @@ static void mkdir_cb(uv_fs_t* 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(uv_default_loop(), &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); @@ -927,6 +956,37 @@ TEST_IMPL(fs_async_sendfile) { } +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(loop, &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; @@ -985,6 +1045,13 @@ TEST_IMPL(fs_fstat) { ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec); ASSERT(s->st_flags == t.st_flags); ASSERT(s->st_gen == t.st_gen); +#elif defined(_AIX) + ASSERT(s->st_atim.tv_sec == t.st_atime); + ASSERT(s->st_atim.tv_nsec == 0); + ASSERT(s->st_mtim.tv_sec == t.st_mtime); + ASSERT(s->st_mtim.tv_nsec == 0); + ASSERT(s->st_ctim.tv_sec == t.st_ctime); + ASSERT(s->st_ctim.tv_nsec == 0); #elif defined(__sun) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ diff --git a/deps/uv/test/test-getsockname.c b/deps/uv/test/test-getsockname.c index a67d967f0b..565c17fe50 100644 --- a/deps/uv/test/test-getsockname.c +++ b/deps/uv/test/test-getsockname.c @@ -353,6 +353,9 @@ TEST_IMPL(getsockname_udp) { ASSERT(getsocknamecount == 2); + ASSERT(udp.send_queue_size == 0); + ASSERT(udpServer.send_queue_size == 0); + MAKE_VALGRIND_HAPPY(); return 0; } diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index 61b649b66c..ed8c4dd7f0 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -27,6 +27,7 @@ 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; @@ -38,8 +39,6 @@ static int local_conn_accepted; static int remote_conn_accepted; static int tcp_server_listening; static uv_write_t write_req; -static uv_pipe_t channel; -static uv_tcp_t tcp_server; static uv_write_t conn_notify_req; static int close_cb_called; static int connection_accepted; @@ -205,6 +204,71 @@ static void on_read(uv_stream_t* handle, 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, 12, 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, 12, 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, @@ -424,6 +488,13 @@ TEST_IMPL(listen_no_simultaneous_accepts) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(ipc_listen_after_bind_twice) { + int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice); + ASSERT(read_cb_called == 2); + ASSERT(exit_cb_called == 1); + return r; +} #endif @@ -608,7 +679,7 @@ int ipc_helper(int listen_after_write) { int ipc_helper_tcp_connection(void) { /* - * This is launched from test-ipc.c. stdin is a duplex channel that we + * This is launched from test-ipc.c. stdin is a duplex channel * over which a handle will be transmitted. */ @@ -657,3 +728,51 @@ int ipc_helper_tcp_connection(void) { 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/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 15c2e4ed38..6dbe22307e 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -28,6 +28,7 @@ TEST_DECLARE (loop_alive) TEST_DECLARE (loop_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) +TEST_DECLARE (loop_backend_timeout) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) @@ -56,6 +57,7 @@ TEST_DECLARE (delayed_accept) TEST_DECLARE (multiple_listen) TEST_DECLARE (tcp_writealot) TEST_DECLARE (tcp_try_write) +TEST_DECLARE (tcp_write_queue_order) TEST_DECLARE (tcp_open) TEST_DECLARE (tcp_connect_error_after_write) TEST_DECLARE (tcp_shutdown_after_write) @@ -71,7 +73,9 @@ TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close) +#ifndef _WIN32 TEST_DECLARE (tcp_close_accept) +#endif TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_unexpected_read) @@ -84,6 +88,7 @@ TEST_DECLARE (tcp_bind6_localhost_ok) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_send_and_recv) +TEST_DECLARE (udp_send_immediate) TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_join6) TEST_DECLARE (udp_multicast_ttl) @@ -95,6 +100,7 @@ TEST_DECLARE (udp_ipv6_only) TEST_DECLARE (udp_options) TEST_DECLARE (udp_no_autobind) TEST_DECLARE (udp_open) +TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) TEST_DECLARE (pipe_bind_error_inval) @@ -186,6 +192,7 @@ TEST_DECLARE (spawn_stdout_to_file) TEST_DECLARE (spawn_stdout_and_stderr_to_file) TEST_DECLARE (spawn_auto_unref) TEST_DECLARE (spawn_closed_process_io) +TEST_DECLARE (spawn_reads_child_path) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (kill) @@ -197,6 +204,7 @@ 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_chmod) TEST_DECLARE (fs_chown) @@ -254,6 +262,7 @@ TEST_DECLARE (listen_with_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) +TEST_DECLARE (ipc_listen_after_bind_twice) #else TEST_DECLARE (emfile) TEST_DECLARE (close_fd) @@ -286,6 +295,7 @@ TASK_LIST_START TEST_ENTRY (loop_close) TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) + TEST_ENTRY (loop_backend_timeout) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) @@ -330,6 +340,8 @@ TASK_LIST_START TEST_ENTRY (tcp_try_write) + TEST_ENTRY (tcp_write_queue_order) + TEST_ENTRY (tcp_open) TEST_HELPER (tcp_open, tcp4_echo_server) @@ -349,7 +361,9 @@ TASK_LIST_START TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close) +#ifndef _WIN32 TEST_ENTRY (tcp_close_accept) +#endif TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_write_to_half_open_connection) TEST_ENTRY (tcp_unexpected_read) @@ -366,6 +380,7 @@ TASK_LIST_START TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_send_and_recv) + TEST_ENTRY (udp_send_immediate) TEST_ENTRY (udp_dgram_too_big) TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_ipv6_only) @@ -376,6 +391,7 @@ TASK_LIST_START 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) @@ -505,6 +521,7 @@ TASK_LIST_START TEST_ENTRY (spawn_stdout_and_stderr_to_file) TEST_ENTRY (spawn_auto_unref) TEST_ENTRY (spawn_closed_process_io) + TEST_ENTRY (spawn_reads_child_path) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) @@ -518,6 +535,7 @@ TASK_LIST_START TEST_ENTRY (listen_no_simultaneous_accepts) TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) + TEST_ENTRY (ipc_listen_after_bind_twice) #else TEST_ENTRY (emfile) TEST_ENTRY (close_fd) @@ -541,6 +559,7 @@ TASK_LIST_START 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_chmod) TEST_ENTRY (fs_chown) diff --git a/deps/uv/test/test-loop-time.c b/deps/uv/test/test-loop-time.c index 49dc79b2c3..a2db42ccee 100644 --- a/deps/uv/test/test-loop-time.c +++ b/deps/uv/test/test-loop-time.c @@ -30,5 +30,34 @@ TEST_IMPL(loop_update_time) { 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/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index c75f1ca2fd..57f0862f94 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -31,6 +31,7 @@ # include <basetyps.h> # endif # include <shellapi.h> +# include <wchar.h> #else # include <unistd.h> #endif @@ -897,45 +898,110 @@ TEST_IMPL(environment_creation) { "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 expected[512]; - WCHAR* ptr = expected; + 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 < sizeof(environment) / sizeof(environment[0]) - 1; i++) { - ptr += uv_utf8_to_utf16(environment[i], - ptr, - expected + sizeof(expected) - ptr); + 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); + } } - memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT=")); - ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1; - ptr += GetEnvironmentVariableW(L"SYSTEMROOT", - ptr, - expected + sizeof(expected) - ptr); - ++ptr; - - memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE=")); - ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1; - ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", - ptr, - expected + sizeof(expected) - ptr); - ++ptr; - *ptr = '\0'; - result = make_program_env(environment, &env); ASSERT(result == 0); - for (str = env; *str; str += wcslen(str) + 1) { - wprintf(L"%s\n", str); + 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 + ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1); +#endif + } + ASSERT(found); /* verify that we expected this variable */ } - ASSERT(wcscmp(expected, env) == 0); + /* 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; } @@ -1225,3 +1291,38 @@ TEST_IMPL(closed_fd_events) { return 0; } #endif /* !_WIN32 */ + +TEST_IMPL(spawn_reads_child_path) { + int r; + int len; + char path[1024]; + char *env[2] = {path, NULL}; + + /* 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); + options.file = "run-tests"; + args[0] = "run-tests"; + + /* Set up the PATH env variable */ + for (len = strlen(exepath); + exepath[len - 1] != '/' && exepath[len - 1] != '\\'; + len--); + exepath[len] = 0; + strcpy(path, "PATH="); + strcpy(path + 5, exepath); + + 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; +} diff --git a/deps/uv/test/test-tcp-close-accept.c b/deps/uv/test/test-tcp-close-accept.c index 10f9d91964..5517aaf99e 100644 --- a/deps/uv/test/test-tcp-close-accept.c +++ b/deps/uv/test/test-tcp-close-accept.c @@ -19,6 +19,9 @@ * IN THE SOFTWARE. */ +/* this test is Unix only */ +#ifndef _WIN32 + #include "uv.h" #include "task.h" @@ -181,3 +184,5 @@ TEST_IMPL(tcp_close_accept) { MAKE_VALGRIND_HAPPY(); return 0; } + +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-tcp-try-write.c b/deps/uv/test/test-tcp-try-write.c index 00341e4169..baff6cf36c 100644 --- a/deps/uv/test/test-tcp-try-write.c +++ b/deps/uv/test/test-tcp-try-write.c @@ -54,21 +54,19 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - static char zeroes[1024]; int r; uv_buf_t buf; ASSERT(status == 0); connect_cb_called++; do { - buf = uv_buf_init(zeroes, sizeof(zeroes)); + buf = uv_buf_init("PING", 4); r = uv_try_write((uv_stream_t*) &client, &buf, 1); - ASSERT(r >= 0); - bytes_written += r; - - /* Partial write */ - if (r != (int) sizeof(zeroes)) + ASSERT(r > 0 || r == UV_EAGAIN); + if (r > 0) { + bytes_written += r; break; + } } while (1); uv_close((uv_handle_t*) &client, close_cb); } diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c new file mode 100644 index 0000000000..18e1f192b6 --- /dev/null +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -0,0 +1,137 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "uv.h" +#include "task.h" + +#define REQ_COUNT 100000 + +static uv_timer_t timer; +static uv_tcp_t server; +static uv_tcp_t client; +static uv_tcp_t incoming; +static int connect_cb_called; +static int close_cb_called; +static int connection_cb_called; +static int write_callbacks; +static int write_cancelled_callbacks; +static int write_error_callbacks; + +static uv_write_t write_requests[REQ_COUNT]; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +void timer_cb(uv_timer_t* handle) { + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &server, close_cb); + uv_close((uv_handle_t*) &incoming, close_cb); +} + +void write_cb(uv_write_t* req, int status) { + if (status == 0) + write_callbacks++; + else if (status == UV_ECANCELED) + write_cancelled_callbacks++; + else + write_error_callbacks++; +} + +static void connect_cb(uv_connect_t* req, int status) { + static char base[1024]; + int r; + int i; + uv_buf_t buf; + + ASSERT(status == 0); + connect_cb_called++; + + buf = uv_buf_init(base, sizeof(base)); + + for (i = 0; i < REQ_COUNT; i++) { + r = uv_write(&write_requests[i], + req->handle, + &buf, + 1, + write_cb); + ASSERT(r == 0); + } +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT(status == 0); + + ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); + ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + + connection_cb_called++; +} + + +static void start_server(void) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); +} + + +TEST_IMPL(tcp_write_queue_order) { + uv_connect_t connect_req; + struct sockaddr_in addr; + + start_server(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + ASSERT(0 == uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); + + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0)); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(connection_cb_called == 1); + ASSERT(write_callbacks > 0); + ASSERT(write_cancelled_callbacks > 0); + ASSERT(write_callbacks + + write_error_callbacks + + write_cancelled_callbacks == REQ_COUNT); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-udp-multicast-interface.c b/deps/uv/test/test-udp-multicast-interface.c index 643df31802..f0679c578e 100644 --- a/deps/uv/test/test-udp-multicast-interface.c +++ b/deps/uv/test/test-udp-multicast-interface.c @@ -91,6 +91,9 @@ TEST_IMPL(udp_multicast_interface) { 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/deps/uv/test/test-udp-open.c b/deps/uv/test/test-udp-open.c index 9a97303f12..b2b6117784 100644 --- a/deps/uv/test/test-udp-open.c +++ b/deps/uv/test/test-udp-open.c @@ -159,6 +159,8 @@ TEST_IMPL(udp_open) { ASSERT(send_cb_called == 1); ASSERT(close_cb_called == 1); + ASSERT(client.send_queue_size == 0); + MAKE_VALGRIND_HAPPY(); return 0; } diff --git a/deps/uv/test/test-udp-send-and-recv.c b/deps/uv/test/test-udp-send-and-recv.c index 3020ded7bf..633a16727b 100644 --- a/deps/uv/test/test-udp-send-and-recv.c +++ b/deps/uv/test/test-udp-send-and-recv.c @@ -206,6 +206,9 @@ TEST_IMPL(udp_send_and_recv) { 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/deps/uv/test/test-udp-send-immediate.c b/deps/uv/test/test-udp-send-immediate.c new file mode 100644 index 0000000000..0999f6b342 --- /dev/null +++ b/deps/uv/test/test-udp-send-immediate.c @@ -0,0 +1,148 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int cl_send_cb_called; +static int sv_recv_cb_called; +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(1 == uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + cl_send_cb_called++; +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards sv_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(memcmp("PING", rcvbuf->base, nread) == 0 || + memcmp("PANG", rcvbuf->base, nread) == 0); + + if (++sv_recv_cb_called == 2) { + uv_close((uv_handle_t*) &server, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } +} + + +TEST_IMPL(udp_send_immediate) { + struct sockaddr_in addr; + uv_udp_send_t req1, req2; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + /* client sends "PING", then "PANG" */ + buf = uv_buf_init("PING", 4); + + r = uv_udp_send(&req1, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + cl_send_cb); + ASSERT(r == 0); + + buf = uv_buf_init("PANG", 4); + + r = uv_udp_send(&req2, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + cl_send_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(cl_send_cb_called == 2); + ASSERT(sv_recv_cb_called == 2); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-udp-try-send.c b/deps/uv/test/test-udp-try-send.c new file mode 100644 index 0000000000..7b6de36548 --- /dev/null +++ b/deps/uv/test/test-udp-try-send.c @@ -0,0 +1,133 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 + +TEST_IMPL(udp_try_send) { + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#else /* !_WIN32 */ + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; + +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(uv_is_closing(handle)); + close_cb_called++; +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + ASSERT(nread > 0); + + if (nread == 0) { + ASSERT(addr == NULL); + return; + } + + ASSERT(nread == 4); + ASSERT(addr != NULL); + + ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0); + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + + sv_recv_cb_called++; +} + + +TEST_IMPL(udp_try_send) { + struct sockaddr_in addr; + static char buffer[64 * 1024]; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + buf = uv_buf_init(buffer, sizeof(buffer)); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); + ASSERT(r == UV_EMSGSIZE); + + buf = uv_buf_init("EXIT", 4); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); + ASSERT(r == 4); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + ASSERT(sv_recv_cb_called == 1); + + ASSERT(client.send_queue_size == 0); + ASSERT(server.send_queue_size == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-watcher-cross-stop.c b/deps/uv/test/test-watcher-cross-stop.c index 9284a1291f..bf765cb00c 100644 --- a/deps/uv/test/test-watcher-cross-stop.c +++ b/deps/uv/test/test-watcher-cross-stop.c @@ -91,7 +91,7 @@ TEST_IMPL(watcher_cross_stop) { for (i = 0; i < ARRAY_SIZE(sockets); i++) uv_close((uv_handle_t*) &sockets[i], close_cb); - ASSERT(0 < recv_cb_called && recv_cb_called <= ARRAY_SIZE(sockets)); + ASSERT(recv_cb_called > 0); ASSERT(ARRAY_SIZE(sockets) == send_cb_called); uv_run(loop, UV_RUN_DEFAULT); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 147fc06c3a..5b4d69a924 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -61,11 +61,13 @@ 'include/uv.h', 'include/tree.h', 'include/uv-errno.h', + 'include/uv-threadpool.h', 'include/uv-version.h', 'src/fs-poll.c', 'src/heap-inl.h', 'src/inet.c', 'src/queue.h', + 'src/threadpool.c', 'src/uv-common.c', 'src/uv-common.h', 'src/version.c' @@ -103,7 +105,6 @@ 'src/win/stream-inl.h', 'src/win/tcp.c', 'src/win/tty.c', - 'src/win/threadpool.c', 'src/win/timer.c', 'src/win/udp.c', 'src/win/util.c', @@ -114,11 +115,11 @@ ], 'link_settings': { 'libraries': [ - '-ladvapi32.lib', - '-liphlpapi.lib', - '-lpsapi.lib', - '-lshell32.lib', - '-lws2_32.lib' + '-ladvapi32', + '-liphlpapi', + '-lpsapi', + '-lshell32', + '-lws2_32' ], }, }, { # Not Windows i.e. POSIX @@ -136,6 +137,7 @@ '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', @@ -154,7 +156,6 @@ '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', @@ -245,6 +246,7 @@ 'defines': [ '_ALL_SOURCE', '_XOPEN_SOURCE=500', + '_LINUX_SOURCE_COMPAT', ], 'link_settings': { 'libraries': [ @@ -378,6 +380,7 @@ 'test/test-tcp-try-write.c', 'test/test-tcp-unexpected-read.c', 'test/test-tcp-read-stop.c', + 'test/test-tcp-write-queue-order.c', 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', 'test/test-mutexes.c', @@ -394,6 +397,7 @@ 'test/test-udp-open.c', 'test/test-udp-options.c', 'test/test-udp-send-and-recv.c', + 'test/test-udp-send-immediate.c', 'test/test-udp-multicast-join.c', 'test/test-udp-multicast-join6.c', 'test/test-dlerror.c', @@ -402,6 +406,7 @@ 'test/test-ip6-addr.c', 'test/test-udp-multicast-interface.c', 'test/test-udp-multicast-interface6.c', + 'test/test-udp-try-send.c', ], 'conditions': [ [ 'OS=="win"', { @@ -409,7 +414,7 @@ 'test/runner-win.c', 'test/runner-win.h' ], - 'libraries': [ 'ws2_32.lib' ] + 'libraries': [ '-lws2_32' ] }, { # POSIX 'defines': [ '_GNU_SOURCE' ], 'sources': [ @@ -473,7 +478,7 @@ 'test/runner-win.c', 'test/runner-win.h', ], - 'libraries': [ 'ws2_32.lib' ] + 'libraries': [ '-lws2_32' ] }, { # POSIX 'defines': [ '_GNU_SOURCE' ], 'sources': [ |