diff options
110 files changed, 6370 insertions, 1680 deletions
diff --git a/deps/uv/.gitignore b/deps/uv/.gitignore index a2e255811..14a174adf 100644 --- a/deps/uv/.gitignore +++ b/deps/uv/.gitignore @@ -61,3 +61,9 @@ UpgradeLog*.XML Debug Release ipch + +# sphinx generated files +/docs/build/ + +*.xcodeproj +*.xcworkspace diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 2ca07c838..34f5e4daf 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -14,11 +14,13 @@ Isaac Z. Schlueter <i@izs.me> Justin Venus <justin.venus@gmail.com> <justin.venus@orbitz.com> Keno Fischer <kenof@stanford.edu> <kfischer+github@college.harvard.edu> Keno Fischer <kenof@stanford.edu> <kfischer@college.harvard.edu> +Leonard Hecker <leonard.hecker91@gmail.com> <leonard@hecker.io> Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com> Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com> Rasmus Christian Pedersen <ruysch@outlook.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 19f911f11..210fa5610 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -155,3 +155,5 @@ Pavel Platto <hinidu@gmail.com> Tony Kelman <tony@kelman.net> John Firebaugh <john.firebaugh@gmail.com> lilohuang <lilohuang@hotmail.com> +Paul Goldsmith <paul.goldsmith@aplink.net> +Julien Gilli <julien.gilli@joyent.com> diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index db13f188c..9d303e4ff 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,101 @@ -2014.08.08, Version 0.11.28 (Unstable) +2014.09.18, Version 1.0.0-rc1 (Unstable), 0c28bbf7b42882853d1799ab96ff68b07f7f8d49 + +* windows: improve timer precision (Alexis Campailla) + +* build, gyp: set xcode flags (Recep ASLANTAS) + +* ignore: include m4 files which are created manually (Recep ASLANTAS) + +* build: add m4 for feature/flag-testing (Recep ASLANTAS) + +* ignore: ignore Xcode project and workspace files (Recep ASLANTAS) + +* unix: fix warnings about dollar symbol usage in identifiers (Recep ASLANTAS) + +* unix: fix warnings when loading functions with dlsym (Recep ASLANTAS) + +* linux: try epoll_pwait if epoll_wait is missing (Michael Hudson-Doyle) + +* test: add test for closing and recreating default loop (Saúl Ibarra Corretgé) + +* windows: properly close the default loop (Saúl Ibarra Corretgé) + +* version: add ability to specify a version suffix (Saúl Ibarra Corretgé) + +* doc: add API documentation (Saúl Ibarra Corretgé) + +* test: don't close connection on write error (Trevor Norris) + +* windows: further simplify the code for timers (Saúl Ibarra Corretgé) + +* gyp: remove UNLIMITED_SELECT from dependent define (Fedor Indutny) + +* darwin: allocate enough space for select() hack (Fedor Indutny) + +* unix, windows: don't allow a NULL callback on timers (Saúl Ibarra Corretgé) + +* windows: simplify code in uv_timer_again (Saúl Ibarra Corretgé) + +* test: use less requests on tcp-write-queue-order (Saúl Ibarra Corretgé) + +* unix: stop child process watcher after last one exits (Saúl Ibarra Corretgé) + +* unix: simplify how process handle queue is managed (Saúl Ibarra Corretgé) + +* windows: remove duplicated field (mattn) + +* core: add a reserved field to uv_handle_t and uv_req_t (Saúl Ibarra Corretgé) + +* windows: fix buffer leak after failed udp send (Bert Belder) + +* windows: make sure sockets and handles are reset on close (Saúl Ibarra Corretgé) + +* unix, windows: add uv_fileno (Saúl Ibarra Corretgé) + +* build: use same CFLAGS in autotools build as in gyp (Saúl Ibarra Corretgé) + +* build: remove unneeded define in uv.gyp (Saúl Ibarra Corretgé) + +* test: fix watcher_cross_stop on Windows (Saúl Ibarra Corretgé) + +* unix, windows: move includes for EAI constants (Saúl Ibarra Corretgé) + +* unix: fix exposing EAI_* glibc-isms (Saúl Ibarra Corretgé) + +* unix: fix tcp write after bad connect freezing (Andrius Bentkus) + + +2014.08.20, Version 0.11.29 (Unstable), 35451fed830807095bbae8ef981af004a4b9259e + +Changes since version 0.11.28: + +* windows: make uv_read_stop immediately stop reading (Jameson Nash) + +* windows: fix uv__getaddrinfo_translate_error (Alexis Campailla) + +* netbsd: fix build (Saúl Ibarra Corretgé) + +* unix, windows: add uv_recv_buffer_size and uv_send_buffer_size (Andrius + Bentkus) + +* windows: add support for UNC paths on uv_spawn (Paul Goldsmith) + +* windows: replace use of inet_addr with uv_inet_pton (Saúl Ibarra Corretgé) + +* unix: replace some asserts with returning errors (Andrius Bentkus) + +* windows: use OpenBSD implementation for uv_fs_mkdtemp (Pavel Platto) + +* windows: fix GetNameInfoW error handling (Alexis Campailla) + +* fs: introduce uv_readdir_next() and report types (Fedor Indutny) + +* fs: extend reported types in uv_fs_readdir_next (Saúl Ibarra Corretgé) + +* unix: read on stream even when UV__POLLHUP set. (Julien Gilli) + + +2014.08.08, Version 0.11.28 (Unstable), fc9e2a0bc487b299c0cd3b2c9a23aeb554b5d8d1 Changes since version 0.11.27: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 861b632bb..06a5532ef 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -23,7 +23,7 @@ CLEANFILES = lib_LTLIBRARIES = libuv.la libuv_la_CFLAGS = @CFLAGS@ -libuv_la_LDFLAGS = -no-undefined -version-info 11:0:0 +libuv_la_LDFLAGS = -no-undefined -version-info 1:0:0 libuv_la_SOURCES = src/fs-poll.c \ src/heap-inl.h \ src/inet.c \ @@ -81,6 +81,7 @@ else # WINNT include_HEADERS += include/uv-unix.h AM_CPPFLAGS += -I$(top_srcdir)/src/unix +libuv_la_CFLAGS += -g --std=gnu89 -pedantic -Wall -Wextra -Wno-unused-parameter libuv_la_SOURCES += src/unix/async.c \ src/unix/atomic-ops.h \ src/unix/core.c \ @@ -126,6 +127,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-condvar.c \ test/test-connection-fail.c \ test/test-cwd-and-chdir.c \ + test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ test/test-embed.c \ @@ -141,6 +143,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-getaddrinfo.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ + test/test-handle-fileno.c \ test/test-hrtime.c \ test/test-idle.c \ test/test-ip4-addr.c \ @@ -163,6 +166,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-getsockname.c \ test/test-pipe-sendmsg.c \ test/test-pipe-server-close.c \ + test/test-pipe-close-stdout-read-stdin.c \ test/test-platform-output.c \ test/test-poll-close.c \ test/test-poll-closesocket.c \ @@ -177,6 +181,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-shutdown-twice.c \ test/test-signal-multiple-loops.c \ test/test-signal.c \ + test/test-socket-buffer-size.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ test/test-tcp-bind-error.c \ @@ -194,6 +199,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-shutdown-after-write.c \ test/test-tcp-unexpected-read.c \ test/test-tcp-write-to-half-open-connection.c \ + test/test-tcp-write-after-connect.c \ test/test-tcp-writealot.c \ test/test-tcp-try-write.c \ test/test-tcp-write-queue-order.c \ @@ -216,6 +222,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-options.c \ test/test-udp-send-and-recv.c \ test/test-udp-send-immediate.c \ + test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ test/test-walk-handles.c \ test/test-watcher-cross-stop.c @@ -253,6 +260,7 @@ endif if DARWIN include_HEADERS += include/uv-darwin.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 +libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/darwin.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 364cf695c..e0edf5038 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -34,6 +34,11 @@ used by Mozilla's [Rust language](http://www.rust-lang.org/), * Threading and synchronization primitives +## Versioning + +Starting with version 1.0.0 libuv follows the [semantic versioning](http://semver.org/) +scheme. The API change and backwards compatiblity rules are those indicated by +SemVer. libuv will keep a stable ABI across major releases. ## Community @@ -41,8 +46,34 @@ used by Mozilla's [Rust language](http://www.rust-lang.org/), ## Documentation - * [include/uv.h](https://github.com/joyent/libuv/blob/master/include/uv.h) - — API documentation in the form of detailed header comments. +### Official API documentation + +Located in the docs/ subdirectory. It uses the [Sphinx](http://sphinx-doc.org/) +framework, which makes it possible to build the documentation in multiple +formats. + +Show different supported building options: + + $ make help + +Build documentation as HTML: + + $ make html + +Build documentation as man pages: + + $ make man + +Build documentation as ePub: + + $ make epub + +NOTE: Windows users need to use make.bat instead of plain 'make'. + +Documentation can be browsed online [here](http://docs.libuv.org). + +### Other resources + * [An Introduction to libuv](http://nikhilm.github.com/uvbook/) — An overview of libuv with tutorials. * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index ac789524b..e85439c05 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,16 +13,18 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [0.11.28], [https://github.com/joyent/libuv/issues]) +AC_INIT([libuv], [1.0.0], [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]) +m4_include([m4/libuv-check-flags.m4]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) AC_CANONICAL_HOST AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O +CC_CHECK_CFLAGS_APPEND([-Wno-dollar-in-identifier-extension]) # AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/deps/uv/docs/make.bat b/deps/uv/docs/make.bat new file mode 100644 index 000000000..10eb94b01 --- /dev/null +++ b/deps/uv/docs/make.bat @@ -0,0 +1,243 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=build +set SRCDIR=src +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SRCDIR% +set I18NSPHINXOPTS=%SPHINXOPTS% %SRCDIR% +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^<target^>` where ^<target^> is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libuv.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libuv.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/deps/uv/docs/src/async.rst b/deps/uv/docs/src/async.rst new file mode 100644 index 000000000..7afc92a71 --- /dev/null +++ b/deps/uv/docs/src/async.rst @@ -0,0 +1,56 @@ + +.. _async: + +:c:type:`uv_async_t` --- Async handle +===================================== + +Async handles allow the user to "wakeup" the event loop and get a callback +called from another thread. + + +Data types +---------- + +.. c:type:: uv_async_t + + Async handle type. + +.. c:type:: void (*uv_async_cb)(uv_async_t* handle) + + Type definition for callback passed to :c:func:`uv_async_init`. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) + + Initialize the handle. A NULL callback is allowed. + + .. note:: + Unlike other handle initialization functions, it immediately starts the handle. + +.. c:function:: int uv_async_send(uv_async_t* async) + + Wakeup the event loop and call the async handle's callback. + + .. note:: + It's safe to call this function from any thread. The callback will be called on the + loop thread. + + .. warning:: + libuv will coalesce calls to :c:func:`uv_async_send`, that is, not every call to it will + yield an execution of the callback, the only guarantee is that it will be called at least + once. Thus, calling this function may not wakeup the event loop if it was already called + previously within a short period of time. + +.. seealso:: + The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/check.rst b/deps/uv/docs/src/check.rst new file mode 100644 index 000000000..8d48f2227 --- /dev/null +++ b/deps/uv/docs/src/check.rst @@ -0,0 +1,46 @@ + +.. _check: + +:c:type:`uv_check_t` --- Check handle +===================================== + +Check handles will run the given callback once per loop iteration, right +after polling for i/o. + + +Data types +---------- + +.. c:type:: uv_check_t + + Check handle type. + +.. c:type:: void (*uv_check_cb)(uv_check_t* handle) + + Type definition for callback passed to :c:func:`uv_check_start`. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_check_init(uv_loop_t*, uv_check_t* check) + + Initialize the handle. + +.. c:function:: int uv_check_start(uv_check_t* check, uv_check_cb cb) + + Start the handle with the given callback. + +.. c:function:: int uv_check_stop(uv_check_t* check) + + Stop the handle, the callback will no longer be called. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/conf.py b/deps/uv/docs/src/conf.py new file mode 100644 index 000000000..9ec9ec2c9 --- /dev/null +++ b/deps/uv/docs/src/conf.py @@ -0,0 +1,348 @@ +# -*- coding: utf-8 -*- +# +# libuv API documentation documentation build configuration file, created by +# sphinx-quickstart on Sun Jul 27 11:47:51 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import os +import re +import sys + + +def get_libuv_version(): + with open('../../include/uv-version.h') as f: + data = f.read() + try: + m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE) + major = int(m.group(1)) + m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE) + minor = int(m.group(1)) + m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE) + patch = int(m.group(1)) + m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE) + is_release = int(m.group(1)) + m = re.search(r"""^#define UV_VERSION_SUFFIX \"(\w*)\"$""", data, re.MULTILINE) + suffix = m.group(1) + return '%d.%d.%d%s' % (major, minor, patch, '-%s' % suffix if not is_release else '') + except Exception: + return 'unknown' + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'libuv API documentation' +copyright = u'libuv contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = get_libuv_version() +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +html_title = 'libuv API documentation' + +# A shorter title for the navigation bar. Default is the same as html_title. +html_short_title = 'libuv %s API documentation' % version + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = 'static/logo.png' + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +html_favicon = 'static/favicon.ico' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libuv' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'libuv.tex', u'libuv API documentation', + u'libuv contributors', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'libuv', u'libuv API documentation', + [u'libuv contributors'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'libuv', u'libuv API documentation', + u'libuv contributors', 'libuv', 'Cross-platform asychronous I/O', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'libuv API documentation' +epub_author = u'libuv contributors' +epub_publisher = u'libuv contributors' +epub_copyright = u'2014, libuv contributors' + +# The basename for the epub file. It defaults to the project name. +epub_basename = u'libuv' + +# The HTML theme for the epub output. Since the default themes are not optimized +# for small screen space, using the same theme for HTML and epub output is +# usually not wise. This defaults to 'epub', a theme designed to save visual +# space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the PIL. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True diff --git a/deps/uv/docs/src/design.rst b/deps/uv/docs/src/design.rst new file mode 100644 index 000000000..803a42198 --- /dev/null +++ b/deps/uv/docs/src/design.rst @@ -0,0 +1,137 @@ + +.. _design: + +Design overview +=============== + +libuv is cross-platform support library which was originally written for NodeJS. It's designed +around the event-driven asynchronous I/O model. + +The library provides much more than simply abstraction over different I/O polling mechanisms: +'handles' and 'streams' provde a high level abstraction for sockets and other entities; +cross-platform file I/O and threading functionality is also provided, amongst other things. + +Here is a diagram illustrating the different parts that compose libuv and what subsystem they +relate to: + +.. image:: static/architecture.png + :scale: 75% + :align: center + + +Handles and requests +^^^^^^^^^^^^^^^^^^^^ + +libuv provides users with 2 abstractions to work with, in combination with the event loop: +handles and requests. + +Handles represent long-lived objects capable of performing certain operations while active. Some +examples: a prepare handle gets its callback called once every loop iteration when active, and +a TCP server handle get its connection callback called every time there is a new connection. + +Requests represent (typically) short-lived operations. These operations can be performed over a +handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests +don't need a handle they run directly on the loop. + + +The I/O loop +^^^^^^^^^^^^ + +The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O +operations, and it's meant to be tied to a single thread. One can run multiple event loops +as long as each runs in a different thread. The libuv event loop (or any other API involving +the loop or handles, for that matter) **is not thread-safe** except stated otherwise. + +The event loop follows the rather usual single threaded asynchronous I/O approah: all (network) +I/O is performed on non-blocking sockets which are polled using the best mechanism available +on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP +on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets +which have been added to the poller and callbacks will be fired indicating socket conditions +(readable, writable hangup) so handles can read, write or perform the desired I/O operation. + +In order to better understand how the event loop operates, the following diagram illustrates all +stages of a loop iteration: + +.. image:: static/loop_iteration.png + :scale: 75% + :align: center + + +#. The loop concept of 'now' is updated. The event loop caches the current time at the start of + the event loop tick in order to reduce the number of time-related system calls. + +#. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So, + when is a loop considered to be *alive*? If a loop has active and ref'd handles, active + requests or closing handles it's considered to be *alive*. + +#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now* + get their callbacks called. + +#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the + most part. There are cases, however, in which calling such a callback is deferred for the next + loop iteration. If the previous iteration deferred any I/O callback it will be run at this point. + +#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every + loop iteration, if they are active. + +#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before + the loop will block for I/O. + +#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should + block. These are the rules when calculating the timeout: + + * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0. + * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0. + * If there are no active handles or requests, the timeout is 0. + * If there are any idle handles active, the timeout is 0. + * If there are any handles pending to be closed, the timeout is 0. + * If none of the above cases was matched, the timeout of the closest timer is taken, or + if there are no active timers, infinity. + +#. The loop blocks for I/O. At this point the loop will block for I/O for the timeout calculated + on the previous step. All I/O related handles that were monitoring a given file descriptor + for a read or write operation get their callbacks called at this point. + +#. Check handle callbacks are called. Check handles get their callbacks called right after the + loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles. + +#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will + get the close callback called. + +#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress. + It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed + so there might be timers which are due, those timers get their callbacks called. + +#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the + iteration is ended and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` + it will contionue from the start if it's asill *alive*, otherwise it will also end. + + +.. important:: + libuv uses a thread pool to make asynchronous file I/O operations possible, but + network I/O is **always** performed in a single thread, each loop's thread. + +.. note:: + While the polling mechanism is different, libuv makes the execution model consistent + Unix systems and Windows. + + +File I/O +^^^^^^^^ + +Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, +so the current approach is to run blocking file I/O operations in a thread pool. + +For a thorough explanation of the cross-platform file I/O landscape, checkout +`this post <http://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_. + +libuv currently uses a global thread pool on which all loops can queue work on. 3 types of +operations are currently run on this pool: + + * Filesystem operations + * DNS functions (getaddrinfo and getnameinfo) + * User specified code via :c:func:`uv_queue_work` + +.. warning:: + See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size + is quite limited. diff --git a/deps/uv/docs/src/dll.rst b/deps/uv/docs/src/dll.rst new file mode 100644 index 000000000..3afa31f39 --- /dev/null +++ b/deps/uv/docs/src/dll.rst @@ -0,0 +1,44 @@ + +.. _dll: + +Shared library handling +======================= + +libuv prodives cross platform utilities for loading shared libraries and +retrieving symbols from them, using the following API. + + +Data types +---------- + +.. c:type:: uv_lib_t + + Shared library data type. + + +Public members +^^^^^^^^^^^^^^ + +N/A + + +API +--- + +.. c:function:: int uv_dlopen(const char* filename, uv_lib_t* lib) + + Opens a shared library. The filename is in utf-8. Returns 0 on success and + -1 on error. Call :c:func:`uv_dlerror` to get the error message. + +.. c:function:: void uv_dlclose(uv_lib_t* lib) + + Close the shared library. + +.. c:function:: uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) + + Retrieves a data pointer from a dynamic library. It is legal for a symbol + to map to NULL. Returns 0 on success and -1 if the symbol was not found. + +.. c:function:: const char* uv_dlerror(const uv_lib_t* lib) + + Returns the last uv_dlopen() or uv_dlsym() error message. diff --git a/deps/uv/docs/src/dns.rst b/deps/uv/docs/src/dns.rst new file mode 100644 index 000000000..d7c889f7a --- /dev/null +++ b/deps/uv/docs/src/dns.rst @@ -0,0 +1,83 @@ + +.. _dns: + +DNS utility functions +===================== + +libuv provides asynchronous variants of `getaddrinfo` and `getnameinfo`. + + +Data types +---------- + +.. c:type:: uv_getaddrinfo_t + + `getaddrinfo` request type. + +.. c:type:: void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, int status, struct addrinfo* res) + + Callback which will be called with the getaddrinfo request result once + complete. In case it was cancelled, `status` will have a value of + ``UV_ECANCELED``. + +.. c:type:: uv_getnameinfo_t + + `getnameinfo` request type. + +.. c:type:: void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, int status, const char* hostname, const char* service) + + Callback which will be called with the getnameinfo request result once + complete. In case it was cancelled, `status` will have a value of + ``UV_ECANCELED``. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_loop_t* uv_getaddrinfo_t.loop + + Loop that started this getaddrinfo request and where completion will be + reported. Readonly. + +.. c:member:: uv_loop_t* uv_getnameinfo_t.loop + + Loop that started this getnameinfo request and where completion will be + reported. Readonly. + +.. seealso:: The :c:type:`uv_req_t` members also apply. + + +API +--- + +.. c:function:: int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints) + + Asynchronous ``getaddrinfo(3)``. + + Either node or service may be NULL but not both. + + `hints` is a pointer to a struct addrinfo with additional address type + constraints, or NULL. Consult `man -s 3 getaddrinfo` for more details. + + Returns 0 on success or an error code < 0 on failure. If successful, the + callback will get called sometime in the future with the lookup result, + which is either: + + * status == 0, the res argument points to a valid `struct addrinfo`, or + * status < 0, the res argument is NULL. See the UV_EAI_* constants. + + Call :c:func:`uv_freeaddrinfo` to free the addrinfo structure. + +.. c:function:: void uv_freeaddrinfo(struct addrinfo* ai) + + Free the struct addrinfo. Passing NULL is allowed and is a no-op. + +.. c:function:: int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags) + + Asynchronous ``getnameinfo(3)``. + + Returns 0 on success or an error code < 0 on failure. If successful, the + callback will get called sometime in the future with the lookup result. + Consult `man -s 3 getnameinfo` for more details. + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. diff --git a/deps/uv/docs/src/errors.rst b/deps/uv/docs/src/errors.rst new file mode 100644 index 000000000..5d59dc30f --- /dev/null +++ b/deps/uv/docs/src/errors.rst @@ -0,0 +1,329 @@ + +.. _errors: + +Error handling +============== + +In libuv errors are negative numbered constants. As a rule of thumb, whenever +there is a status parameter, or an API functions returns an integer, a negative +number will imply an error. + +.. note:: + Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on + Windows they are defined by libuv to arbitrary negative numbers. + + +Error constants +--------------- + +.. c:macro:: UV_E2BIG + + argument list too long + +.. c:macro:: UV_EACCES + + permission denied + +.. c:macro:: UV_EADDRINUSE + + address already in use + +.. c:macro:: UV_EADDRNOTAVAIL + + address not available + +.. c:macro:: UV_EAFNOSUPPORT + + address family not supported + +.. c:macro:: UV_EAGAIN + + resource temporarily unavailable + +.. c:macro:: UV_EAI_ADDRFAMILY + + address family not supported + +.. c:macro:: UV_EAI_AGAIN + + temporary failure + +.. c:macro:: UV_EAI_BADFLAGS + + bad ai_flags value + +.. c:macro:: UV_EAI_BADHINTS + + invalid value for hints + +.. c:macro:: UV_EAI_CANCELED + + request canceled + +.. c:macro:: UV_EAI_FAIL + + permanent failure + +.. c:macro:: UV_EAI_FAMILY + + ai_family not supported + +.. c:macro:: UV_EAI_MEMORY + + out of memory + +.. c:macro:: UV_EAI_NODATA + + no address + +.. c:macro:: UV_EAI_NONAME + + unknown node or service + +.. c:macro:: UV_EAI_OVERFLOW + + argument buffer overflow + +.. c:macro:: UV_EAI_PROTOCOL + + resolved protocol is unknown + +.. c:macro:: UV_EAI_SERVICE + + service not available for socket type + +.. c:macro:: UV_EAI_SOCKTYPE + + socket type not supported + +.. c:macro:: UV_EALREADY + + connection already in progress + +.. c:macro:: UV_EBADF + + bad file descriptor + +.. c:macro:: UV_EBUSY + + resource busy or locked + +.. c:macro:: UV_ECANCELED + + operation canceled + +.. c:macro:: UV_ECHARSET + + invalid Unicode character + +.. c:macro:: UV_ECONNABORTED + + software caused connection abort + +.. c:macro:: UV_ECONNREFUSED + + connection refused + +.. c:macro:: UV_ECONNRESET + + connection reset by peer + +.. c:macro:: UV_EDESTADDRREQ + + destination address required + +.. c:macro:: UV_EEXIST + + file already exists + +.. c:macro:: UV_EFAULT + + bad address in system call argument + +.. c:macro:: UV_EFBIG + + file too large + +.. c:macro:: UV_EHOSTUNREACH + + host is unreachable + +.. c:macro:: UV_EINTR + + interrupted system call + +.. c:macro:: UV_EINVAL + + invalid argument + +.. c:macro:: UV_EIO + + i/o error + +.. c:macro:: UV_EISCONN + + socket is already connected + +.. c:macro:: UV_EISDIR + + illegal operation on a directory + +.. c:macro:: UV_ELOOP + + too many symbolic links encountered + +.. c:macro:: UV_EMFILE + + too many open files + +.. c:macro:: UV_EMSGSIZE + + message too long + +.. c:macro:: UV_ENAMETOOLONG + + name too long + +.. c:macro:: UV_ENETDOWN + + network is down + +.. c:macro:: UV_ENETUNREACH + + network is unreachable + +.. c:macro:: UV_ENFILE + + file table overflow + +.. c:macro:: UV_ENOBUFS + + no buffer space available + +.. c:macro:: UV_ENODEV + + no such device + +.. c:macro:: UV_ENOENT + + no such file or directory + +.. c:macro:: UV_ENOMEM + + not enough memory + +.. c:macro:: UV_ENONET + + machine is not on the network + +.. c:macro:: UV_ENOPROTOOPT + + protocol not available + +.. c:macro:: UV_ENOSPC + + no space left on device + +.. c:macro:: UV_ENOSYS + + function not implemented + +.. c:macro:: UV_ENOTCONN + + socket is not connected + +.. c:macro:: UV_ENOTDIR + + not a directory + +.. c:macro:: UV_ENOTEMPTY + + directory not empty + +.. c:macro:: UV_ENOTSOCK + + socket operation on non-socket + +.. c:macro:: UV_ENOTSUP + + operation not supported on socket + +.. c:macro:: UV_EPERM + + operation not permitted + +.. c:macro:: UV_EPIPE + + broken pipe + +.. c:macro:: UV_EPROTO + + protocol error + +.. c:macro:: UV_EPROTONOSUPPORT + + protocol not supported + +.. c:macro:: UV_EPROTOTYPE + + protocol wrong type for socket + +.. c:macro:: UV_ERANGE + + result too large + +.. c:macro:: UV_EROFS + + read-only file system + +.. c:macro:: UV_ESHUTDOWN + + cannot send after transport endpoint shutdown + +.. c:macro:: UV_ESPIPE + + invalid seek + +.. c:macro:: UV_ESRCH + + no such process + +.. c:macro:: UV_ETIMEDOUT + + connection timed out + +.. c:macro:: UV_ETXTBSY + + text file is busy + +.. c:macro:: UV_EXDEV + + cross-device link not permitted + +.. c:macro:: UV_UNKNOWN + + unknown error + +.. c:macro:: UV_EOF + + end of file + +.. c:macro:: UV_ENXIO + + no such device or address + +.. c:macro:: UV_EMLINK + + too many links + + +API +--- + +.. c:function:: const char* uv_strerror(int err) + + Returns the error message for the given error code. + +.. c:function:: const char* uv_err_name(int err) + + Returns the error name for the given error code. diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst new file mode 100644 index 000000000..d2db40813 --- /dev/null +++ b/deps/uv/docs/src/fs.rst @@ -0,0 +1,259 @@ + +.. _fs: + +Filesystem operations +===================== + +libuv provides a wide variety of cross-platform sync and async filesystem +operations. All functions defined in this document take a callback, which is +allowed to be NULL. If the callback is NULL the request is completed synchronously, +otherwise it will be performed asynchronously. + +All file operations are run on the threadpool, see :ref:`threadpool` for information +on the threadpool size. + + +Data types +---------- + +.. c:type:: uv_fs_t + + Filesystem request type. + +.. c:type:: uv_stat_t + + Portable equivalent of `struct stat`. + + :: + + typedef struct { + uint64_t st_dev; + uint64_t st_mode; + uint64_t st_nlink; + uint64_t st_uid; + uint64_t st_gid; + uint64_t st_rdev; + uint64_t st_ino; + uint64_t st_size; + uint64_t st_blksize; + uint64_t st_blocks; + uint64_t st_flags; + uint64_t st_gen; + uv_timespec_t st_atim; + uv_timespec_t st_mtim; + uv_timespec_t st_ctim; + uv_timespec_t st_birthtim; + } uv_stat_t; + +.. c:type:: uv_fs_type + + Filesystem request type. + + :: + + typedef enum { + UV_FS_UNKNOWN = -1, + UV_FS_CUSTOM, + UV_FS_OPEN, + UV_FS_CLOSE, + UV_FS_READ, + UV_FS_WRITE, + UV_FS_SENDFILE, + UV_FS_STAT, + UV_FS_LSTAT, + UV_FS_FSTAT, + UV_FS_FTRUNCATE, + UV_FS_UTIME, + UV_FS_FUTIME, + UV_FS_CHMOD, + UV_FS_FCHMOD, + UV_FS_FSYNC, + UV_FS_FDATASYNC, + UV_FS_UNLINK, + UV_FS_RMDIR, + UV_FS_MKDIR, + UV_FS_MKDTEMP, + UV_FS_RENAME, + UV_FS_READDIR, + UV_FS_LINK, + UV_FS_SYMLINK, + UV_FS_READLINK, + UV_FS_CHOWN, + UV_FS_FCHOWN + } uv_fs_type; + +.. c:type:: uv_dirent_t + + Cross platform (reduced) equivalent of ``struct dirent``. + Used in :c:func:`uv_fs_readdir_next`. + + :: + + typedef enum { + UV_DIRENT_UNKNOWN, + UV_DIRENT_FILE, + UV_DIRENT_DIR, + UV_DIRENT_LINK, + UV_DIRENT_FIFO, + UV_DIRENT_SOCKET, + UV_DIRENT_CHAR, + UV_DIRENT_BLOCK + } uv_dirent_type_t; + + typedef struct uv_dirent_s { + const char* name; + uv_dirent_type_t type; + } uv_dirent_t; + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_loop_t* uv_fs_t.loop + + Loop that started this request and where completion will be reported. + Readonly. + +.. c:member:: uv_fs_type uv_fs_t.fs_type + + FS request type. + +.. c:member:: const char* uv_fs_t.path + + Path affecting the request. + +.. c:member:: ssize_t uv_fs_t.result + + Result of the request. < 0 means error, success otherwise. On requests such + as :c:func:`uv_fs_read` or :c:func:`uv_fs_write` it indicates the amount of + data that was read or written, respectively. + +.. c:member:: uv_stat_t uv_fs_t.statbuf + + Stores the result of :c:func:`uv_fs_stat` and other stat requests. + +.. c:member:: void* uv_fs_t.ptr + + Stores the result of :c:func:`uv_fs_readlink` and serves as an alias to + `statbuf`. + +.. seealso:: The :c:type:`uv_req_t` members also apply. + + +API +--- + +.. c:function:: void uv_fs_req_cleanup(uv_fs_t* req) + + Cleanup request. Must be called after a request is finished to deallocate + any memory libuv might have allocated. + +.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to ``close(2)``. + +.. c:function:: int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) + + Equivalent to ``open(2)``. + +.. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) + + Equivalent to ``preadv(2)``. + +.. c:function:: int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to ``unlink(2)``. + +.. c:function:: int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) + + Equivalent to ``pwritev(2)``. + +.. c:function:: int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) + + Equivalent to ``mkdir(2)``. + + .. note:: + `mode` is currently not implemented on Windows. + +.. c:function:: int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb) + + Equivalent to ``mkdtemp(3)``. + +.. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to ``rmdir(2)``. + +.. c:function:: int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) +.. c:function:: int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent) + + Equivalent to ``readdir(2)``, with a slightly different API. Once the callback + for the request is called, the user can use :c:func:`uv_fs_readdir_next` to + get `ent` populated with the next directory entry data. When there are no + more entries ``UV_EOF`` will be returned. + +.. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) +.. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) +.. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to ``(f/l)stat(2)``. + +.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) + + Equivalent to ``rename(2)``. + +.. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to ``fsync(2)``. + +.. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + Equivalent to ``fdatasync(2)``. + +.. c:function:: int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb) + + Equivalent to ``ftruncate(2)``. + +.. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) + + Limited equivalent to ``sendfile(2)``. + +.. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) +.. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb) + + Equivalent to ``(f)chmod(2)``. + +.. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) +.. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) + + Equivalent to ``(f)utime(s)(2)``. + +.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) + + Equivalent to ``link(2)``. + +.. c:function:: int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb) + + Equivalent to ``symlink(2)``. + + .. note:: + On Windows the `flags` parameter can be specified to control how the symlink will + be created: + + * ``UV_FS_SYMLINK_DIR``: indicates that `path` points to a directory. + + * ``UV_FS_SYMLINK_JUNCTION``: request that the symlink is created + using junktion points. + +.. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to ``readlink(2)``. + +.. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) +.. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) + + Equivalent to ``(f)chown(2)``. + + .. note:: + These functions are not implemented on Windows. + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. diff --git a/deps/uv/docs/src/fs_event.rst b/deps/uv/docs/src/fs_event.rst new file mode 100644 index 000000000..eeb6bfbcb --- /dev/null +++ b/deps/uv/docs/src/fs_event.rst @@ -0,0 +1,102 @@ + +.. _fs_event: + +:c:type:`uv_fs_event_t` --- FS Event handle +=========================================== + +FS Event handles allow the user to monitor a given path for changes, for example, +if the file was renamed or there was a generic change in it. This handle uses +the best backend for the job on each platform. + + +Data types +---------- + +.. c:type:: uv_fs_event_t + + FS Event handle type. + +.. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status) + + Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly + after the handle is started. If the handle was started with a directory the + `filename` parameter will be a relative path to a file contained in the directory. + The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements. + +.. c:type:: uv_fs_event + + Event types that :c:type:`uv_fs_event_t` handles monitor. + + :: + + enum uv_fs_event { + UV_RENAME = 1, + UV_CHANGE = 2 + }; + +.. c:type:: uv_fs_event_flags + + Flags that can be passed to :c:func:`uv_fs_event_start` to control its + behavior. + + :: + + enum uv_fs_event_flags { + /* + * By default, if the fs event watcher is given a directory name, we will + * watch for all events in that directory. This flags overrides this behavior + * and makes fs_event report only changes to the directory entry itself. This + * flag does not affect individual files watched. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_WATCH_ENTRY = 1, + /* + * By default uv_fs_event will try to use a kernel interface such as inotify + * or kqueue to detect events. This may not work on remote filesystems such + * as NFS mounts. This flag makes fs_event fall back to calling stat() on a + * regular interval. + * This flag is currently not implemented yet on any backend. + */ + UV_FS_EVENT_STAT = 2, + /* + * By default, event watcher, when watching directory, is not registering + * (is ignoring) changes in it's subdirectories. + * This flag will override this behaviour on platforms that support it. + */ + UV_FS_EVENT_RECURSIVE = 4 + }; + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) + + Initialize the handle. + +.. c:function:: int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) + + Start the handle with the given callback, which will watch the specified + `path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`. + +.. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle) + + Stop the handle, the callback will no longer be called. + +.. c:function:: int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) + + Get the path being monitored by the handle. The buffer must be preallocated + by the user. Returns 0 on success or an error code < 0 in case of failure. + On sucess, `buf` will contain the path and `len` its length. If the buffer + is not big enough UV_ENOBUFS will be returned and len will be set to the + required size. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/fs_poll.rst b/deps/uv/docs/src/fs_poll.rst new file mode 100644 index 000000000..2e64bfb70 --- /dev/null +++ b/deps/uv/docs/src/fs_poll.rst @@ -0,0 +1,65 @@ + +.. _fs_poll: + +:c:type:`uv_fs_poll_t` --- FS Poll handle +========================================= + +FS Poll handles allow the user to monitor a given path for changes. Unlike +:c:type:`uv_fs_event_t`, fs poll handles use `stat` to detect when a file has +changed so they can work on file systems where fs event handles can't. + + +Data types +---------- + +.. c:type:: uv_fs_poll_t + + FS Poll handle type. + +.. c:type:: void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr) + + Callback passed to :c:func:`uv_fs_poll_start` which will be called repeatedly + after the handle is started, when any change happens to the monitored path. + + The callback is invoked with `status < 0` if `path` does not exist + or is inaccessible. The watcher is *not* stopped but your callback is + not called again until something changes (e.g. when the file is created + or the error reason changes). + + When `status == 0`, the callback receives pointers to the old and new + :c:type:`uv_stat_t` structs. They are valid for the duration of the + callback only. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_fs_poll_start(uv_fs_poll_t* handle, uv_fs_poll_cb poll_cb, const char* path, unsigned int interval) + + Check the file at `path` for changes every `interval` milliseconds. + + .. note:: + For maximum portability, use multi-second intervals. Sub-second intervals will not detect + all changes on many file systems. + +.. c:function:: int uv_fs_poll_stop(uv_fs_poll_t* handle) + + Stop the handle, the callback will no longer be called. + +.. c:function:: int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buf, size_t* len) + + Get the path being monitored by the handle. The buffer must be preallocated + by the user. Returns 0 on success or an error code < 0 in case of failure. + On sucess, `buf` will contain the path and `len` its length. If the buffer + is not big enough UV_ENOBUFS will be returned and len will be set to the + required size. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/handle.rst b/deps/uv/docs/src/handle.rst new file mode 100644 index 000000000..ae8efb70d --- /dev/null +++ b/deps/uv/docs/src/handle.rst @@ -0,0 +1,172 @@ + +.. _handle: + +:c:type:`uv_handle_t` --- Base handle +===================================== + +`uv_handle_t` is the base type for all libuv handle types. + +Strcutures are aligned so that any libuv handle can be cast to `uv_handle_t`. +All API functions defined here work with any handle type. + + +Data types +---------- + +.. c:type:: uv_handle_t + + The base libuv handle type. + +.. c:type:: uv_any_handle + + Union of all handle types. + +.. c:type:: void (*uv_close_cb)(uv_handle_t* handle) + + Type definition for callback passed to :c:func:`uv_close`. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_loop_t* uv_handle_t.loop + + Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly. + +.. c:member:: void* uv_handle_t.data + + Space for user-defined arbitrary data. libuv does not use this field. + + +API +--- + +.. c:function:: int uv_is_active(const uv_handle_t* handle) + + Returns non-zero if the handle is active, zero if it's inactive. What + "active" means depends on the type of handle: + + - A uv_async_t handle is always active and cannot be deactivated, except + by closing it with uv_close(). + + - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that + deals with i/o - is active when it is doing something that involves i/o, + like reading, writing, connecting, accepting new connections, etc. + + - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has + been started with a call to uv_check_start(), uv_idle_start(), etc. + + Rule of thumb: if a handle of type `uv_foo_t` has a `uv_foo_start()` + function, then it's active from the moment that function is called. + Likewise, `uv_foo_stop()` deactivates the handle again. + +.. c:function:: int uv_is_closing(const uv_handle_t* handle) + + Returns non-zero if the handle is closing or closed, zero otherwise. + + .. note:: + This function should only be used between the initialization of the handle and the + arrival of the close callback. + +.. c:function:: void uv_close(uv_handle_t* handle, uv_close_cb close_cb) + + Request handle to be closed. `close_cb` will be called asynchronously after + this call. This MUST be called on each handle before memory is released. + + Handles that wrap file descriptors are closed immediately but + `close_cb` will still be deferred to the next iteration of the event loop. + It gives you a chance to free up any resources associated with the handle. + + In-progress requests, like uv_connect_t or uv_write_t, are cancelled and + have their callbacks called asynchronously with status=UV_ECANCELED. + +.. c:function:: void uv_ref(uv_handle_t* handle) + + Reference the given handle. References are idempotent, that is, if a handle + is already referenced calling this function again will have no effect. + + See :ref:`refcount`. + +.. c:function:: void uv_unref(uv_handle_t* handle) + + Un-reference the given handle. References are idempotent, that is, if a handle + is not referenced calling this function again will have no effect. + + See :ref:`refcount`. + +.. c:function:: int uv_has_ref(const uv_handle_t* handle) + + Returns non-zero if the handle referenced, zero otherwise. + + See :ref:`refcount`. + +.. c:function:: size_t uv_handle_size(uv_handle_type type) + + Returns the size of the given handle type. Useful for FFI binding writers + who don't want to know the structure layout. + + +Miscellaneous API functions +--------------------------- + +The following API functions take a :c:type:`uv_handle_t` argument but they work +just for some handle types. + +.. c:function:: int uv_send_buffer_size(uv_handle_t* handle, int* value) + + Gets or sets the size of the send buffer that the operating + system uses for the socket. + + If `*value` == 0, it will return the current send buffer size, + otherwise it will use `*value` to set the new send buffer size. + + This function works for TCP, pipe and UDP handles on Unix and for TCP and + UDP handles on Windows. + + .. note:: + Linux will set double the size and return double the size of the original set value. + +.. c:function:: int uv_recv_buffer_size(uv_handle_t* handle, int* value) + + Gets or sets the size of the receive buffer that the operating + system uses for the socket. + + If `*value` == 0, it will return the current receive buffer size, + otherwise it will use `*value` to set the new receive buffer size. + + This function works for TCP, pipe and UDP handles on Unix and for TCP and + UDP handles on Windows. + + .. note:: + Linux will set double the size and return double the size of the original set value. + +.. c:function:: int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) + + Gets the platform dependent file descriptor equivalent. + + The following handles are supported: TCP, pipes, TTY, UDP and poll. Passing + any other handle type will fail with `UV_EINVAL`. + + If a handle doesn't have an attached file descriptor yet or the handle + itself has been closed, this function will return `UV_EBADF`. + + .. warning:: + Be very careful when using this function. libuv assumes it's in control of the file + descriptor so any change to it may lead to malfunction. + + +.. _refcount: + +Reference counting +------------------ + +The libuv event loop (if run in the default mode) will run until there are no +active `and` referenced handles left. The user can force the loop to exit early +by unreferencing handles which are active, for example by calling :c:func:`uv_unref` +after calling :c:func:`uv_timer_start`. + +A handle can be referenced or unreferenced, the refcounting scheme doesn't use +a counter, so both operations are idempotent. + +All handles are referenced when active by default, see :c:func:`uv_is_active` +for a more detailed explanation on what being `active` involves. diff --git a/deps/uv/docs/src/idle.rst b/deps/uv/docs/src/idle.rst new file mode 100644 index 000000000..81f51d207 --- /dev/null +++ b/deps/uv/docs/src/idle.rst @@ -0,0 +1,54 @@ + +.. _idle: + +:c:type:`uv_idle_t` --- Idle handle +=================================== + +Idle handles will run the given callback once per loop iteration, right +before the :c:type:`uv_prepare_t` handles. + +.. note:: + The notable difference with prepare handles is that when there are active idle handles, + the loop will perform a zero timeout poll instead of blocking for i/o. + +.. warning:: + Despite the name, idle handles will get their callbacks called on every loop iteration, + not when the loop is actually "idle". + + +Data types +---------- + +.. c:type:: uv_idle_t + + Idle handle type. + +.. c:type:: void (*uv_idle_cb)(uv_idle_t* handle) + + Type definition for callback passed to :c:func:`uv_idle_start`. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_idle_init(uv_loop_t*, uv_idle_t* idle) + + Initialize the handle. + +.. c:function:: int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) + + Start the handle with the given callback. + +.. c:function:: int uv_idle_stop(uv_idle_t* idle) + + Stop the handle, the callback will no longer be called. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst new file mode 100644 index 000000000..112a0d04c --- /dev/null +++ b/deps/uv/docs/src/index.rst @@ -0,0 +1,84 @@ + +Welcome to the libuv API documentation +====================================== + +Overview +-------- + +libuv is a multi-platform support library with a focus on asynchronous I/O. It +was primarily developed for use by `Node.js`_, but it's also used by Mozilla's +`Rust language`_, `Luvit`_, `Julia`_, `pyuv`_, and `others`_. + +.. note:: + In case you find errors in this documentation you can help by sending + `pull requests <https://github.com/joyent/libuv>`_! + +.. _Node.js: http://nodejs.org +.. _Rust language: http://www.rust-lang.org +.. _Luvit: http://luvit.io +.. _Julia: http://julialang.org +.. _pyuv: https://github.com/saghul/pyuv +.. _others: https://github.com/joyent/libuv/wiki/Projects-that-use-libuv + + +Features +-------- + +* Full-featured event loop backed by epoll, kqueue, IOCP, event ports. +* Asynchronous TCP and UDP sockets +* Asynchronous DNS resolution +* Asynchronous file and file system operations +* File system events +* ANSI escape code controlled TTY +* IPC with socket sharing, using Unix domain sockets or named pipes (Windows) +* Child processes +* Thread pool +* Signal handling +* High resolution clock +* Threading and synchronization primitives + + +Downloads +--------- + +libuv can be downloaded from `here <http://dist.libuv.org/dist/>`_. + + +Installation +------------ + +Installation instructions can be found on `the README <https://github.com/joyent/libuv/blob/master/README.md>`_. + + +Documentation +------------- + +.. toctree:: + :maxdepth: 1 + + design + errors + loop + handle + request + timer + prepare + check + idle + async + poll + signal + process + stream + tcp + pipe + tty + udp + fs_event + fs_poll + fs + threadpool + dns + dll + threading + misc diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst new file mode 100644 index 000000000..bc2afe2ff --- /dev/null +++ b/deps/uv/docs/src/loop.rst @@ -0,0 +1,137 @@ + +.. _loop: + +:c:type:`uv_loop_t` --- Event loop +================================== + +The event loop is the central part of libuv's functionality. It takes care +of polling for i/o and scheduling callbacks to be run based on different sources +of events. + + +Data types +---------- + +.. c:type:: uv_loop_t + + Loop data type. + +.. c:type:: uv_run_mode + + Mode used to run the loop with :c:func:`uv_run`. + + :: + + typedef enum { + UV_RUN_DEFAULT = 0, + UV_RUN_ONCE, + UV_RUN_NOWAIT + } uv_run_mode; + +.. c:type:: void (*uv_walk_cb)(uv_handle_t* handle, void* arg) + + Type definition for callback passed to :c:func:`uv_walk`. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: void* uv_loop_t.data + + Space for user-defined arbitrary data. libuv does not use this field. + + +API +--- + +.. c:function:: int uv_loop_init(uv_loop_t* loop) + + Initializes the given `uv_loop_t` structure. + +.. c:function:: int uv_loop_close(uv_loop_t* loop) + + Closes all internal loop resources. This function must only be called once + the loop has finished its execution or it will return UV_EBUSY. After this + function returns the user shall free the memory allocated for the loop. + +.. c:function:: uv_loop_t* uv_default_loop(void) + + Returns the initialized default loop. It may return NULL in case of + allocation failture. + +.. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode) + + This function runs the event loop. It will act differently depending on the + specified mode: + + - UV_RUN_DEFAULT: Runs the event loop until there are no more active and + referenced handles or requests. Always returns zero. + - UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if + there are no pending callbacks. Returns zero when done (no active handles + or requests left), or non-zero if more callbacks are expected (meaning + you should run the event loop again sometime in the future). + - UV_RUN_NOWAIT: Poll for i/o once but don't block if there are no + pending callbacks. Returns zero if done (no active handles + or requests left), or non-zero if more callbacks are expected (meaning + you should run the event loop again sometime in the future). + +.. c:function:: int uv_loop_alive(const uv_loop_t* loop) + + Returns non-zero if there are active handles or request in the loop. + +.. c:function:: void uv_stop(uv_loop_t* loop) + + Stop the event loop, causing :c:func:`uv_run` to end as soon as + possible. This will happen not sooner than the next loop iteration. + If this function was called before blocking for i/o, the loop won't block + for i/o on this iteration. + +.. c:function:: size_t uv_loop_size(void) + + Returns the size of the `uv_loop_t` structure. Useful for FFI binding + writers who don't want to know the structure layout. + +.. c:function:: int uv_backend_fd(const uv_loop_t* loop) + + Get backend file descriptor. Only kqueue, epoll and event ports are + supported. + + This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to + poll in one thread and run the event loop's callbacks in another see + test/test-embed.c for an example. + + .. note:: + Embedding a kqueue fd in another kqueue pollset doesn't work on all platforms. It's not + an error to add the fd but it never generates events. + +.. c:function:: int uv_backend_timeout(const uv_loop_t* loop) + + Get the poll timeout. The return value is in milliseconds, or -1 for no + timeout. + +.. c:function:: uint64_t uv_now(const uv_loop_t* loop) + + Return the current timestamp in milliseconds. The timestamp is cached at + the start of the event loop tick, see :c:func:`uv_update_time` for details + and rationale. + + The timestamp increases monotonically from some arbitrary point in time. + Don't make assumptions about the starting point, you will only get + disappointed. + + .. note:: + Use :c:func:`uv_hrtime` if you need sub-millisecond granularity. + +.. c:function:: void uv_update_time(uv_loop_t* loop) + + Update the event loop's concept of "now". Libuv caches the current time + at the start of the event loop tick in order to reduce the number of + time-related system calls. + + You won't normally need to call this function unless you have callbacks + that block the event loop for longer periods of time, where "longer" is + somewhat subjective but probably on the order of a millisecond or more. + +.. c:function:: void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) + + Walk the list of handles: `walk_cb` will be executed with the given `arg`. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst new file mode 100644 index 000000000..b313159db --- /dev/null +++ b/deps/uv/docs/src/misc.rst @@ -0,0 +1,228 @@ + +.. _misc: + +Miscelaneous utilities +====================== + +This section contains miscelaneous functions that don't really belong in any +other section. + + +Data types +---------- + +.. c:type:: uv_buf_t + + Buffer data type. + +.. c:type:: uv_file + + Cross platform representation of a file handle. + +.. c:type:: uv_os_sock_t + + Cross platform representation of a socket handle. + +.. c:type:: uv_os_fd_t + + Abstract representation of a file descriptor. On Unix systems this is a + `typedef` of `int` and on Windows fa `HANDLE`. + +.. c:type:: uv_rusage_t + + Data type for resource usage results. + + :: + + typedef struct { + uv_timeval_t ru_utime; /* user CPU time used */ + uv_timeval_t ru_stime; /* system CPU time used */ + uint64_t ru_maxrss; /* maximum resident set size */ + uint64_t ru_ixrss; /* integral shared memory size */ + uint64_t ru_idrss; /* integral unshared data size */ + uint64_t ru_isrss; /* integral unshared stack size */ + uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_majflt; /* page faults (hard page faults) */ + uint64_t ru_nswap; /* swaps */ + uint64_t ru_inblock; /* block input operations */ + uint64_t ru_oublock; /* block output operations */ + uint64_t ru_msgsnd; /* IPC messages sent */ + uint64_t ru_msgrcv; /* IPC messages received */ + uint64_t ru_nsignals; /* signals received */ + uint64_t ru_nvcsw; /* voluntary context switches */ + uint64_t ru_nivcsw; /* involuntary context switches */ + } uv_rusage_t; + +.. c:type:: uv_cpu_info_t + + Data type for CPU information. + + :: + + typedef struct uv_cpu_info_s { + char* model; + int speed; + struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; + } cpu_times; + } uv_cpu_info_t; + +.. c:type:: uv_interface_address_t + + Data type for interface addresses. + + :: + + typedef struct uv_interface_address_s { + char* name; + char phys_addr[6]; + int is_internal; + union { + struct sockaddr_in address4; + struct sockaddr_in6 address6; + } address; + union { + struct sockaddr_in netmask4; + struct sockaddr_in6 netmask6; + } netmask; + } uv_interface_address_t; + + +API +--- + +.. c:function:: uv_handle_type uv_guess_handle(uv_file file) + + Used to detect what type of stream should be used with a given file + descriptor. Usually this will be used during initialization to guess the + type of the stdio streams. + + For ``isatty()`` functionality use this function and test for ``UV_TTY``. + +.. c:function:: unsigned int uv_version(void) + + Returns the libuv version packed into a single integer. 8 bits are used for + each component, with the patch number stored in the 8 least significant + bits. E.g. for libuv 1.2.3 this would return 0x010203. + +.. c:function:: const char* uv_version_string(void) + + Returns the libuv version number as a string. For non-release versions + "-pre" is appended, so the version number could be "1.2.3-pre". + +.. c:function:: uv_buf_t uv_buf_init(char* base, unsigned int len) + + Constructor for :c:type:`uv_buf_t`. + + Due to platform differences the user cannot rely on the ordering of the + `base` and `len` members of the uv_buf_t struct. The user is responsible for + freeing `base` after the uv_buf_t is done. Return struct passed by value. + +.. c:function:: char** uv_setup_args(int argc, char** argv) + + Store the program arguments. Required for getting / setting the process title. + +.. c:function:: int uv_get_process_title(char* buffer, size_t size) + + Gets the title of the current process. + +.. c:function:: int uv_set_process_title(const char* title) + + Sets the current process title. + +.. c:function:: int uv_resident_set_memory(size_t* rss) + + Gets the resident set size (RSS) for the current process. + +.. c:function:: int uv_uptime(double* uptime) + + Gets the current system uptime. + +.. c:function:: int uv_getrusage(uv_rusage_t* rusage) + + Gets the resource usage measures for the current process. + + .. note:: + On Windows not all fields are set, the unsupported fields are filled with zeroes. + +.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) + + Gets information about the CPUs on the system. The `cpu_infos` array will + have `count` elements and needs to be freed with :c:func:`uv_free_cpu_info`. + +.. c:function:: void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) + + Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`. + +.. c:function:: int uv_interface_addresses(uv_interface_address_t** addresses, int* count) + + Gets address information about the network interfaces on the system. An + array of `count` elements is allocated and returned in `addresses`. It must + be freed by the user, calling :c:func:`uv_free_interface_addresses`. + +.. c:function:: void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) + + Free an array of :c:type:`uv_interface_address_t` which was returned by + :c:func:`uv_interface_addresses`. + +.. c:function:: void uv_loadavg(double avg[3]) + + Gets the load average. See: http://en.wikipedia.org/wiki/Load_(computing) + + .. note:: + Returns [0,0,0] on Windows (i.e., it's not implemented). + +.. c:function:: int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) + + Convert a string containing an IPv4 addresses to a binary structure. + +.. c:function:: int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) + + Convert a string containing an IPv6 addresses to a binary structure. + +.. c:function:: int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) + + Convert a binary structure containing an IPv4 addres to a string. + +.. c:function:: int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) + + Convert a binary structure containing an IPv6 addres to a string. + +.. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size) +.. c:function:: int uv_inet_pton(int af, const char* src, void* dst) + + Cross-platform IPv6-capable implementation of the 'standard' ``inet_ntop()`` + and ``inet_pton()`` functions. On success they return 0. In case of error + the target `dst` pointer is unmodified. + +.. c:function:: int uv_exepath(char* buffer, size_t* size) + + Gets the executable path. + +.. c:function:: int uv_cwd(char* buffer, size_t* size) + + Gets the current working directory. + +.. c:function:: int uv_chdir(const char* dir) + + Changes the current working directory. + +.. uint64_t uv_get_free_memory(void) +.. c:function:: uint64_t uv_get_total_memory(void) + + Gets memory information (in bytes). + +.. c:function:: uint64_t uv_hrtime(void) + + Returns the current high-resolution real time. This is expressed in + nanoseconds. It is relative to an arbitrary time in the past. It is not + related to the time of day and therefore not subject to clock drift. The + primary use is for measuring performance between intervals. + + .. note:: + Not every platform can support nanosecond resolution; however, this value will always + be in nanoseconds. diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst new file mode 100644 index 000000000..9a4a19340 --- /dev/null +++ b/deps/uv/docs/src/pipe.rst @@ -0,0 +1,86 @@ + +.. _pipe: + +:c:type:`uv_pipe_t` --- Pipe handle +=================================== + +Pipe handles provide an abstraction over local domain sockets on Unix and named +pipes on Windows. + +:c:type:`uv_pipe_t` is a 'subclass' of :c:type:`uv_stream_t`. + + +Data types +---------- + +.. c:type:: uv_pipe_t + + Pipe handle type. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_stream_t` members also apply. + + +API +--- + +.. c:function:: int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc) + + Initialize a pipe handle. The `ipc` argument is a boolean to indicate if + this pipe will be used for handle passing between processes. + +.. c:function:: int uv_pipe_open(uv_pipe_t*, uv_file file) + + Open an existing file descriptor or HANDLE as a pipe. + + .. note:: + The user is responsible for setting the dile descriptor in non-blocking mode. + +.. c:function:: int uv_pipe_bind(uv_pipe_t* handle, const char* name) + + Bind the pipe to a file path (Unix) or a name (Windows). + + .. note:: + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between + 92 and 108 bytes. + +.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) + + Connect to the Unix domain socket or the named pipe. + + .. note:: + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between + 92 and 108 bytes. + +.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) + + 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. + +.. c:function:: void uv_pipe_pending_instances(uv_pipe_t* handle, int count) + + Set the number of pending pipe instance handles when the pipe server is + waiting for connections. + + .. note:: + This setting applies to Windows only. + +.. c:function:: int uv_pipe_pending_count(uv_pipe_t* handle) +.. c:function:: uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) + + Used to receive handles over IPC pipes. + + First - call :c:func:`uv_pipe_pending_count`, if it's > 0 then initialize + a handle of the given `type`, returned by :c:func:`uv_pipe_pending_type` + and call ``uv_accept(pipe, handle)``. + +.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst new file mode 100644 index 000000000..f34842256 --- /dev/null +++ b/deps/uv/docs/src/poll.rst @@ -0,0 +1,99 @@ + +.. _poll: + +:c:type:`uv_poll_t` --- Poll handle +=================================== + +Poll handles are used to watch file descriptors for readability and +writability, similar to the purpose of poll(2). + +The purpose of poll handles is to enable integrating external libraries that +rely on the event loop to signal it about the socket status changes, like +c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended; +:c:type:`uv_tcp_t`, :c:type:`uv_udp_t`, etc. provide an implementation that is faster and +more scalable than what can be achieved with :c:type:`uv_poll_t`, especially on +Windows. + +It is possible that poll handles occasionally signal that a file descriptor is +readable or writable even when it isn't. The user should therefore always +be prepared to handle EAGAIN or equivalent when it attempts to read from or +write to the fd. + +It is not okay to have multiple active poll handles for the same socket, this +can cause libuv to busyloop or otherwise malfunction. + +The user should not close a file descriptor while it is being polled by an +active poll handle. This can cause the handle to report an error, +but it might also start polling another socket. However the fd can be safely +closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`. + +.. note:: + On windows only sockets can be polled with poll handles. On Unix any file + descriptor that would be accepted by poll(2) can be used. + + +Data types +---------- + +.. c:type:: uv_poll_t + + Poll handle type. + +.. c:type:: void (*uv_poll_cb)(uv_poll_t* handle, int status, int events) + + Type definition for callback passed to :c:func:`uv_poll_start`. + +.. c:type:: uv_poll_event + + Poll event types + + :: + + enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2 + }; + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) + + Initialize the handle using a file descriptor. + +.. c:function:: int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket) + + Initialize the handle using a socket descriptor. On Unix this is identical + to :c:func:`uv_poll_init`. On windows it takes a SOCKET handle. + +.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) + + Starts polling the file descriptor. `events` is a bitmask consisting made up + of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback + will be called with `status` set to 0, and the detected events set on the + `events` field. + + If an error happens while polling, `status` will be < 0 and corresponds + with one of the UV_E* error codes (see :ref:`errors`). The user should + not close the socket while the handle is active. If the user does that + anyway, the callback *may* be called reporting an error status, but this + is **not** guaranteed. + + .. note:: + Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so + will update the events mask that is being watched for. + +.. c:function:: int uv_poll_stop(uv_poll_t* poll) + + Stop polling the file descriptor, the callback will no longer be called. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/prepare.rst b/deps/uv/docs/src/prepare.rst new file mode 100644 index 000000000..aca581558 --- /dev/null +++ b/deps/uv/docs/src/prepare.rst @@ -0,0 +1,46 @@ + +.. _prepare: + +:c:type:`uv_prepare_t` --- Prepare handle +========================================= + +Prepare handles will run the given callback once per loop iteration, right +before polling for i/o. + + +Data types +---------- + +.. c:type:: uv_prepare_t + + Prepare handle type. + +.. c:type:: void (*uv_prepare_cb)(uv_prepare_t* handle) + + Type definition for callback passed to :c:func:`uv_prepare_start`. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) + + Initialize the handle. + +.. c:function:: int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) + + Start the handle with the given callback. + +.. c:function:: int uv_prepare_stop(uv_prepare_t* prepare) + + Stop the handle, the callback will no longer be called. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/process.rst b/deps/uv/docs/src/process.rst new file mode 100644 index 000000000..fccfc00ca --- /dev/null +++ b/deps/uv/docs/src/process.rst @@ -0,0 +1,215 @@ + +.. _process: + +:c:type:`uv_process_t` --- Process handle +========================================= + +Process handles will spawn a new process and allow the user to control it and +establish communication channels with it using streams. + + +Data types +---------- + +.. c:type:: uv_process_t + + Process handle type. + +.. c:type:: uv_process_options_t + + Options for spawning the process (passed to :c:func:`uv_spawn`. + + :: + + typedef struct uv_process_options_s { + uv_exit_cb exit_cb; + const char* file; + char** args; + char** env; + const char* cwd; + unsigned int flags; + int stdio_count; + uv_stdio_container_t* stdio; + uv_uid_t uid; + uv_gid_t gid; + } uv_process_options_t; + +.. c:type:: void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal) + + Type definition for callback passed in :c:type:`uv_process_options_t` which + will indicate the exit status and the signal that caused the process to + terminate, if any. + +.. c:type:: uv_process_flags + + Flags to be set on the flags field of :c:type:`uv_process_options_t`. + + :: + + enum uv_process_flags { + /* + * Set the child process' user id. + */ + UV_PROCESS_SETUID = (1 << 0), + /* + * Set the child process' group id. + */ + UV_PROCESS_SETGID = (1 << 1), + /* + * Do not wrap any arguments in quotes, or perform any other escaping, when + * converting the argument list into a command line string. This option is + * only meaningful on Windows systems. On Unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2), + /* + * Spawn the child process in a detached state - this will make it a process + * group leader, and will effectively enable the child to keep running after + * the parent exits. Note that the child process will still keep the + * parent's event loop alive unless the parent process calls uv_unref() on + * the child's process handle. + */ + UV_PROCESS_DETACHED = (1 << 3), + /* + * Hide the subprocess console window that would normally be created. This + * option is only meaningful on Windows systems. On Unix it is silently + * ignored. + */ + UV_PROCESS_WINDOWS_HIDE = (1 << 4) + }; + +.. c:type:: uv_stdio_container_t + + Container for each stdio handle or fd passed to a child process. + + :: + + typedef struct uv_stdio_container_s { + uv_stdio_flags flags; + union { + uv_stream_t* stream; + int fd; + } data; + } uv_stdio_container_t; + +.. c:type:: uv_stdio_flags + + Flags specifying how a stdio should be transmitted to the child process. + + :: + + typedef enum { + UV_IGNORE = 0x00, + UV_CREATE_PIPE = 0x01, + UV_INHERIT_FD = 0x02, + UV_INHERIT_STREAM = 0x04, + /* + * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE + * determine the direction of flow, from the child process' perspective. Both + * flags may be specified to create a duplex data stream. + */ + UV_READABLE_PIPE = 0x10, + UV_WRITABLE_PIPE = 0x20 + } uv_stdio_flags; + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_process_t.pid + + The PID of the spawned process. It's set after calling :c:func:`uv_spawn`. + +.. note:: + The :c:type:`uv_handle_t` members also apply. + +.. c:member:: uv_process_options_t.exit_cb + + Callback called after the process exits. + +.. c:member:: uv_process_options_t.file + + Path pointing to the program to be executed. + +.. c:member:: uv_process_options_t.args + + Command line arguments. args[0] should be the path to the program. On + Windows this uses `CreateProcess` which concatenates the arguments into a + string this can cause some strange errors. See the + ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`. + +.. c:member:: uv_process_options_t.env + + Environment for the new process. If NULL the parents environment is used. + +.. c:member:: uv_process_options_t.cwd + + Current working directory for the subprocess. + +.. c:member:: uv_process_options_t.flags + + Various flags that control how :c:func:`uv_spawn` behaves. See + :c:type:`uv_process_flags`. + +.. c:member:: uv_process_options_t.stdio_count +.. c:member:: uv_process_options_t.stdio + + The `stdio` field points to an array of :c:type:`uv_stdio_container_t` + structs that describe the file descriptors that will be made available to + the child process. The convention is that stdio[0] points to stdin, + fd 1 is used for stdout, and fd 2 is stderr. + + .. note:: + On Windows file descriptors greater than 2 are available to the child process only if + the child processes uses the MSVCRT runtime. + +.. c:member:: uv_process_options_t.uid +.. c:member:: uv_process_options_t.gid + + Libuv can change the child process' user/group id. This happens only when + the appropriate bits are set in the flags fields. + + .. note:: + This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error + to ``UV_ENOTSUP``. + +.. c:member:: uv_stdio_container_t.flags + + Flags specifying how the stdio container should be passed to the child. See + :c:type:`uv_stdio_flags`. + +.. c:member:: uv_stdio_container_t.data + + Union containing either the stream or fd to be passed on to the child + process. + + +API +--- + +.. c:function:: void uv_disable_stdio_inheritance(void) + + Disables inheritance for file descriptors / handles that this process + inherited from its parent. The effect is that child processes spawned by + this process don't accidentally inherit these handles. + + It is recommended to call this function as early in your program as possible, + before the inherited file descriptors can be closed or duplicated. + + .. note:: + This function works on a best-effort basis: there is no guarantee that libuv can discover + all file descriptors that were inherited. In general it does a better job on Windows than + it does on Unix. + +.. c:function:: int uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options) + + Initializes the process handle and starts the process. If the process is + successfully spawned, this function will return 0. Otherwise, the + negative error code corresponding to the reason it couldn't spawn is + returned. + + Possible reasons for failing to spawn would include (but not be limited to) + the file to execute not existing, not having permissions to use the setuid or + setgid specified, or not having enough memory to allocate for the new + process. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/request.rst b/deps/uv/docs/src/request.rst new file mode 100644 index 000000000..29c127792 --- /dev/null +++ b/deps/uv/docs/src/request.rst @@ -0,0 +1,82 @@ + +.. _request: + +:c:type:`uv_req_t` --- Base request +=================================== + +`uv_req_t` is the base type for all libuv request types. + +Strcutures are aligned so that any libuv request can be cast to `uv_req_t`. +All API functions defined here work with any request type. + + +Data types +---------- + +.. c:type:: uv_req_t + + The base libuv request structure. + +.. c:type:: uv_any_req + + Union of all request types. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: void* uv_request_t.data + + Space for user-defined arbitrary data. libuv does not use this field. + +.. c:member:: uv_req_type uv_req_t.type + + Indicated the type of request. Readonly. + + :: + + typedef enum { + UV_UNKNOWN_REQ = 0, + UV_REQ, + UV_CONNECT, + UV_WRITE, + UV_SHUTDOWN, + UV_UDP_SEND, + UV_FS, + UV_WORK, + UV_GETADDRINFO, + UV_GETNAMEINFO, + UV_REQ_TYPE_PRIVATE, + UV_REQ_TYPE_MAX, + } uv_req_type; + + +API +--- + +.. c:function:: int uv_cancel(uv_req_t* req) + + Cancel a pending request. Fails if the request is executing or has finished + executing. + + Returns 0 on success, or an error code < 0 on failure. + + Only cancellation of :c:type:`uv_fs_t`, :c:type:`uv_getaddrinfo_t`, + :c:type:`uv_getnameinfo_t` and :c:type:`uv_work_t` requests is + currently supported. + + Cancelled requests have their callbacks invoked some time in the future. + It's **not** safe to free the memory associated with the request until the + callback is called. + + Here is how cancellation is reported to the callback: + + * A :c:type:`uv_fs_t` request has its req->result field set to `UV_ECANCELED`. + + * A :c:type:`uv_work_t`, :c:type:`uv_getaddrinfo_t` or c:type:`uv_getnameinfo_t` + request has its callback invoked with status == `UV_ECANCELED`. + +.. c:function:: size_t uv_req_size(uv_req_type type) + + Returns the size of the given request type. Useful for FFI binding writers + who don't want to know the structure layout. diff --git a/deps/uv/docs/src/signal.rst b/deps/uv/docs/src/signal.rst new file mode 100644 index 000000000..21675945f --- /dev/null +++ b/deps/uv/docs/src/signal.rst @@ -0,0 +1,77 @@ + +.. _signal: + +:c:type:`uv_signal_t` --- Signal handle +======================================= + +Signal handles implement Unix style signal handling on a per-event loop bases. + +Reception of some signals is emulated on Windows: + +* SIGINT is normally delivered when the user presses CTRL+C. However, like + on Unix, it is not generated when terminal raw mode is enabled. + +* SIGBREAK is delivered when the user pressed CTRL + BREAK. + +* SIGHUP is generated when the user closes the console window. On SIGHUP the + program is given approximately 10 seconds to perform cleanup. After that + Windows will unconditionally terminate it. + +* SIGWINCH is raised whenever libuv detects that the console has been + resized. SIGWINCH is emulated by libuv when the program uses a :c:type:`uv_tty_t` + handle to write to the console. SIGWINCH may not always be delivered in a + timely manner; libuv will only detect size changes when the cursor is + being moved. When a readable :c:type:`uv_tty_t` handle is used in raw mode, + resizing the console buffer will also trigger a SIGWINCH signal. + +Watchers for other signals can be successfully created, but these signals +are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, +`SIGTERM` and `SIGKILL.` + +Calls to raise() or abort() to programmatically raise a signal are +not detected by libuv; these will not trigger a signal watcher. + +.. note:: + On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to + manage threads. Installing watchers for those signals will lead to unpredictable behavior + and is strongly discouraged. Future versions of libuv may simply reject them. + + +Data types +---------- + +.. c:type:: uv_signal_t + + Signal handle type. + +.. c:type:: void (*uv_signal_cb)(uv_signal_t* handle, int signum) + + Type definition for callback passed to :c:func:`uv_signal_start`. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: int uv_signal_t.signum + + Signal being monitored by this handle. Readonly. + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_signal_init(uv_loop_t*, uv_signal_t* signal) + + Initialize the handle. + +.. c:function:: int uv_signal_start(uv_signal_t* signal, uv_signal_cb cb, int signum) + + Start the handle with the given callback, watching for the given signal. + +.. c:function:: int uv_signal_stop(uv_signal_t* signal) + + Stop the handle, the callback will no longer be called. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/static/architecture.png b/deps/uv/docs/src/static/architecture.png Binary files differnew file mode 100644 index 000000000..81e8749f2 --- /dev/null +++ b/deps/uv/docs/src/static/architecture.png diff --git a/deps/uv/docs/src/static/diagrams.key/Data/st0-311.jpg b/deps/uv/docs/src/static/diagrams.key/Data/st0-311.jpg Binary files differnew file mode 100644 index 000000000..439f58109 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Data/st0-311.jpg diff --git a/deps/uv/docs/src/static/diagrams.key/Data/st1-475.jpg b/deps/uv/docs/src/static/diagrams.key/Data/st1-475.jpg Binary files differnew file mode 100644 index 000000000..ffb21ff22 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Data/st1-475.jpg diff --git a/deps/uv/docs/src/static/diagrams.key/Index.zip b/deps/uv/docs/src/static/diagrams.key/Index.zip Binary files differnew file mode 100644 index 000000000..17aedace1 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Index.zip diff --git a/deps/uv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist b/deps/uv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist new file mode 100644 index 000000000..39dd4fe62 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<array> + <string>Template: White (2014-02-28 09:41)</string> + <string>M6.2.2-1878-1</string> +</array> +</plist> diff --git a/deps/uv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/deps/uv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier new file mode 100644 index 000000000..ddb18f01f --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier @@ -0,0 +1 @@ +F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA
\ No newline at end of file diff --git a/deps/uv/docs/src/static/diagrams.key/Metadata/Properties.plist b/deps/uv/docs/src/static/diagrams.key/Metadata/Properties.plist Binary files differnew file mode 100644 index 000000000..74bc69317 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/Metadata/Properties.plist diff --git a/deps/uv/docs/src/static/diagrams.key/preview-micro.jpg b/deps/uv/docs/src/static/diagrams.key/preview-micro.jpg Binary files differnew file mode 100644 index 000000000..dd8decd63 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/preview-micro.jpg diff --git a/deps/uv/docs/src/static/diagrams.key/preview-web.jpg b/deps/uv/docs/src/static/diagrams.key/preview-web.jpg Binary files differnew file mode 100644 index 000000000..aadd401f1 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/preview-web.jpg diff --git a/deps/uv/docs/src/static/diagrams.key/preview.jpg b/deps/uv/docs/src/static/diagrams.key/preview.jpg Binary files differnew file mode 100644 index 000000000..fc80025a4 --- /dev/null +++ b/deps/uv/docs/src/static/diagrams.key/preview.jpg diff --git a/deps/uv/docs/src/static/favicon.ico b/deps/uv/docs/src/static/favicon.ico Binary files differnew file mode 100644 index 000000000..2c40694cd --- /dev/null +++ b/deps/uv/docs/src/static/favicon.ico diff --git a/deps/uv/docs/src/static/logo.png b/deps/uv/docs/src/static/logo.png Binary files differnew file mode 100644 index 000000000..eaf1eee57 --- /dev/null +++ b/deps/uv/docs/src/static/logo.png diff --git a/deps/uv/docs/src/static/loop_iteration.png b/deps/uv/docs/src/static/loop_iteration.png Binary files differnew file mode 100644 index 000000000..e769cf338 --- /dev/null +++ b/deps/uv/docs/src/static/loop_iteration.png diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst new file mode 100644 index 000000000..686efa1b3 --- /dev/null +++ b/deps/uv/docs/src/stream.rst @@ -0,0 +1,189 @@ + +.. _stream: + +:c:type:`uv_stream_t` --- Stream handle +======================================= + +Stream handles provide an abstraction of a duplex communication channel. +:c:type:`uv_stream_t` is an abstract type, libuv provides 3 stream implementations +in the for of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`. + + +Data types +---------- + +.. c:type:: uv_stream_t + + Stream handle type. + +.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) + + Callback called when data was read on a stream. + + `nread` is > 0 if there is data available, 0 if libuv is done reading for + now, or < 0 on error. + + The callee is responsible for stopping closing the stream when an error happens + by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read + from the stream again is undefined. + + The callee is responsible for freeing the buffer, libuv does not reuse it. + The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on + error. + +.. c:type:: void (*uv_write_cb)(uv_write_t* req, int status) + + Callback called after data was written on a stream. `status` will be 0 in + case of success, < 0 otherwise. + +.. c:type:: void (*uv_connect_cb)(uv_connect_t* req, int status) + + Callback called after a connection started by :c:func:`uv_connect` is done. + `status` will be 0 in case of success, < 0 otherwise. + +.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) + + Callback called after s shutdown request has been completed. `status` will + be 0 in case of success, < 0 otherwise. + +.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status) + + Callback called when a stream server has received an incoming connection. + The user can accept the connection by calling :c:func:`uv_accept`. + `status` will de 0 in case of success, < 0 otherwise. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: size_t uv_stream_t.write_queue_size + + Contains the amount of queued bytes waiting to be sent. Readonly. + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) + + Shutdown the outgoing (write) side of a duplex stream. It waits for pending + write requests to complete. The `handle` should refer to a initialized stream. + `req` should be an uninitialized shutdown request struct. The `cb` is called + after shutdown is complete. + +.. c:function:: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) + + Start listening for incoming connections. `backlog` indicates the number of + connections the kernel might queue, same as ``listen(2)``. When a new + incoming connection is received the :c:type:`uv_connection_cb` callback is + called. + +.. c:function:: int uv_accept(uv_stream_t* server, uv_stream_t* client) + + This call is used in conjunction with :c:func:`uv_listen` to accept incoming + connections. Call this function after receiving a :c:type:`uv_connection_cb` + to accept the connection. Before calling this function the client handle must + be initialized. < 0 return value indicates an error. + + When the :c:type:`uv_connection_cb` callback is called it is guaranteed that + this function will complete successfully the first time. If you attempt to use + it more than once, it may fail. It is suggested to only call this function once + per :c:type:`uv_connection_cb` call. + + .. note:: + `server` and `client` must be handles running on the same loop. + +.. c:function:: int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb) + + Read data from an incoming stream. The callback will be made several + times until there is no more data to read or :c:func:`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; + in that case `buf.len` and `buf.base` are both set to 0. + + .. note:: + `nread` might also be 0, which does *not* indicate an error or EOF, it happens when + libuv requested a buffer through the alloc callback but then decided that it didn't + need that buffer. + +.. c:function:: int uv_read_stop(uv_stream_t*) + + Stop reading data from the stream. The :c:type:`uv_read_cb` callback will + no longer be called. + +.. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb) + + Write data to stream. Buffers are written in order. Example: + + :: + + uv_buf_t a[] = { + { .base = "1", .len = 1 }, + { .base = "2", .len = 1 } + }; + + uv_buf_t b[] = { + { .base = "3", .len = 1 }, + { .base = "4", .len = 1 } + }; + + uv_write_t req1; + uv_write_t req2; + + /* writes "1234" */ + uv_write(&req1, stream, a, 2); + uv_write(&req2, stream, b, 2); + +.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) + + Extended write function for sending handles over a pipe. The pipe must be + initialized with `ipc` == 1. + + .. note:: + `send_handle` must be a TCP socket or pipe, which is a server or a connection (listening + or connected state). Bound sockets or pipes will be assumed to be servers. + +.. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs) + + Same as :c:func:`uv_write`, but won't queue a write request if it can't be + completed immediately. + + Will return either: + + * > 0: number of bytes written (can be less than the supplied buffer size). + * < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent + immediately). + +.. c:function:: int uv_is_readable(const uv_stream_t* handle) + + Returns 1 if the stream is readable, 0 otherwise. + +.. c:function:: int uv_is_writable(const uv_stream_t* handle) + + Returns 1 if the stream is writable, 0 otherwise. + +.. c:function:: int uv_stream_set_blocking(uv_stream_t* handle, int blocking) + + Enable or disable blocking mode for a stream. + + When blocking mode is enabled all writes complete synchronously. The + interface remains unchanged otherwise, e.g. completion or failure of the + operation will still be reported through a callback which is made + asychronously. + + .. warning:: + Relying too much on this API is not recommended. It is likely to change + significantly in the future. + + Currently this only works on Windows and only for + :c:type:`uv_pipe_t` handles. + + Also libuv currently makes no ordering guarantee when the blocking mode + is changed after write requests have already been submitted. Therefore it is + recommended to set the blocking mode immediately after opening or creating + the stream. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst new file mode 100644 index 000000000..2c1001b53 --- /dev/null +++ b/deps/uv/docs/src/tcp.rst @@ -0,0 +1,97 @@ + +.. _tcp: + +:c:type:`uv_tcp_t` --- TCP handle +================================= + +TCP handles are used to represent both TCP streams and servers. + +:c:type:`uv_tcp_t` is a 'subclass' of :c:type:`uv_stream_t`. + + +Data types +---------- + +.. c:type:: uv_tcp_t + + TCP handle type. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_stream_t` members also apply. + + +API +--- + +.. c:function:: int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle) + + Initialize the handle. + +.. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) + + Open an existing file descriptor or SOCKET as a TCP handle. + + .. note:: + The user is responsible for setting the file descriptor in + non-blocking mode. + +.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable) + + Enable / disable Nagle's algorithm. + +.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) + + Enable / disable TCP keep-alive. `delay` is the initial delay in seconds, + ignored when `enable` is zero. + +.. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) + + Enable / disable simultaneous asynchronous accept requests that are + queued by the operating system when listening for new TCP connections. + + This setting is used to tune a TCP server for the desired performance. + Having simultaneous accepts can significantly improve the rate of accepting + connections (which is why it is enabled by default) but may lead to uneven + load distribution in multi-process setups. + +.. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags) + + Bind the handle to an address and port. `addr` should point to an + initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``. + + When the port is already taken, you can expect to see an ``UV_EADDRINUSE`` + error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or + :c:func:`uv_tcp_connect`. That is, a successful call to this function does + not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` + will succeed as well. + + `flags` con contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support + is disabled and only IPv6 is used. + +.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) + + Get the current address to which the handle is bound. `addr` must point to + a valid and big enough chunk of memory, ``struct sockaddr_storage`` is + recommended for IPv4 and IPv6 support. + +.. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) + + Get the address of the peer connected to the handle. `addr` must point to + a valid and big enough chunk of memory, ``struct sockaddr_storage`` is + recommended for IPv4 and IPv6 support. + +.. c:function:: int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, uv_connect_cb cb) + + Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle + and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an + initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``. + + The callback is made when the connection has been established or when a + connection error happened. + +.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst new file mode 100644 index 000000000..38daf4e5a --- /dev/null +++ b/deps/uv/docs/src/threading.rst @@ -0,0 +1,156 @@ + +.. _threading: + +Threading and synchronization utilities +======================================= + +libuv provides cross-platform implementations for multiple threading and +synchronization primitives. The API largely follows the pthreads API. + + +Data types +---------- + +.. c:type:: uv_thread_t + + Thread data type. + +.. c:type:: void (*uv_thread_cb)(void* arg) + + Callback that is invoked to initialize thread execution. `arg` is the same + value that was passed to :c:func:`uv_thread_create`. + +.. c:type:: uv_key_t + + Thread-local key data type. + +.. c:type:: uv_once_t + + Once-only initializer data type. + +.. c:type:: uv_mutex_t + + Mutex data type. + +.. c:type:: uv_rwlock_t + + Read-write lock data type. + +.. c:type:: uv_sem_t + + Semaphore data type. + +.. c:type:: uv_cond_t + + Condition data type. + +.. c:type:: uv_barrier_t + + Barrier data type. + + +API +--- + +Threads +^^^^^^^ + +.. c:function:: int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg) +.. c:function:: unsigned long uv_thread_self(void) +.. c:function:: int uv_thread_join(uv_thread_t *tid) + +Thread-local storage +^^^^^^^^^^^^^^^^^^^^ + +.. note:: + The total thread-local storage size may be limited. That is, it may not be possible to + create many TLS keys. + +.. c:function:: int uv_key_create(uv_key_t* key) +.. c:function:: void uv_key_delete(uv_key_t* key) +.. c:function:: void* uv_key_get(uv_key_t* key) +.. c:function:: void uv_key_set(uv_key_t* key, void* value) + +Once-only initialization +^^^^^^^^^^^^^^^^^^^^^^^^ + +Runs a function once and only once. Concurrent calls to :c:func:`uv_once` with the +same guard will block all callers except one (it's unspecified which one). +The guard should be initialized statically with the UV_ONCE_INIT macro. + +.. c:function:: void uv_once(uv_once_t* guard, void (*callback)(void)) + +Mutex locks +^^^^^^^^^^^ + +Functions return 0 on success or an error code < 0 (unless the +return type is void, of course). + +.. c:function:: int uv_mutex_init(uv_mutex_t* handle) +.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle) +.. c:function:: void uv_mutex_lock(uv_mutex_t* handle) +.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle) +.. c:function:: void uv_mutex_unlock(uv_mutex_t* handle) + +Read-write locks +^^^^^^^^^^^^^^^^ + +Functions return 0 on success or an error code < 0 (unless the +return type is void, of course). + +.. c:function:: int uv_rwlock_init(uv_rwlock_t* rwlock) +.. c:function:: void uv_rwlock_destroy(uv_rwlock_t* rwlock) +.. c:function:: void uv_rwlock_rdlock(uv_rwlock_t* rwlock) +.. c:function:: int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) +.. c:function:: void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) +.. c:function:: void uv_rwlock_wrlock(uv_rwlock_t* rwlock) +.. c:function:: int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) +.. c:function:: void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) + +Semaphores +^^^^^^^^^^ + +Functions return 0 on success or an error code < 0 (unless the +return type is void, of course). + +.. c:function:: int uv_sem_init(uv_sem_t* sem, unsigned int value) +.. c:function:: void uv_sem_destroy(uv_sem_t* sem) +.. c:function:: void uv_sem_post(uv_sem_t* sem) +.. c:function:: void uv_sem_wait(uv_sem_t* sem) +.. c:function:: int uv_sem_trywait(uv_sem_t* sem) + +Conditions +^^^^^^^^^^ + +Functions return 0 on success or an error code < 0 (unless the +return type is void, of course). + +.. note:: + Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` and + :c:func:`uv_cond_timedwait`. + +.. c:function:: int uv_cond_init(uv_cond_t* cond) +.. c:function:: void uv_cond_destroy(uv_cond_t* cond) +.. c:function:: void uv_cond_signal(uv_cond_t* cond) +.. c:function:: void uv_cond_broadcast(uv_cond_t* cond) +.. c:function:: void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) +.. c:function:: int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) + +Barriers +^^^^^^^^ + +Functions return 0 on success or an error code < 0 (unless the +return type is void, of course). + +.. note:: + :c:func:`uv_barrier_wait` returns a value > 0 to an arbitrarily chosen "serializer" thread + to facilitate cleanup, i.e. + + :: + + if (uv_barrier_wait(&barrier) > 0) + uv_barrier_destroy(&barrier); + +.. c:function:: int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) +.. c:function:: void uv_barrier_destroy(uv_barrier_t* barrier) +.. c:function:: int uv_barrier_wait(uv_barrier_t* barrier) diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst new file mode 100644 index 000000000..875bb36ae --- /dev/null +++ b/deps/uv/docs/src/threadpool.rst @@ -0,0 +1,59 @@ + +.. _threadpool: + +Thread pool work scheduling +=========================== + +libuv provides a threadpool which can be used to run user code and get notified +in the loop thread. This thread pool is internally used to run al filesystem +operations, as well as getaddrinfo and getnameinfo requests. + +Its default size is 4, but it can be changed at startup time by setting the +``UV_THREADPOOL_SIZE`` environment variable to any value (the absolute maximum +is 128). + +The threadpool is global and shared across all event loops. + + +Data types +---------- + +.. c:type:: uv_work_t + + Work request type. + +.. c:type:: void (*uv_work_cb)(uv_work_t* req) + + Callback passed to :c:func:`uv_queue_work` which will be run on the thread + pool. + +.. c:type:: void (*uv_after_work_cb)(uv_work_t* req, int status) + + Callback passed to :c:func:`uv_queue_work` which will be called on the loop + thread after the work on the threadpool has been completed. If the work + was cancelled using :c:func:`uv_cancel` `status` will be ``UV_ECANCELED``. + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uv_loop_t* uv_work_t.loop + + Loop that started this request and where completion will be reported. + Readonly. + +.. seealso:: The :c:type:`uv_req_t` members also apply. + + +API +--- + +.. c:function:: int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb) + + Initializes a work request which will run the given `work_cb` in a thread + from the threadpool. Once `work_cb` is completed, `after_work_cb` will be + called on the loop thread. + + This request can be cancelled with :c:func:`uv_cancel`. + +.. seealso:: The :c:type:`uv_req_t` API functions also apply. diff --git a/deps/uv/docs/src/timer.rst b/deps/uv/docs/src/timer.rst new file mode 100644 index 000000000..e558704cb --- /dev/null +++ b/deps/uv/docs/src/timer.rst @@ -0,0 +1,68 @@ + +.. _timer: + +:c:type:`uv_timer_t` --- Timer handle +===================================== + +Timer handles are used to schedule callbacks to be called in the future. + + +Data types +---------- + +.. c:type:: uv_timer_t + + Timer handle type. + +.. c:type:: void (*uv_timer_cb)(uv_timer_t* handle) + + Type definition for callback passed to :c:func:`uv_timer_start`. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) + + Initialize the handle. + +.. c:function:: int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat) + + Start the timer. `timeout` and `repeat` are in milliseconds. + + If `timeout` is zero, the callback fires on the next event loop iteration. + If `repeat` is non-zero, the callback fires first after `timeout` + milliseconds and then repeatedly after `repeat` milliseconds. + +.. c:function:: int uv_timer_stop(uv_timer_t* handle) + + Stop the timer, the callback will not be called anymore. + +.. c:function:: int uv_timer_again(uv_timer_t* handle) + + Stop the timer, and if it is repeating restart it using the repeat value + as the timeout. If the timer has never been started before it returns + UV_EINVAL. + +.. c:function:: void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) + + Set the repeat value in milliseconds. + + .. note:: + If the repeat value is set from a timer callback it does not immediately take effect. + If the timer was non-repeating before, it will have been stopped. If it was repeating, + then the old repeat value will have been used to schedule the next timeout. + +.. c:function:: uint64_t uv_timer_get_repeat(const uv_timer_t* handle) + + Get the timer repeat value. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst new file mode 100644 index 000000000..8cb006632 --- /dev/null +++ b/deps/uv/docs/src/tty.rst @@ -0,0 +1,63 @@ + +.. _tty: + +:c:type:`uv_tty_t` --- TTY handle +================================= + +TTY handles represent a stream for the console. + +:c:type:`uv_tty_t` is a 'subclass' of :c:type:`uv_stream_t`. + + +Data types +---------- + +.. c:type:: uv_tty_t + + TTY handle type. + + +Public members +^^^^^^^^^^^^^^ + +N/A + +.. seealso:: The :c:type:`uv_stream_t` members also apply. + + +API +--- + +.. c:function:: int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable) + + Initialize a new TTY stream with the given file descriptor. Usually the + file descriptor will be: + + * 0 = stdin + * 1 = stdout + * 2 = stderr + + `readable`, specifies if you plan on calling :c:func:`uv_read_start` with + this stream. stdin is readable, stdout is not. + + .. note:: + TTY streams which are not readable have blocking writes. + +.. c:function:: int uv_tty_set_mode(uv_tty_t*, int mode) + + Set the TTY mode. 0 for normal, 1 for raw. + +.. c:function:: int uv_tty_reset_mode(void) + + To be called when the program exits. Resets TTY settings to default + values for the next process to take over. + + This function is async signal-safe on Unix platforms but can fail with error + code ``UV_EBUSY`` if you call it when execution is inside + :c:func:`uv_tty_set_mode`. + +.. c:function:: int uv_tty_get_winsize(uv_tty_t*, int* width, int* height) + + Gets the current Window size. On success it returns 0. + +.. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst new file mode 100644 index 000000000..175ce07a2 --- /dev/null +++ b/deps/uv/docs/src/udp.rst @@ -0,0 +1,280 @@ + +.. _udp: + +:c:type:`uv_udp_t` --- UDP handle +================================= + +UDP handles encapsulate UDP communication for both clients and servers. + + +Data types +---------- + +.. c:type:: uv_udp_t + + UDP handle type. + +.. c:type:: uv_udp_send_t + + UDP send request type. + +.. c:type:: uv_udp_flags + + Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`.. + + :: + + enum uv_udp_flags { + /* Disables dual stack mode. */ + UV_UDP_IPV6ONLY = 1, + /* + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ + UV_UDP_PARTIAL = 2, + /* + * Indicates if SO_REUSEADDR will be set when binding the handle in + * uv_udp_bind. + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + */ + UV_UDP_REUSEADDR = 4 + }; + +.. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status) + + Type definition for callback passed to :c:func:`uv_udp_send`, which is + called after the data was sent. + +.. c:type:: void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) + + Type definition for callback passed to :c:func:`uv_udp_recv_start`, which + is called when the endpoint receives data. + + * `handle`: UDP handle + * `nread`: Number of bytes that have been received. + 0 if there is no more data to read. You may discard or repurpose + the read buffer. Note that 0 may also mean that an empty datagram + was received (in this case `addr` is not NULL). < 0 if a transmission + error was detected. + * `buf`: :c:type:`uv_buf_t` with the received data. + * `addr`: ``struct sockaddr*`` containing the address of the sender. + Can be NULL. Valid for the duration of the callback only. + * `flags`: One or more or'ed UV_UDP_* constants. Right now only + ``UV_UDP_PARTIAL`` is used. + + .. note:: + The receive callback will be called with `nread` == 0 and `addr` == NULL when there is + nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is + received. + +.. c:type:: uv_membership + + Membership type for a multicast address. + + :: + + typedef enum { + UV_LEAVE_GROUP = 0, + UV_JOIN_GROUP + } uv_membership; + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: size_t uv_udp_t.send_queue_size + + Number of bytes queued for sending. This field strictly shows how much + information is currently queued. + +.. c:member:: size_t uv_udp_t.send_queue_count + + Number of send requests currently in the queue awaiting to be processed. + +.. c:member:: uv_udp_t* uv_udp_send_t.handle + + UDP handle where this send request is taking place. + +.. seealso:: The :c:type:`uv_handle_t` members also apply. + + +API +--- + +.. c:function:: int uv_udp_init(uv_loop_t*, uv_udp_t* handle) + + Initialize a new UDP handle. The actual socket is created lazily. + Returns 0 on success. + +.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) + + Opens an existing file descriptor or Windows SOCKET as a UDP handle. + + Unix only: + The only requirement of the `sock` argument is that it follows the datagram + contract (works in unconnected mode, supports sendmsg()/recvmsg(), etc). + In other words, other datagram-type sockets like raw sockets or netlink + sockets can also be passed to this function. + +.. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags) + + Bind the UDP handle to an IP address and port. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param addr: `struct sockaddr_in` or `struct sockaddr_in6` + with the address and port to bind to. + + :param flags: Indicate how the socket will be bound, + ``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen) + + Get the local IP and port of the UDP handle. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init` and bound. + + :param name: Pointer to the structure to be filled with the address data. + In order to support IPv4 and IPv6 `struct sockaddr_storage` should be + used. + + :param namelen: On input it indicates the data of the `name` field. On + output it indicates how much of it was filled. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership) + + Set membership for a multicast address + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param multicast_addr: Multicast address to set membership for. + + :param interface_addr: Interface address. + + :param membership: Should be ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) + + Set IP multicast loop flag. Makes multicast packets loop back to + local sockets. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param on: 1 for on, 0 for off. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) + + Set the multicast ttl. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param ttl: 1 through 255. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) + + Set the multicast interface to send or receive data on. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param interface_addr: interface address. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_broadcast(uv_udp_t* handle, int on) + + Set broadcast on or off. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param on: 1 for on, 0 for off. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_set_ttl(uv_udp_t* handle, int ttl) + + Set the time to live. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param ttl: 1 through 255. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb) + + Send data over the UDP socket. If the socket has not previously been bound + with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0 + (the "all interfaces" IPv4 address) and a random port number. + + :param req: UDP request handle. Need not be initialized. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param bufs: List of buffers to send. + + :param nbufs: Number of buffers in `bufs`. + + :param addr: `struct sockaddr_in` or `struct sockaddr_in6` with the + address and port of the remote peer. + + :param send_cb: Callback to invoke when the data has been sent out. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) + + Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't + be completed immediately. + + :returns: >= 0: number of bytes sent (it matches the given buffer size). + < 0: negative error code (``UV_EAGAIN`` is returned when the message + can't be sent immediately). + +.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) + + Prepare for receiving data. If the socket has not previously been bound + with :c:func:`uv_udp_bind` it is bound to 0.0.0.0 (the "all interfaces" + IPv4 address) and a random port number. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param alloc_cb: Callback to invoke when temporary storage is needed. + + :param recv_cb: Callback to invoke with received data. + + :returns: 0 on success, or an error code < 0 on failure. + +.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle) + + Stop listening for incoming datagrams. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :returns: 0 on success, or an error code < 0 on failure. + +.. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv-errno.h index 00b48609a..c34132795 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv-errno.h @@ -57,12 +57,6 @@ # define UV__EACCES (-4092) #endif -#if defined(EADDRINFO) && !defined(_WIN32) -# define UV__EADDRINFO EADDRINFO -#else -# define UV__EADDRINFO (-4091) -#endif - #if defined(EADDRINUSE) && !defined(_WIN32) # define UV__EADDRINUSE (-EADDRINUSE) #else diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index bbaaefc3e..e72492564 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -25,6 +25,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <dirent.h> #include <sys/socket.h> #include <netinet/in.h> @@ -117,13 +118,14 @@ struct uv__async { #endif /* Note: May be cast to struct iovec. See writev(2). */ -typedef struct { +typedef struct uv_buf_t { char* base; size_t len; } uv_buf_t; typedef int uv_file; typedef int uv_os_sock_t; +typedef int uv_os_fd_t; #define UV_ONCE_INIT PTHREAD_ONCE_INIT @@ -155,6 +157,47 @@ typedef pthread_barrier_t uv_barrier_t; typedef gid_t uv_gid_t; typedef uid_t uv_uid_t; +typedef struct dirent uv__dirent_t; + +#if defined(DT_UNKNOWN) +# define HAVE_DIRENT_TYPES +# if defined(DT_REG) +# define UV__DT_FILE DT_REG +# else +# define UV__DT_FILE -1 +# endif +# if defined(DT_DIR) +# define UV__DT_DIR DT_DIR +# else +# define UV__DT_DIR -2 +# endif +# if defined(DT_LNK) +# define UV__DT_LINK DT_LNK +# else +# define UV__DT_LINK -3 +# endif +# if defined(DT_FIFO) +# define UV__DT_FIFO DT_FIFO +# else +# define UV__DT_FIFO -4 +# endif +# if defined(DT_SOCK) +# define UV__DT_SOCKET DT_SOCK +# else +# define UV__DT_SOCKET -5 +# endif +# if defined(DT_CHR) +# define UV__DT_CHAR DT_CHR +# else +# define UV__DT_CHAR -6 +# endif +# if defined(DT_BLK) +# define UV__DT_BLOCK DT_BLK +# else +# define UV__DT_BLOCK -7 +# endif +#endif + /* Platform-specific definitions for uv_dlopen support. */ #define UV_DYNAMIC /* empty */ @@ -176,7 +219,7 @@ typedef struct { uv_async_t wq_async; \ uv_rwlock_t cloexec_lock; \ uv_handle_t* closing_handles; \ - void* process_handles[1][2]; \ + void* process_handles[2]; \ void* prepare_handles[2]; \ void* check_handles[2]; \ void* idle_handles[2]; \ diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index d33c8f8bd..a95f48b49 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -23,16 +23,17 @@ #define UV_VERSION_H /* - * Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI - * stable. When the minor version is odd, the API can change between patch - * releases. Make sure you update the -soname directives in configure.ac + * Versions with the same major number are ABI stable. API is allowed to + * evolve between minor releases, but only in a backwards compatible way. + * Make sure you update the -soname directives in configure.ac * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but * not UV_VERSION_PATCH.) */ -#define UV_VERSION_MAJOR 0 -#define UV_VERSION_MINOR 11 -#define UV_VERSION_PATCH 28 +#define UV_VERSION_MAJOR 1 +#define UV_VERSION_MINOR 0 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "rc1" #endif /* UV_VERSION_H */ diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 136b0b45d..293b41d08 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -39,6 +39,20 @@ typedef struct pollfd { } WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; #endif +#ifndef LOCALE_INVARIANT +# define LOCALE_INVARIANT 0x007f +#endif + +#ifndef _malloca +# if defined(_DEBUG) +# define _malloca(size) malloc(size) +# define _freea(ptr) free(ptr) +# else +# define _malloca(size) alloca(size) +# define _freea(ptr) +# endif +#endif + #include <mswsock.h> #include <ws2tcpip.h> #include <windows.h> @@ -215,8 +229,8 @@ typedef struct uv_buf_t { } uv_buf_t; typedef int uv_file; - typedef SOCKET uv_os_sock_t; +typedef HANDLE uv_os_fd_t; typedef HANDLE uv_thread_t; @@ -275,6 +289,19 @@ typedef struct uv_once_s { typedef unsigned char uv_uid_t; typedef unsigned char uv_gid_t; +typedef struct uv__dirent_s { + int d_type; + char d_name[1]; +} uv__dirent_t; + +#define UV__DT_DIR UV_DIRENT_DIR +#define UV__DT_FILE UV_DIRENT_FILE +#define UV__DT_LINK UV_DIRENT_LINK +#define UV__DT_FIFO UV_DIRENT_FIFO +#define UV__DT_SOCKET UV_DIRENT_SOCKET +#define UV__DT_CHAR UV_DIRENT_CHAR +#define UV__DT_BLOCK UV_DIRENT_BLOCK + /* Platform-specific definitions for uv_dlopen support. */ #define UV_DYNAMIC FAR WINAPI typedef struct { @@ -289,8 +316,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); HANDLE iocp; \ /* The current time according to the event loop. in msecs. */ \ uint64_t time; \ - /* GetTickCount() result when the event loop time was last updated. */ \ - DWORD last_tick_count; \ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ /* is empty, tail_ is NULL. If there is only one item, */ \ /* tail_->next_req == tail_ */ \ @@ -443,7 +468,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); int queue_len; \ } pending_ipc_info; \ uv_write_t* non_overlapped_writes_tail; \ - void* reserved; + uv_mutex_t readfile_mutex; \ + volatile HANDLE readfile_thread; #define UV_PIPE_PRIVATE_FIELDS \ HANDLE handle; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index df6d9549c..9ee9e9c42 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -227,6 +227,7 @@ typedef struct uv_work_s uv_work_t; /* None of the above. */ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; +typedef struct uv_dirent_s uv_dirent_t; typedef enum { @@ -236,180 +237,43 @@ typedef enum { } uv_run_mode; -/* - * Returns the libuv version packed into a single integer. 8 bits are used for - * each component, with the patch number stored in the 8 least significant - * bits. E.g. for libuv 1.2.3 this would return 0x010203. - */ UV_EXTERN unsigned int uv_version(void); - -/* - * Returns the libuv version number as a string. For non-release versions - * "-pre" is appended, so the version number could be "1.2.3-pre". - */ UV_EXTERN const char* uv_version_string(void); - -/* - * All functions besides uv_run() are non-blocking. - * - * All callbacks in libuv are made asynchronously. That is they are never - * made by the function that takes them as a parameter. - */ - -/* - * Returns the initialized default loop. It may return NULL in case of - * allocation failture. - */ UV_EXTERN uv_loop_t* uv_default_loop(void); - -/* - * Initializes a uv_loop_t structure. - */ UV_EXTERN int uv_loop_init(uv_loop_t* loop); - -/* - * Closes all internal loop resources. This function must only be called once - * the loop has finished it's execution or it will return UV_EBUSY. After this - * function returns the user shall free the memory allocated for the loop. - */ 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. */ 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. */ UV_EXTERN void uv_loop_delete(uv_loop_t*); - -/* - * Returns size of the loop struct, useful for dynamic lookup with FFI. - */ UV_EXTERN size_t uv_loop_size(void); - -/* - * This function runs the event loop. It will act differently depending on the - * specified mode: - * - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to - * zero. Always returns zero. - * - UV_RUN_ONCE: Poll for new events once. Note that this function blocks if - * there are no pending events. Returns zero when done (no active handles - * or requests left), or non-zero if more events are expected (meaning you - * should run the event loop again sometime in the future). - * - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no - * pending events. Returns zero when done (no active handles - * or requests left), or non-zero if more events are expected (meaning you - * should run the event loop again sometime in the future). - */ -UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); - -/* - * This function checks whether the reference count, the number of active - * handles or requests left in the event loop, is non-zero. - */ 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. - */ +UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); UV_EXTERN void uv_stop(uv_loop_t*); -/* - * Manually modify the event loop's reference count. Useful if the user wants - * to have a handle or timeout that doesn't keep the loop alive. - */ UV_EXTERN void uv_ref(uv_handle_t*); UV_EXTERN void uv_unref(uv_handle_t*); UV_EXTERN int uv_has_ref(const uv_handle_t*); -/* - * Update the event loop's concept of "now". Libuv caches the current time - * at the start of the event loop tick in order to reduce the number of - * time-related system calls. - * - * You won't normally need to call this function unless you have callbacks - * that block the event loop for longer periods of time, where "longer" is - * somewhat subjective but probably on the order of a millisecond or more. - */ UV_EXTERN void uv_update_time(uv_loop_t*); - -/* - * Return the current timestamp in milliseconds. The timestamp is cached at - * the start of the event loop tick, see |uv_update_time()| for details and - * rationale. - * - * The timestamp increases monotonically from some arbitrary point in time. - * Don't make assumptions about the starting point, you will only get - * disappointed. - * - * Use uv_hrtime() if you need sub-millisecond granularity. - */ UV_EXTERN uint64_t uv_now(const uv_loop_t*); -/* - * Get backend file descriptor. Only kqueue, epoll and event ports are - * supported. - * - * This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to - * poll in one thread and run the event loop's event callbacks in another. - * - * Useful for embedding libuv's event loop in another event loop. - * See test/test-embed.c for an example. - * - * Note that embedding a kqueue fd in another kqueue pollset doesn't work on - * all platforms. It's not an error to add the fd but it never generates - * events. - */ UV_EXTERN int uv_backend_fd(const uv_loop_t*); - -/* - * Get the poll timeout. The return value is in milliseconds, or -1 for no - * timeout. - */ UV_EXTERN int uv_backend_timeout(const uv_loop_t*); - -/* - * Should prepare a buffer that libuv can use to read data into. - * - * `suggested_size` is a hint. Returning a buffer that is smaller is perfectly - * okay as long as `buf.len > 0`. - * - * If you return a buffer with `buf.len == 0`, libuv skips the read and calls - * your read or recv callback with nread=UV_ENOBUFS. - * - * Note that returning a zero-length buffer does not stop the handle, call - * uv_read_stop() or uv_udp_recv_stop() for that. - */ typedef void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); - -/* - * `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 - * 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 - * error. - */ typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); @@ -463,12 +327,6 @@ typedef struct { } uv_stat_t; -/* -* This will be called repeatedly after the uv_fs_event_t is initialized. -* If uv_fs_event_t was initialized with a directory the filename parameter -* will be a relative path to a file contained in the directory. -* The events parameter is an ORed mask of enum uv_fs_event elements. -*/ typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, @@ -488,9 +346,6 @@ typedef enum { } uv_membership; -/* - * Most functions return 0 on success or an error code < 0 on failure. - */ UV_EXTERN const char* uv_strerror(int err); UV_EXTERN const char* uv_err_name(int err); @@ -502,6 +357,7 @@ UV_EXTERN const char* uv_err_name(int err); uv_req_type type; \ /* private */ \ void* active_queue[2]; \ + void* reserved[4]; \ UV_REQ_PRIVATE_FIELDS \ /* Abstract base class of all requests. */ @@ -514,14 +370,6 @@ struct uv_req_s { UV_PRIVATE_REQ_TYPES -/* - * 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. - */ UV_EXTERN int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb); @@ -543,6 +391,7 @@ struct uv_shutdown_s { /* private */ \ uv_close_cb close_cb; \ void* handle_queue[2]; \ + void* reserved[4]; \ UV_HANDLE_PRIVATE_FIELDS \ /* The abstract base class of all handles. */ @@ -550,66 +399,20 @@ 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. - */ UV_EXTERN size_t uv_handle_size(uv_handle_type type); - -/* - * Returns size of request types, useful for dynamic lookup with FFI. - */ UV_EXTERN size_t uv_req_size(uv_req_type type); -/* - * Returns non-zero if the handle is active, zero if it's inactive. - * - * What "active" means depends on the type of handle: - * - * - A uv_async_t handle is always active and cannot be deactivated, except - * by closing it with uv_close(). - * - * - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that - * deals with i/o - is active when it is doing something that involves i/o, - * like reading, writing, connecting, accepting new connections, etc. - * - * - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has - * been started with a call to uv_check_start(), uv_idle_start(), etc. - * - * Rule of thumb: if a handle of type uv_foo_t has a uv_foo_start() - * function, then it's active from the moment that function is called. - * Likewise, uv_foo_stop() deactivates the handle again. - * - */ UV_EXTERN int uv_is_active(const uv_handle_t* handle); -/* - * Walk the list of open handles. - */ UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); - -/* - * Request handle to be closed. close_cb will be called asynchronously after - * this call. This MUST be called on each handle before memory is released. - * - * Note that handles that wrap file descriptors are closed immediately but - * close_cb will still be deferred to the next iteration of the event loop. - * It gives you a chance to free up any resources associated with the handle. - * - * In-progress requests, like uv_connect_t or uv_write_t, are cancelled and - * have their callbacks called asynchronously with status=UV_ECANCELED. - */ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); +UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); +UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value); + +UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd); -/* - * 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. - */ UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); @@ -634,89 +437,24 @@ struct uv_stream_s { }; UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); - -/* - * This call is used in conjunction with uv_listen() to accept incoming - * connections. Call uv_accept after receiving a uv_connection_cb to accept - * 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 - * 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 - * 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. - * When we've reached EOF nread will be set to UV_EOF. - * - * When nread < 0, the buf parameter might not point to a valid buffer; - * in that case buf.len and buf.base are both set to 0. - * - * Note that nread might also be 0, which does *not* indicate an error or - * eof; it happens when libuv requested a buffer through the alloc callback - * but then decided that it didn't need that buffer. - */ UV_EXTERN int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb); - UV_EXTERN int uv_read_stop(uv_stream_t*); - -/* - * Write data to stream. Buffers are written in order. Example: - * - * uv_buf_t a[] = { - * { .base = "1", .len = 1 }, - * { .base = "2", .len = 1 } - * }; - * - * uv_buf_t b[] = { - * { .base = "3", .len = 1 }, - * { .base = "4", .len = 1 } - * }; - * - * uv_write_t req1; - * uv_write_t req2; - * - * // writes "1234" - * uv_write(&req1, stream, a, 2); - * uv_write(&req2, stream, b, 2); - * - */ UV_EXTERN int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); - -/* - * Extended write function for sending handles over a pipe. The pipe must be - * initialized with ipc == 1. - * send_handle must be a TCP socket or pipe, which is a server or a connection - * (listening or connected state). Bound sockets or pipes will be assumed to - * be servers. - */ UV_EXTERN int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb); - -/* - * 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 (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); @@ -731,40 +469,11 @@ struct uv_write_s { }; -/* - * Used to determine whether a stream is readable or writable. - */ UV_EXTERN int uv_is_readable(const uv_stream_t* handle); UV_EXTERN int uv_is_writable(const uv_stream_t* handle); - -/* - * Enable or disable blocking mode for a stream. - * - * When blocking mode is enabled all writes complete synchronously. The - * interface remains unchanged otherwise, e.g. completion or failure of the - * operation will still be reported through a callback which is made - * asychronously. - * - * Relying too much on this API is not recommended. It is likely to change - * significantly in the future. - * - * Currently this only works on Windows and only for uv_pipe_t handles. - * - * Also libuv currently makes no ordering guarantee when the blocking mode - * is changed after write requests have already been submitted. Therefore it is - * recommended to set the blocking mode immediately after opening or creating - * the stream. - */ 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. - */ UV_EXTERN int uv_is_closing(const uv_handle_t* handle); @@ -780,33 +489,11 @@ struct uv_tcp_s { }; UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle); - -/* - * Opens an existing file descriptor or SOCKET as a tcp handle. - */ UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock); - -/* Enable/disable Nagle's algorithm. */ UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); - -/* - * Enable/disable TCP keep-alive. - * - * `delay` is the initial delay in seconds, ignored when `enable` is zero. - */ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay); - -/* - * 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. - */ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); enum uv_tcp_flags { @@ -814,16 +501,6 @@ enum uv_tcp_flags { UV_TCP_IPV6ONLY = 1 }; -/* - * 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(). - * - * 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, unsigned int flags); @@ -833,15 +510,6 @@ UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle, UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen); - -/* - * Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle - * 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 - * connection error happened. - */ UV_EXTERN int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, @@ -879,31 +547,7 @@ enum uv_udp_flags { UV_UDP_REUSEADDR = 4 }; -/* - * Called after uv_udp_send(). status 0 indicates success otherwise error. - */ typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status); - -/* - * Callback that is invoked when a new UDP datagram is received. - * - * handle UDP handle. - * nread Number of bytes that have been received. - * - 0 if there is no more data to read. You may discard or repurpose - * the read buffer. Note that 0 may also mean that an empty datagram - * was received (in this case `addr` is not NULL). - * - < 0 if a transmission error was detected. - * buf uv_buf_t with the received data. - * addr struct sockaddr* containing the address of the sender. Can be NULL. - * Valid for the duration of the callback only. - * flags One or more OR'ed UV_UDP_* constants. Right now only UV_UDP_PARTIAL - * is used. - * - * NOTE: - * The receive callback will be called with nread == 0 and addr == NULL when - * there is nothing to read, and with nread == 0 and addr != NULL when an empty - * UDP packet is received. - */ typedef void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, @@ -934,44 +578,8 @@ struct uv_udp_send_s { UV_UDP_SEND_PRIVATE_FIELDS }; -/* - * Initialize a new UDP handle. The actual socket is created lazily. - * Returns 0 on success. - */ 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. - * This behavior is something of an anomaly and may be replaced by an explicit - * opt-in mechanism in future versions of libuv. - */ 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(). - * 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 - * UV_UDP_REUSEADDR are supported. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags); @@ -979,155 +587,29 @@ UV_EXTERN int uv_udp_bind(uv_udp_t* handle, UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen); - -/* - * Set membership for a multicast address - * - * 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. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership); - -/* - * Set IP multicast loop flag. Makes multicast packets loop back to - * local sockets. - * - * Arguments: - * handle UDP handle. Should have been initialized with - * uv_udp_init(). - * on 1 for on, 0 for off. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); - -/* - * Set the multicast ttl. - * - * Arguments: - * handle UDP handle. Should have been initialized with - * uv_udp_init(). - * ttl 1 through 255. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); - - -/* - * Set the multicast interface to send on. - * - * Arguments: - * handle UDP handle. Should have been initialized with - * uv_udp_init(). - * interface_addr interface address. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr); - -/* - * Set broadcast on or off. - * - * Arguments: - * handle UDP handle. Should have been initialized with - * uv_udp_init(). - * on 1 for on, 0 for off. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on); - -/* - * Set the time to live. - * - * Arguments: - * handle UDP handle. Should have been initialized with - * uv_udp_init(). - * ttl 1 through 255. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ 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. - * - * Arguments: - * req UDP request handle. Need not be initialized. - * 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 - * port of the remote peer. - * send_cb Callback to invoke when the data has been sent out. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb); - -/* - * 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(). - * alloc_cb Callback to invoke when temporary storage is needed. - * recv_cb Callback to invoke with received data. - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb); - -/* - * Stop listening for incoming datagrams. - * - * Arguments: - * handle UDP handle. Should have been initialized with uv_udp_init(). - * - * Returns: - * 0 on success, or an error code < 0 on failure. - */ UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); @@ -1142,45 +624,11 @@ struct uv_tty_s { UV_TTY_PRIVATE_FIELDS }; -/* - * Initialize a new TTY stream with the given file descriptor. Usually the - * 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. - * - * TTY streams which are not readable have blocking writes. - */ UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable); - -/* - * Set mode. 0 for normal, 1 for raw. - */ 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 - * code UV_EBUSY if you call it when execution is inside uv_tty_set_mode(). - */ UV_EXTERN int uv_tty_reset_mode(void); - -/* - * Gets the current Window size. On success zero is returned. - */ 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); /* @@ -1196,95 +644,21 @@ struct uv_pipe_s { UV_PIPE_PRIVATE_FIELDS }; -/* - * Initialize a pipe. The last argument is a boolean to indicate if - * this pipe will be used for handle passing between processes. - */ UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc); - -/* - * Opens an existing file descriptor or HANDLE as a pipe. - */ UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); - -/* - * Bind the pipe to a file path (Unix) or a name (Windows). - * - * 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. - * - * 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, uv_pipe_t* handle, const char* name, uv_connect_cb cb); - -/* - * 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. - */ UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len); - -/* - * This setting applies to Windows only. - * - * 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). - */ UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); -/* - * uv_poll_t is a subclass of uv_handle_t. - * - * The uv_poll watcher is used to watch file descriptors for readability and - * writability, similar to the purpose of poll(2). - * - * 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 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 - * be prepared to handle EAGAIN or equivalent when it attempts to read from or - * write to the fd. - * - * It is not okay to have multiple active uv_poll watchers for the same socket. - * This can cause libuv to busyloop or otherwise malfunction. - * - * The user should not close a file descriptor while it is being polled by an - * active uv_poll watcher. This can cause the poll watcher to report an error, - * 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 - * descriptor that would be accepted by poll(2) can be used with uv_poll. - */ + struct uv_poll_s { UV_HANDLE_FIELDS uv_poll_cb poll_cb; @@ -1296,124 +670,52 @@ enum uv_poll_event { UV_WRITABLE = 2 }; -/* 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. - */ UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket); - -/* - * Starts polling the file descriptor. `events` is a bitmask consisting made up - * of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback - * will be called with `status` set to 0, and the detected events set en the - * `events` field. - * - * If an error happens while polling status, `status` < 0 and corresponds - * with one of the UV_E* error codes. The user should not close the socket - * while uv_poll is active. If the user does that anyway, the callback *may* - * be called reporting an error status, but this is not guaranteed. - * - * Calling uv_poll_start on an uv_poll watcher that is already active is fine. - * Doing so will update the events mask that is being watched for. - */ UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb); - -/* Stops polling the file descriptor. */ UV_EXTERN int uv_poll_stop(uv_poll_t* handle); -/* - * uv_prepare_t is a subclass of uv_handle_t. - * - * Every active prepare handle gets its callback called exactly once per loop - * iteration, just before the system blocks to wait for completed i/o. - */ struct uv_prepare_s { UV_HANDLE_FIELDS UV_PREPARE_PRIVATE_FIELDS }; UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare); - UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb); - UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare); -/* - * uv_check_t is a subclass of uv_handle_t. - * - * Every active check handle gets its callback called exactly once per loop - * iteration, just after the system returns from blocking. - */ struct uv_check_s { UV_HANDLE_FIELDS UV_CHECK_PRIVATE_FIELDS }; UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check); - UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb); - UV_EXTERN int uv_check_stop(uv_check_t* check); -/* - * uv_idle_t is a subclass of uv_handle_t. - * - * Every active idle handle gets its callback called repeatedly until it is - * stopped. This happens after all other types of callbacks are processed. - * When there are multiple "idle" handles active, their callbacks are called - * in turn. - */ struct uv_idle_s { UV_HANDLE_FIELDS UV_IDLE_PRIVATE_FIELDS }; UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle); - UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb); - UV_EXTERN int uv_idle_stop(uv_idle_t* idle); -/* - * 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. - * - * 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 UV_ASYNC_PRIVATE_FIELDS }; -/* - * Initialize the uv_async_t handle. A NULL callback is allowed. - * - * Note that uv_async_init(), unlike other libuv functions, immediately - * starts the handle. To stop the handle again, close it with uv_close(). - */ UV_EXTERN int uv_async_init(uv_loop_t*, uv_async_t* async, uv_async_cb async_cb); - -/* - * This can be called from other threads to wake up a libuv thread. - */ UV_EXTERN int uv_async_send(uv_async_t* async); @@ -1428,37 +730,13 @@ struct uv_timer_s { }; UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle); - -/* - * Start the timer. `timeout` and `repeat` are in milliseconds. - * - * If timeout is zero, the callback fires on the next tick of the event loop. - * - * If repeat is non-zero, the callback fires first after timeout milliseconds - * and then repeatedly after repeat milliseconds. - */ UV_EXTERN int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat); - UV_EXTERN int uv_timer_stop(uv_timer_t* handle); - -/* - * Stop the timer, and if it is repeating restart it using the repeat value - * as the timeout. If the timer has never been started before it returns - * UV_EINVAL. - */ UV_EXTERN int uv_timer_again(uv_timer_t* handle); - -/* - * Set the repeat value in milliseconds. Note that if the repeat value is set - * from a timer callback it does not immediately take effect. If the timer was - * non-repeating before, it will have been stopped. If it was repeating, then - * the old repeat value will have been used to schedule the next timeout. - */ UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat); - UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle); @@ -1475,34 +753,12 @@ struct uv_getaddrinfo_s { }; -/* - * Asynchronous getaddrinfo(3). - * - * Either node or service may be NULL but not both. - * - * hints is a pointer to a struct addrinfo with additional address type - * constraints, or NULL. Consult `man -s 3 getaddrinfo` for details. - * - * Returns 0 on success or an error code < 0 on failure. - * - * If successful, your callback gets called sometime in the future with the - * lookup result, which is either: - * - * a) err == 0, the res argument points to a valid struct addrinfo, or - * b) err < 0, the res argument is NULL. See the UV_EAI_* constants. - * - * Call uv_freeaddrinfo() to free the addrinfo structure. - */ UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints); - -/* - * Free the struct addrinfo. Passing NULL is allowed and is a no-op. - */ UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai); @@ -1518,14 +774,6 @@ struct uv_getnameinfo_s { UV_GETNAMEINFO_PRIVATE_FIELDS }; -/* - * Asynchronous getnameinfo. - * - * Returns 0 on success or an error code < 0 on failure. - * - * If successful, your callback gets called sometime in the future with the - * lookup result. - */ UV_EXTERN int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, @@ -1651,46 +899,10 @@ struct uv_process_s { UV_PROCESS_PRIVATE_FIELDS }; -/* - * Initializes the uv_process_t and starts the process. If the process is - * successfully spawned, then this function will return 0. Otherwise, the - * negative error code corresponding to the reason it couldn't spawn is - * returned. - * - * Possible reasons for failing to spawn would include (but not be limited to) - * the file to execute not existing, not having permissions to use the setuid or - * setgid specified, or not having enough memory to allocate for the new - * process. - */ UV_EXTERN int uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options); - - -/* - * Kills the process with the specified signal. The user must still - * 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`, - * `uv_process_t.exit_signal` will be set to signum, so the process will appear - * to have been killed by `signum`. - */ UV_EXTERN int uv_process_kill(uv_process_t*, int signum); - - -/* Kills the process with the specified signal. - * - * Emulates some aspects of Unix signals on Windows: - * - SIGTERM, SIGKILL, and SIGINT call TerminateProcess() to unconditionally - * cause the target to exit with status 1. Unlike Unix, this cannot be caught - * or ignored (but see uv_process_kill() and uv_signal_start()). - * - Signal number `0` causes a check for target existence, as in Unix. Return - * value is 0 on existence, UV_ESRCH on non-existence. - * - * Returns 0 on success, or an error code on failure. UV_ESRCH is portably used - * for non-existence of target process, other errors may be system specific. - */ UV_EXTERN int uv_kill(int pid, int signum); @@ -1705,34 +917,11 @@ struct uv_work_s { UV_WORK_PRIVATE_FIELDS }; -/* Queues a work request to execute asynchronously on the thread pool. */ UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb); -/* Cancel a pending request. Fails if the request is executing or has finished - * executing. - * - * Returns 0 on success, or an error code < 0 on failure. - * - * Only cancellation of uv_fs_t, uv_getaddrinfo_t and uv_work_t requests is - * currently supported. - * - * Cancelled requests have their callbacks invoked some time in the future. - * It's _not_ safe to free the memory associated with the request until your - * callback is called. - * - * Here is how cancellation is reported to your callback: - * - * - A uv_fs_t request has its req->result field set to UV_ECANCELED. - * - * - 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, - * it always returns UV_ENOSYS. - */ UV_EXTERN int uv_cancel(uv_req_t* req); @@ -1762,6 +951,22 @@ struct uv_interface_address_s { } netmask; }; +typedef enum { + UV_DIRENT_UNKNOWN, + UV_DIRENT_FILE, + UV_DIRENT_DIR, + UV_DIRENT_LINK, + UV_DIRENT_FIFO, + UV_DIRENT_SOCKET, + UV_DIRENT_CHAR, + UV_DIRENT_BLOCK +} uv_dirent_type_t; + +struct uv_dirent_s { + const char* name; + uv_dirent_type_t type; +}; + UV_EXTERN char** uv_setup_args(int argc, char** argv); UV_EXTERN int uv_get_process_title(char* buffer, size_t size); UV_EXTERN int uv_set_process_title(const char* title); @@ -1792,41 +997,16 @@ typedef struct { uint64_t ru_nivcsw; /* involuntary context switches */ } uv_rusage_t; -/* - * Get information about OS resource utilization for the current process. - * Please note that not all uv_rusage_t struct fields will be filled on Windows. - */ 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(). - */ 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(). - */ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, - int* count); + int* count); UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count); + int count); -/* - * File System Methods. - * - * The uv_fs_* functions execute a blocking system call asynchronously (in a - * thread pool) and call the specified callback in the specified loop after - * completion. If the user gives NULL as the callback the blocking system - * call will be called synchronously. req should be a pointer to an - * uninitialized uv_fs_t object. - * - * uv_fs_req_cleanup() must be called after completion of the uv_fs_ - * function to free any internal memory allocations associated with the - * request. - */ typedef enum { UV_FS_UNKNOWN = -1, @@ -1873,69 +1053,113 @@ struct uv_fs_s { }; UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req); - -UV_EXTERN int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, - int flags, int mode, uv_fs_cb cb); - -UV_EXTERN int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, - const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb); - -UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, - const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb); - -UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, - int mode, uv_fs_cb cb); - -UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, - const char* path, int flags, uv_fs_cb cb); - -UV_EXTERN int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, uv_fs_cb cb); - -UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, - int64_t offset, uv_fs_cb cb); - -UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, - uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb); - -UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, - int mode, uv_fs_cb cb); - -UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, - double atime, double mtime, uv_fs_cb cb); - -UV_EXTERN int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, - double atime, double mtime, uv_fs_cb cb); - -UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, uv_fs_cb cb); +UV_EXTERN int uv_fs_close(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_open(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_read(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_unlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_write(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + const uv_buf_t bufs[], + unsigned int nbufs, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop, + uv_fs_t* req, + const char* tpl, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readdir_next(uv_fs_t* req, + uv_dirent_t* ent); +UV_EXTERN int uv_fs_stat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fstat(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_rename(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fsync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_fs_cb cb); +UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int64_t offset, + uv_fs_cb cb); +UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop, + uv_fs_t* req, + uv_file out_fd, + uv_file in_fd, + int64_t in_offset, + size_t length, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_utime(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_futime(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + double atime, + double mtime, + uv_fs_cb cb); +UV_EXTERN int uv_fs_lstat(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_link(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + uv_fs_cb cb); /* * This flag can be used with uv_fs_symlink() on Windows to specify whether @@ -1949,20 +1173,33 @@ UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, */ #define UV_FS_SYMLINK_JUNCTION 0x0002 -UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - const char* new_path, int flags, uv_fs_cb cb); - -UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_fs_cb cb); - -UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, - int mode, uv_fs_cb cb); - -UV_EXTERN int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, - uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); - -UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, - uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); +UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb); +UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + int mode, + uv_fs_cb cb); +UV_EXTERN int uv_fs_chown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); +UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, + uv_fs_t* req, + uv_file file, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); enum uv_fs_event { @@ -1989,77 +1226,14 @@ struct uv_fs_poll_s { }; UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle); - -/* - * Check the file at `path` for changes every `interval` milliseconds. - * - * Your callback is invoked with `status < 0` if `path` does not exist - * or is inaccessible. The watcher is *not* stopped but your callback is - * not called again until something changes (e.g. when the file is created - * or the error reason changes). - * - * When `status == 0`, your callback receives pointers to the old and new - * `uv_stat_t` structs. They are valid for the duration of the callback - * only! - * - * For maximum portability, use multi-second intervals. Sub-second intervals - * will not detect all changes on many file systems. - */ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, uv_fs_poll_cb poll_cb, const char* path, unsigned int interval); - UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); - -/* - * Get the path being monitored by the handle. The buffer must be preallocated - * by the user. Returns 0 on success or an error code < 0 in case of failure. - * On sucess, `buf` will contain the path and `len` its length. If the buffer - * is not big enough UV_ENOBUFS will be returned and len will be set to the - * required size. - */ 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 - * ultra efficient so don't go creating a million event loops with a million - * signal watchers. - * - * Note to Linux users: SIGRT0 and SIGRT1 (signals 32 and 33) are used by the - * NPTL pthreads library to manage threads. Installing watchers for those - * signals will lead to unpredictable behavior and is strongly discouraged. - * Future versions of libuv may simply reject them. - * - * Reception of some signals is emulated on Windows: - * - * SIGINT is normally delivered when the user presses CTRL+C. However, like - * on Unix, it is not generated when terminal raw mode is enabled. - * - * SIGBREAK is delivered when the user pressed CTRL+BREAK. - * - * SIGHUP is generated when the user closes the console window. On SIGHUP the - * program is given approximately 10 seconds to perform cleanup. After that - * Windows will unconditionally terminate it. - * - * SIGWINCH is raised whenever libuv detects that the console has been - * resized. SIGWINCH is emulated by libuv when the program uses an uv_tty_t - * handle to write to the console. SIGWINCH may not always be delivered in a - * timely manner; libuv will only detect size changes when the cursor is - * being moved. When a readable uv_tty_handle is used in raw mode, resizing - * the console buffer will also trigger a SIGWINCH signal. - * - * Watchers for other signals can be successfully created, but these signals - * are never received. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV, - * SIGTERM and SIGKILL. - * - * Note that calls to raise() or abort() to programmatically raise a signal are - * not detected by libuv; these will not trigger a signal watcher. - * - * See uv_process_kill() and uv_kill() for information about support for sending - * signals. - */ struct uv_signal_s { UV_HANDLE_FIELDS uv_signal_cb signal_cb; @@ -2068,21 +1242,11 @@ struct uv_signal_s { }; UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); - UV_EXTERN int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum); - UV_EXTERN int uv_signal_stop(uv_signal_t* handle); - -/* - * 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]); @@ -2118,118 +1282,48 @@ enum uv_fs_event_flags { UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle); - UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags); - UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle); - -/* - * Get the path being monitored by the handle. The buffer must be preallocated - * by the user. Returns 0 on success or an error code < 0 in case of failure. - * On sucess, `buf` will contain the path and `len` its length. If the buffer - * is not big enough UV_ENOBUFS will be returned and len will be set to the - * required size. - */ UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len); - -/* Utilities. */ - -/* 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. */ 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. - */ 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. */ UV_EXTERN int uv_exepath(char* buffer, size_t* size); -/* Gets the current working directory. */ UV_EXTERN int uv_cwd(char* buffer, size_t* size); -/* Changes the current working directory. */ UV_EXTERN int uv_chdir(const char* dir); -/* Gets memory info in bytes. */ UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); -/* - * Returns the current high-resolution real time. This is expressed in - * nanoseconds. It is relative to an arbitrary time in the past. It is not - * related to the time of day and therefore not subject to clock drift. The - * primary use is for measuring performance between intervals. - * - * Note not every platform can support nanosecond resolution; however, this - * value will always be in nanoseconds. - */ UV_EXTERN extern uint64_t uv_hrtime(void); - -/* - * Disables inheritance for file descriptors / handles that this process - * inherited from its parent. The effect is that child processes spawned by - * this process don't accidentally inherit these handles. - * - * It is recommended to call this function as early in your program as possible, - * before the inherited file descriptors can be closed or duplicated. - * - * Note 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. - */ 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. - */ UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); - -/* - * Close the shared library. - */ UV_EXTERN void uv_dlclose(uv_lib_t* lib); - -/* - * Retrieves a data pointer from a dynamic library. It is legal for a symbol to - * map to NULL. Returns 0 on success and -1 if the symbol was not found. - */ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); - -/* - * Returns the last uv_dlopen() or uv_dlsym() error message. - */ 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). - */ UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle); -/* - * Same goes for the read/write lock functions. - */ UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock); UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock); UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock); @@ -2239,80 +1333,33 @@ UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); -/* - * Same goes for the semaphore functions. - */ UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); UV_EXTERN void uv_sem_destroy(uv_sem_t* sem); UV_EXTERN void uv_sem_post(uv_sem_t* sem); UV_EXTERN void uv_sem_wait(uv_sem_t* sem); UV_EXTERN int uv_sem_trywait(uv_sem_t* sem); -/* - * Same goes for the condition variable functions. - */ UV_EXTERN int uv_cond_init(uv_cond_t* cond); UV_EXTERN void uv_cond_destroy(uv_cond_t* cond); UV_EXTERN void uv_cond_signal(uv_cond_t* cond); UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond); -/* - * Same goes for the barrier functions. Note that uv_barrier_wait() returns - * a value > 0 to an arbitrarily chosen "serializer" thread to facilitate - * cleanup, i.e.: - * - * if (uv_barrier_wait(&barrier) > 0) - * uv_barrier_destroy(&barrier); - */ 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. - * - * 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. - * 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. - */ -UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, - uint64_t timeout); +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 - * 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 - * pthread_key_create(), pthread_key_delete(), pthread_getspecific() and - * pthread_setspecific(). - * - * Note that the total thread-local storage size may be limited. - * That is, it may not be possible to create many TLS keys. - */ UV_EXTERN int uv_key_create(uv_key_t* key); UV_EXTERN void uv_key_delete(uv_key_t* key); UV_EXTERN void* uv_key_get(uv_key_t* key); UV_EXTERN void uv_key_set(uv_key_t* key, void* value); -/* - * Callback that is invoked to initialize thread execution. - * - * `arg` is the same value that was passed to uv_thread_create(). - */ typedef void (*uv_thread_cb)(void* arg); UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); diff --git a/deps/uv/m4/.gitignore b/deps/uv/m4/.gitignore index bde78f43f..9d0f4af88 100644 --- a/deps/uv/m4/.gitignore +++ b/deps/uv/m4/.gitignore @@ -1,2 +1,5 @@ # Ignore libtoolize-generated files. *.m4 +!as_case.m4 +!dtrace.m4 +!libuv-check-flags.m4
\ No newline at end of file diff --git a/deps/uv/m4/as_case.m4 b/deps/uv/m4/as_case.m4 new file mode 100644 index 000000000..c7ae0f0f5 --- /dev/null +++ b/deps/uv/m4/as_case.m4 @@ -0,0 +1,21 @@ +# AS_CASE(WORD, [PATTERN1], [IF-MATCHED1]...[DEFAULT]) +# ---------------------------------------------------- +# Expand into +# | case WORD in +# | PATTERN1) IF-MATCHED1 ;; +# | ... +# | *) DEFAULT ;; +# | esac +m4_define([_AS_CASE], +[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])], + [$#], 1, [ *) $1 ;;], + [$#], 2, [ $1) m4_default([$2], [:]) ;;], + [ $1) m4_default([$2], [:]) ;; +$0(m4_shiftn(2, $@))])dnl +]) +m4_defun([AS_CASE], +[m4_ifval([$2$3], +[case $1 in +_AS_CASE(m4_shift($@)) +esac])]) + diff --git a/deps/uv/m4/dtrace.m4 b/deps/uv/m4/dtrace.m4 new file mode 100644 index 000000000..09f7dc89c --- /dev/null +++ b/deps/uv/m4/dtrace.m4 @@ -0,0 +1,66 @@ +dnl Copyright (C) 2009 Sun Microsystems +dnl This file is free software; Sun Microsystems +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl --------------------------------------------------------------------------- +dnl Macro: PANDORA_ENABLE_DTRACE +dnl --------------------------------------------------------------------------- +AC_DEFUN([PANDORA_ENABLE_DTRACE],[ + AC_ARG_ENABLE([dtrace], + [AS_HELP_STRING([--disable-dtrace], + [enable DTrace USDT probes. @<:@default=yes@:>@])], + [ac_cv_enable_dtrace="$enableval"], + [ac_cv_enable_dtrace="yes"]) + + AS_IF([test "$ac_cv_enable_dtrace" = "yes"],[ + AC_CHECK_PROGS([DTRACE], [dtrace]) + AS_IF([test "x$ac_cv_prog_DTRACE" = "xdtrace"],[ + + AC_CACHE_CHECK([if dtrace works],[ac_cv_dtrace_works],[ + cat >conftest.d <<_ACEOF +provider Example { + probe increment(int); +}; +_ACEOF + $DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero + AS_IF([test $? -eq 0],[ac_cv_dtrace_works=yes], + [ac_cv_dtrace_works=no]) + rm -f conftest.h conftest.d + ]) + AS_IF([test "x$ac_cv_dtrace_works" = "xyes"],[ + AC_DEFINE([HAVE_DTRACE], [1], [Enables DTRACE Support]) + AC_CACHE_CHECK([if dtrace should instrument object files], + [ac_cv_dtrace_needs_objects],[ + dnl DTrace on MacOSX does not use -G option + cat >conftest.d <<_ACEOF +provider Example { + probe increment(int); +}; +_ACEOF + cat > conftest.c <<_ACEOF +#include "conftest.h" +void foo() { + EXAMPLE_INCREMENT(1); +} +_ACEOF + $DTRACE -h -o conftest.h -s conftest.d 2>/dev/zero + $CC -c -o conftest.o conftest.c + $DTRACE -G -o conftest.d.o -s conftest.d conftest.o 2>/dev/zero + AS_IF([test $? -eq 0],[ac_cv_dtrace_needs_objects=yes], + [ac_cv_dtrace_needs_objects=no]) + rm -f conftest.d.o conftest.d conftest.h conftest.o conftest.c + ]) + ]) + AC_SUBST(DTRACEFLAGS) dnl TODO: test for -G on OSX + ac_cv_have_dtrace=yes + ])]) + +AM_CONDITIONAL([HAVE_DTRACE], [test "x$ac_cv_dtrace_works" = "xyes"]) +AM_CONDITIONAL([DTRACE_NEEDS_OBJECTS], + [test "x$ac_cv_dtrace_needs_objects" = "xyes"]) + +]) +dnl --------------------------------------------------------------------------- +dnl End Macro: PANDORA_ENABLE_DTRACE +dnl --------------------------------------------------------------------------- diff --git a/deps/uv/m4/libuv-check-flags.m4 b/deps/uv/m4/libuv-check-flags.m4 new file mode 100644 index 000000000..59c306355 --- /dev/null +++ b/deps/uv/m4/libuv-check-flags.m4 @@ -0,0 +1,319 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2008 Diego Pettenà <flameeyes gmail com> +dnl Copyright (c) 2006-2008 xine project +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if the flag is supported by compiler +dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ + AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], + [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl Check if the flag is supported by compiler (cacheable) +dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) +dnl Check for CFLAG and appends them to CFLAGS if supported +AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) +]) + +dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) +AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ + for flag in $1; do + CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LANG_PUSH([C]) + AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + AC_LANG_POP([C]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable commandline, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_LANG_PUSH([C]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + AC_LANG_POP([C]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_LANG_PUSH([C]) + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + AC_LANG_POP([C]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_LANG_PUSH([C]) + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + AC_LANG_POP([C]) + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +])
\ No newline at end of file diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 871228fc8..0de15b173 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -60,6 +60,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, struct poll_ctx* ctx; uv_loop_t* loop; size_t len; + int err; if (uv__is_active(handle)) return 0; @@ -78,19 +79,25 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, ctx->parent_handle = handle; memcpy(ctx->path, path, len + 1); - if (uv_timer_init(loop, &ctx->timer_handle)) - abort(); + err = uv_timer_init(loop, &ctx->timer_handle); + if (err < 0) + goto error; ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; uv__handle_unref(&ctx->timer_handle); - if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb)) - abort(); + err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); + if (err < 0) + goto error; handle->poll_ctx = ctx; uv__handle_start(handle); return 0; + +error: + free(ctx); + return err; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 4770d8d8c..9dcc3935d 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -163,6 +163,33 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv__make_close_pending(handle); } +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int fd; + socklen_t len; + + if (handle == NULL || value == NULL) + return -EINVAL; + + if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) + fd = uv__stream_fd((uv_stream_t*) handle); + else if (handle->type == UV_UDP) + fd = ((uv_udp_t *) handle)->io_watcher.fd; + else + return -ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(fd, SOL_SOCKET, optname, value, &len); + else + r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); + + if (r < 0) + return -errno; + + return 0; +} void uv__make_close_pending(uv_handle_t* handle) { assert(handle->flags & UV_CLOSING); @@ -635,6 +662,36 @@ void uv_disable_stdio_inheritance(void) { } +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + int fd_out; + + switch (handle->type) { + case UV_TCP: + case UV_NAMED_PIPE: + case UV_TTY: + fd_out = uv__stream_fd((uv_stream_t*) handle); + break; + + case UV_UDP: + fd_out = ((uv_udp_t *) handle)->io_watcher.fd; + break; + + case UV_POLL: + fd_out = ((uv_poll_t *) handle)->io_watcher.fd; + break; + + default: + return -EINVAL; + } + + if (uv__is_closing(handle) || fd_out == -1) + return -EBADF; + + *fd = fd_out; + return 0; +} + + static void uv__run_pending(uv_loop_t* loop) { QUEUE* q; uv__io_t* w; diff --git a/deps/uv/src/unix/darwin-proctitle.c b/deps/uv/src/unix/darwin-proctitle.c index 8cd358bcf..b7267caa9 100644 --- a/deps/uv/src/unix/darwin-proctitle.c +++ b/deps/uv/src/unix/darwin-proctitle.c @@ -36,7 +36,7 @@ static int uv__pthread_setname_np(const char* name) { int err; /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ - dynamic_pthread_setname_np = dlsym(RTLD_DEFAULT, "pthread_setname_np"); + *(void **)(&dynamic_pthread_setname_np) = dlsym(RTLD_DEFAULT, "pthread_setname_np"); if (dynamic_pthread_setname_np == NULL) return -ENOSYS; @@ -94,13 +94,13 @@ int uv__set_process_title(const char* title) { if (application_services_handle == NULL || core_foundation_handle == NULL) goto out; - pCFStringCreateWithCString = + *(void **)(&pCFStringCreateWithCString) = dlsym(core_foundation_handle, "CFStringCreateWithCString"); - pCFBundleGetBundleWithIdentifier = + *(void **)(&pCFBundleGetBundleWithIdentifier) = dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier"); - pCFBundleGetDataPointerForName = + *(void **)(&pCFBundleGetDataPointerForName) = dlsym(core_foundation_handle, "CFBundleGetDataPointerForName"); - pCFBundleGetFunctionPointerForName = + *(void **)(&pCFBundleGetFunctionPointerForName) = dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName"); if (pCFStringCreateWithCString == NULL || @@ -118,14 +118,14 @@ int uv__set_process_title(const char* title) { if (launch_services_bundle == NULL) goto out; - pLSGetCurrentApplicationASN = + *(void **)(&pLSGetCurrentApplicationASN) = pCFBundleGetFunctionPointerForName(launch_services_bundle, S("_LSGetCurrentApplicationASN")); if (pLSGetCurrentApplicationASN == NULL) goto out; - pLSSetApplicationInformationItem = + *(void **)(&pLSSetApplicationInformationItem) = pCFBundleGetFunctionPointerForName(launch_services_bundle, S("_LSSetApplicationInformationItem")); @@ -138,9 +138,9 @@ int uv__set_process_title(const char* title) { if (display_name_key == NULL || *display_name_key == NULL) goto out; - pCFBundleGetInfoDictionary = dlsym(core_foundation_handle, + *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle, "CFBundleGetInfoDictionary"); - pCFBundleGetMainBundle = dlsym(core_foundation_handle, + *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle, "CFBundleGetMainBundle"); if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) goto out; @@ -152,13 +152,13 @@ int uv__set_process_title(const char* title) { if (hi_services_bundle == NULL) goto out; - pSetApplicationIsDaemon = pCFBundleGetFunctionPointerForName( + *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName( hi_services_bundle, S("SetApplicationIsDaemon")); - pLSApplicationCheckIn = pCFBundleGetFunctionPointerForName( + *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName( launch_services_bundle, S("_LSApplicationCheckIn")); - pLSSetApplicationLaunchServicesServerConnectionStatus = + *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) = pCFBundleGetFunctionPointerForName( launch_services_bundle, S("_LSSetApplicationLaunchServicesServerConnectionStatus")); diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 47f667229..2dd0fe97c 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -38,7 +38,6 @@ #include <sys/stat.h> #include <sys/time.h> #include <pthread.h> -#include <dirent.h> #include <unistd.h> #include <fcntl.h> #include <utime.h> @@ -296,9 +295,9 @@ done: #if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) -static int uv__fs_readdir_filter(struct dirent* dent) { +static int uv__fs_readdir_filter(uv__dirent_t* dent) { #else -static int uv__fs_readdir_filter(const struct dirent* dent) { +static int uv__fs_readdir_filter(const uv__dirent_t* dent) { #endif return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; } @@ -306,12 +305,8 @@ static int uv__fs_readdir_filter(const struct dirent* dent) { /* This should have been called uv__fs_scandir(). */ static ssize_t uv__fs_readdir(uv_fs_t* req) { - struct dirent **dents; + uv__dirent_t **dents; int saved_errno; - size_t off; - size_t len; - char *buf; - int i; int n; dents = NULL; @@ -322,32 +317,17 @@ static ssize_t uv__fs_readdir(uv_fs_t* req) { else if (n == -1) return n; - len = 0; - - for (i = 0; i < n; i++) - len += strlen(dents[i]->d_name) + 1; - - buf = malloc(len); - - if (buf == NULL) { - errno = ENOMEM; - n = -1; - goto out; - } - - off = 0; - - for (i = 0; i < n; i++) { - len = strlen(dents[i]->d_name) + 1; - memcpy(buf + off, dents[i]->d_name, len); - off += len; - } + /* NOTE: We will use nbufs as an index field */ + req->ptr = dents; + req->nbufs = 0; - req->ptr = buf; + return n; out: saved_errno = errno; if (dents != NULL) { + int i; + for (i = 0; i < n; i++) free(dents[i]); free(dents); @@ -1184,6 +1164,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; req->new_path = NULL; + if (req->fs_type == UV_FS_READDIR && req->ptr != NULL) + uv__fs_readdir_cleanup(req); + if (req->ptr != &req->statbuf) free(req->ptr); req->ptr = NULL; diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index 1c7896d8d..49085306b 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -525,7 +525,7 @@ static int uv__fsevents_global_init(void) { err = -ENOENT; #define V(handle, symbol) \ do { \ - p ## symbol = dlsym((handle), #symbol); \ + *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ if (p ## symbol == NULL) \ goto out; \ } \ diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index 1db00680d..f6c2de9b4 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -18,6 +18,13 @@ * IN THE SOFTWARE. */ +/* Expose glibc-specific EAI_* error codes. Needs to be defined before we + * include any headers. + */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + #include "uv.h" #include "internal.h" @@ -26,6 +33,66 @@ #include <stdlib.h> #include <string.h> +/* EAI_* constants. */ +#include <netdb.h> + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; +#endif +#if defined(EAI_AGAIN) + case EAI_AGAIN: return UV_EAI_AGAIN; +#endif +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: return UV_EAI_BADFLAGS; +#endif +#if defined(EAI_BADHINTS) + case EAI_BADHINTS: return UV_EAI_BADHINTS; +#endif +#if defined(EAI_CANCELED) + case EAI_CANCELED: return UV_EAI_CANCELED; +#endif +#if defined(EAI_FAIL) + case EAI_FAIL: return UV_EAI_FAIL; +#endif +#if defined(EAI_FAMILY) + case EAI_FAMILY: return UV_EAI_FAMILY; +#endif +#if defined(EAI_MEMORY) + case EAI_MEMORY: return UV_EAI_MEMORY; +#endif +#if defined(EAI_NODATA) + case EAI_NODATA: return UV_EAI_NODATA; +#endif +#if defined(EAI_NONAME) +# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME + case EAI_NONAME: return UV_EAI_NONAME; +# endif +#endif +#if defined(EAI_OVERFLOW) + case EAI_OVERFLOW: return UV_EAI_OVERFLOW; +#endif +#if defined(EAI_PROTOCOL) + case EAI_PROTOCOL: return UV_EAI_PROTOCOL; +#endif +#if defined(EAI_SERVICE) + case EAI_SERVICE: return UV_EAI_SERVICE; +#endif +#if defined(EAI_SOCKTYPE) + case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; +#endif +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: return -errno; +#endif + } + assert(!"unknown EAI_* error code"); + abort(); + return 0; /* Pacify compiler. */ +} + static void uv__getaddrinfo_work(struct uv__work* w) { uv_getaddrinfo_t* req; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 114cb696e..d5bc3109f 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -143,7 +143,7 @@ enum { UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ - UV_HANDLE_IPV6 = 0x2000 /* Handle is bound to a IPv6 socket. */ + UV_HANDLE_IPV6 = 0x10000 /* Handle is bound to a IPv6 socket. */ }; typedef enum { diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 5f6215998..7a4363049 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -149,6 +149,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int fd; int op; int i; + static int no_epoll_wait; if (loop->nfds == 0) { assert(QUEUE_EMPTY(&loop->watcher_queue)); @@ -195,10 +196,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { count = 48; /* Benchmarks suggest this gives the best throughput. */ for (;;) { - nfds = uv__epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); + if (!no_epoll_wait) { + nfds = uv__epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + if (nfds == -1 && errno == ENOSYS) { + no_epoll_wait = 1; + continue; + } + } else { + nfds = uv__epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + NULL); + } /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index aa74be645..002224855 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -99,7 +99,6 @@ void uv_loop_delete(uv_loop_t* loop) { static int uv__loop_init(uv_loop_t* loop, int default_loop) { - unsigned int i; int err; uv__signal_global_once_init(); @@ -138,9 +137,7 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) { uv_signal_init(loop, &loop->child_watcher); uv__handle_unref(&loop->child_watcher); loop->child_watcher.flags |= UV__HANDLE_INTERNAL; - - for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) - QUEUE_INIT(loop->process_handles + i); + QUEUE_INIT(&loop->process_handles); if (uv_rwlock_init(&loop->cloexec_lock)) abort(); diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index 7423a7107..5f1182f8b 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -38,6 +38,7 @@ #include <sys/resource.h> #include <sys/types.h> #include <sys/sysctl.h> +#include <uvm/uvm_extern.h> #include <unistd.h> #include <time.h> diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 52e4eb281..0aff5fd31 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -45,77 +45,65 @@ extern char **environ; #endif -static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) { - assert(pid > 0); - return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles); -} - - static void uv__chld(uv_signal_t* handle, int signum) { uv_process_t* process; uv_loop_t* loop; int exit_status; int term_signal; - unsigned int i; int status; pid_t pid; QUEUE pending; - QUEUE* h; QUEUE* q; + QUEUE* h; assert(signum == SIGCHLD); QUEUE_INIT(&pending); loop = handle->loop; - for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) { - h = loop->process_handles + i; - q = QUEUE_HEAD(h); + h = &loop->process_handles; + q = QUEUE_HEAD(h); + while (q != h) { + process = QUEUE_DATA(q, uv_process_t, queue); + q = QUEUE_NEXT(q); - while (q != h) { - process = QUEUE_DATA(q, uv_process_t, queue); - q = QUEUE_NEXT(q); + do + pid = waitpid(process->pid, &status, WNOHANG); + while (pid == -1 && errno == EINTR); - do - pid = waitpid(process->pid, &status, WNOHANG); - while (pid == -1 && errno == EINTR); - - if (pid == 0) - continue; - - if (pid == -1) { - if (errno != ECHILD) - abort(); - continue; - } + if (pid == 0) + continue; - process->status = status; - QUEUE_REMOVE(&process->queue); - QUEUE_INSERT_TAIL(&pending, &process->queue); + if (pid == -1) { + if (errno != ECHILD) + abort(); + continue; } - while (!QUEUE_EMPTY(&pending)) { - q = QUEUE_HEAD(&pending); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + process->status = status; + QUEUE_REMOVE(&process->queue); + QUEUE_INSERT_TAIL(&pending, &process->queue); + } - process = QUEUE_DATA(q, uv_process_t, queue); - uv__handle_stop(process); + QUEUE_FOREACH(q, &pending) { + process = QUEUE_DATA(q, uv_process_t, queue); + QUEUE_REMOVE(q); + uv__handle_stop(process); - if (process->exit_cb == NULL) - continue; + if (process->exit_cb == NULL) + continue; - exit_status = 0; - if (WIFEXITED(process->status)) - exit_status = WEXITSTATUS(process->status); + exit_status = 0; + if (WIFEXITED(process->status)) + exit_status = WEXITSTATUS(process->status); - term_signal = 0; - if (WIFSIGNALED(process->status)) - term_signal = WTERMSIG(process->status); + term_signal = 0; + if (WIFSIGNALED(process->status)) + term_signal = WTERMSIG(process->status); - process->exit_cb(process, exit_status, term_signal); - } + process->exit_cb(process, exit_status, term_signal); } + assert(QUEUE_EMPTY(&pending)); } @@ -369,7 +357,6 @@ int uv_spawn(uv_loop_t* loop, int signal_pipe[2] = { -1, -1 }; int (*pipes)[2]; int stdio_count; - QUEUE* q; ssize_t r; pid_t pid; int err; @@ -483,8 +470,7 @@ int uv_spawn(uv_loop_t* loop, /* Only activate this handle if exec() happened successfully */ if (exec_errorno == 0) { - q = uv__process_queue(loop, pid); - QUEUE_INSERT_TAIL(q, &process->queue); + QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); uv__handle_start(process); } @@ -526,7 +512,8 @@ int uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { - /* TODO stop signal watcher when this is the last handle */ QUEUE_REMOVE(&handle->queue); uv__handle_stop(handle); + if (QUEUE_EMPTY(&handle->loop->process_handles)) + uv_signal_stop(&handle->loop->child_watcher); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index ae7880c33..9c7d28cbf 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -53,6 +53,10 @@ struct uv__stream_select_s { int fake_fd; int int_fd; int fd; + fd_set* sread; + size_t sread_sz; + fd_set* swrite; + size_t swrite_sz; }; #endif /* defined(__APPLE__) */ @@ -127,8 +131,6 @@ static void uv__stream_osx_select(void* arg) { uv_stream_t* stream; uv__stream_select_t* s; char buf[1024]; - fd_set sread; - fd_set swrite; int events; int fd; int r; @@ -149,17 +151,17 @@ static void uv__stream_osx_select(void* arg) { break; /* Watch fd using select(2) */ - FD_ZERO(&sread); - FD_ZERO(&swrite); + memset(s->sread, 0, s->sread_sz); + memset(s->swrite, 0, s->swrite_sz); if (uv__io_active(&stream->io_watcher, UV__POLLIN)) - FD_SET(fd, &sread); + FD_SET(fd, s->sread); if (uv__io_active(&stream->io_watcher, UV__POLLOUT)) - FD_SET(fd, &swrite); - FD_SET(s->int_fd, &sread); + FD_SET(fd, s->swrite); + FD_SET(s->int_fd, s->sread); /* Wait indefinitely for fd events */ - r = select(max_fd + 1, &sread, &swrite, NULL, NULL); + r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL); if (r == -1) { if (errno == EINTR) continue; @@ -173,7 +175,7 @@ static void uv__stream_osx_select(void* arg) { continue; /* Empty socketpair's buffer in case of interruption */ - if (FD_ISSET(s->int_fd, &sread)) + if (FD_ISSET(s->int_fd, s->sread)) while (1) { r = read(s->int_fd, buf, sizeof(buf)); @@ -194,12 +196,12 @@ static void uv__stream_osx_select(void* arg) { /* Handle events */ events = 0; - if (FD_ISSET(fd, &sread)) + if (FD_ISSET(fd, s->sread)) events |= UV__POLLIN; - if (FD_ISSET(fd, &swrite)) + if (FD_ISSET(fd, s->swrite)) events |= UV__POLLOUT; - assert(events != 0 || FD_ISSET(s->int_fd, &sread)); + assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); if (events != 0) { ACCESS_ONCE(int, s->events) = events; @@ -261,6 +263,9 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { int ret; int kq; int old_fd; + int max_fd; + size_t sread_sz; + size_t swrite_sz; kq = kqueue(); if (kq == -1) { @@ -284,31 +289,48 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { return 0; /* At this point we definitely know that this fd won't work with kqueue */ - s = malloc(sizeof(*s)); - if (s == NULL) - return -ENOMEM; + + /* + * Create fds for io watcher and to interrupt the select() loop. + * NOTE: do it ahead of malloc below to allocate enough space for fd_sets + */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -errno; + + max_fd = *fd; + if (fds[1] > max_fd) + max_fd = fds[1]; + + sread_sz = (max_fd + NBBY) / NBBY; + swrite_sz = sread_sz; + + s = malloc(sizeof(*s) + sread_sz + swrite_sz); + if (s == NULL) { + err = -ENOMEM; + goto failed_malloc; + } s->events = 0; s->fd = *fd; + s->sread = (fd_set*) ((char*) s + sizeof(*s)); + s->sread_sz = sread_sz; + s->swrite = (fd_set*) ((char*) s->sread + sread_sz); + s->swrite_sz = swrite_sz; err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb); - if (err) { - free(s); - return err; - } + if (err) + goto failed_async_init; s->async.flags |= UV__HANDLE_INTERNAL; uv__handle_unref(&s->async); - if (uv_sem_init(&s->close_sem, 0)) - goto fatal1; - - if (uv_sem_init(&s->async_sem, 0)) - goto fatal2; + err = uv_sem_init(&s->close_sem, 0); + if (err != 0) + goto failed_close_sem_init; - /* Create fds for io watcher and to interrupt the select() loop. */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - goto fatal3; + err = uv_sem_init(&s->async_sem, 0); + if (err != 0) + goto failed_async_sem_init; s->fake_fd = fds[0]; s->int_fd = fds[1]; @@ -318,26 +340,36 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { stream->select = s; *fd = s->fake_fd; - if (uv_thread_create(&s->thread, uv__stream_osx_select, stream)) - goto fatal4; + err = uv_thread_create(&s->thread, uv__stream_osx_select, stream); + if (err != 0) + goto failed_thread_create; return 0; -fatal4: +failed_thread_create: s->stream = NULL; stream->select = NULL; *fd = old_fd; - uv__close(s->fake_fd); - uv__close(s->int_fd); - s->fake_fd = -1; - s->int_fd = -1; -fatal3: + uv_sem_destroy(&s->async_sem); -fatal2: + +failed_async_sem_init: uv_sem_destroy(&s->close_sem); -fatal1: + +failed_close_sem_init: + uv__close(fds[0]); + uv__close(fds[1]); uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); - return -errno; + return err; + +failed_async_init: + free(s); + +failed_malloc: + uv__close(fds[0]); + uv__close(fds[1]); + + return err; } #endif /* defined(__APPLE__) */ @@ -361,10 +393,22 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { } -void uv__stream_destroy(uv_stream_t* stream) { +void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { uv_write_t* req; QUEUE* q; + while (!QUEUE_EMPTY(&stream->write_queue)) { + q = QUEUE_HEAD(&stream->write_queue); + QUEUE_REMOVE(q); + req = QUEUE_DATA(q, uv_write_t, queue); + req->error = error; + + QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + } +} + + +void uv__stream_destroy(uv_stream_t* stream) { assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT)); assert(stream->flags & UV_CLOSED); @@ -374,16 +418,7 @@ void uv__stream_destroy(uv_stream_t* stream) { stream->connect_req = NULL; } - while (!QUEUE_EMPTY(&stream->write_queue)) { - q = QUEUE_HEAD(&stream->write_queue); - QUEUE_REMOVE(q); - - req = QUEUE_DATA(q, uv_write_t, queue); - req->error = -ECANCELED; - - QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); - } - + uv__stream_flush_write_queue(stream, -ECANCELED); uv__write_callbacks(stream); if (stream->shutdown_req) { @@ -537,7 +572,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { break; default: - assert(0); + return -EINVAL; } done: @@ -573,7 +608,6 @@ done: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { int err; - err = -EINVAL; switch (stream->type) { case UV_TCP: err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); @@ -584,7 +618,7 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { break; default: - assert(0); + err = -EINVAL; } if (err == 0) @@ -1163,7 +1197,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ - if (events & (UV__POLLIN | UV__POLLERR)) + if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) uv__read(stream); if (uv__stream_fd(stream) == -1) @@ -1233,10 +1267,21 @@ static void uv__stream_connect(uv_stream_t* stream) { stream->connect_req = NULL; uv__req_unregister(stream->loop, req); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + + if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + } if (req->cb) req->cb(req, error); + + if (uv__stream_fd(stream) == -1) + return; + + if (error < 0) { + uv__stream_flush_write_queue(stream, -ECANCELED); + uv__write_callbacks(stream); + } } diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/unix/timer.c index 9bd0423b5..ca3ec3db9 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/unix/timer.c @@ -65,6 +65,9 @@ int uv_timer_start(uv_timer_t* handle, uint64_t repeat) { uint64_t clamped_timeout; + if (cb == NULL) + return -EINVAL; + if (uv__is_active(handle)) uv_timer_stop(handle); diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index bf91cbdf9..7cafea1d0 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -340,8 +340,6 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, unsigned char taddr[sizeof(struct sockaddr_in6)]; socklen_t addrlen; - assert(domain == AF_INET || domain == AF_INET6); - if (handle->io_watcher.fd != -1) return 0; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 4e3968cb4..13e732dd3 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -19,13 +19,6 @@ * IN THE SOFTWARE. */ -/* Expose glibc-specific EAI_* error codes. Needs to be defined before we - * include any headers. - */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - #include "uv.h" #include "uv-common.h" @@ -39,13 +32,6 @@ # include <net/if.h> /* if_nametoindex */ #endif -/* EAI_* constants. */ -#if !defined(_WIN32) -# include <sys/types.h> -# include <sys/socket.h> -# include <netdb.h> -#endif - #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); size_t uv_handle_size(uv_handle_type type) { @@ -410,62 +396,6 @@ uint64_t uv_now(const uv_loop_t* loop) { } -int uv__getaddrinfo_translate_error(int sys_err) { - switch (sys_err) { - case 0: return 0; -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY; -#endif -#if defined(EAI_AGAIN) - case EAI_AGAIN: return UV_EAI_AGAIN; -#endif -#if defined(EAI_BADFLAGS) - case EAI_BADFLAGS: return UV_EAI_BADFLAGS; -#endif -#if defined(EAI_BADHINTS) - case EAI_BADHINTS: return UV_EAI_BADHINTS; -#endif -#if defined(EAI_CANCELED) - case EAI_CANCELED: return UV_EAI_CANCELED; -#endif -#if defined(EAI_FAIL) - case EAI_FAIL: return UV_EAI_FAIL; -#endif -#if defined(EAI_FAMILY) - case EAI_FAMILY: return UV_EAI_FAMILY; -#endif -#if defined(EAI_MEMORY) - case EAI_MEMORY: return UV_EAI_MEMORY; -#endif -#if defined(EAI_NODATA) - case EAI_NODATA: return UV_EAI_NODATA; -#endif -#if defined(EAI_NONAME) -# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME - case EAI_NONAME: return UV_EAI_NONAME; -# endif -#endif -#if defined(EAI_OVERFLOW) - case EAI_OVERFLOW: return UV_EAI_OVERFLOW; -#endif -#if defined(EAI_PROTOCOL) - case EAI_PROTOCOL: return UV_EAI_PROTOCOL; -#endif -#if defined(EAI_SERVICE) - case EAI_SERVICE: return UV_EAI_SERVICE; -#endif -#if defined(EAI_SOCKTYPE) - case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; -#endif -#if defined(EAI_SYSTEM) - case EAI_SYSTEM: return -errno; -#endif - } - assert(!"unknown EAI_* error code"); - abort(); - return 0; /* Pacify compiler. */ -} - size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { unsigned int i; @@ -478,6 +408,13 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { return bytes; } +int uv_recv_buffer_size(uv_handle_t* handle, int* value) { + return uv__socket_sockopt(handle, SO_RCVBUF, value); +} + +int uv_send_buffer_size(uv_handle_t* handle, int *value) { + return uv__socket_sockopt(handle, SO_SNDBUF, value); +} int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) { size_t required_len; @@ -498,3 +435,68 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buf, size_t* len) { return 0; } + + +void uv__fs_readdir_cleanup(uv_fs_t* req) { + uv__dirent_t** dents; + + dents = req->ptr; + if (req->nbufs > 0 && req->nbufs != (unsigned int) req->result) + req->nbufs--; + for (; req->nbufs < (unsigned int) req->result; req->nbufs++) + free(dents[req->nbufs]); +} + + +int uv_fs_readdir_next(uv_fs_t* req, uv_dirent_t* ent) { + uv__dirent_t** dents; + uv__dirent_t* dent; + + dents = req->ptr; + + /* Free previous entity */ + if (req->nbufs > 0) + free(dents[req->nbufs - 1]); + + /* End was already reached */ + if (req->nbufs == (unsigned int) req->result) { + free(dents); + req->ptr = NULL; + return UV_EOF; + } + + dent = dents[req->nbufs++]; + + ent->name = dent->d_name; +#ifdef HAVE_DIRENT_TYPES + switch (dent->d_type) { + case UV__DT_DIR: + ent->type = UV_DIRENT_DIR; + break; + case UV__DT_FILE: + ent->type = UV_DIRENT_FILE; + break; + case UV__DT_LINK: + ent->type = UV_DIRENT_LINK; + break; + case UV__DT_FIFO: + ent->type = UV_DIRENT_FIFO; + break; + case UV__DT_SOCKET: + ent->type = UV_DIRENT_SOCKET; + break; + case UV__DT_CHAR: + ent->type = UV_DIRENT_CHAR; + break; + case UV__DT_BLOCK: + ent->type = UV_DIRENT_BLOCK; + break; + default: + ent->type = UV_DIRENT_UNKNOWN; + } +#else + ent->type = UV_DIRENT_UNKNOWN; +#endif + + return 0; +} diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 34c287898..c9bad2f16 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -107,6 +107,10 @@ void uv__work_done(uv_async_t* handle); size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs); +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); + +void uv__fs_readdir_cleanup(uv_fs_t* req); + #define uv__has_active_reqs(loop) \ (QUEUE_EMPTY(&(loop)->active_reqs) == 0) diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c index 02de6de30..ff91a4609 100644 --- a/deps/uv/src/version.c +++ b/deps/uv/src/version.c @@ -35,7 +35,7 @@ #if UV_VERSION_IS_RELEASE # define UV_VERSION_STRING UV_VERSION_STRING_BASE #else -# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-pre" +# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX #endif diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index c39597561..c9e4c88fa 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -36,12 +36,11 @@ #include "req-inl.h" -/* The only event loop we support right now */ -static uv_loop_t uv_default_loop_; +static uv_loop_t default_loop_struct; +static uv_loop_t* default_loop_ptr; /* uv_once intialization guards */ 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(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)) @@ -138,7 +137,6 @@ int uv_loop_init(uv_loop_t* loop) { * 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); @@ -181,48 +179,45 @@ int uv_loop_init(uv_loop_t* loop) { } -static void uv_default_loop_init(void) { - /* Initialize libuv itself first */ - uv__once_init(); - - /* Initialize the main loop */ - uv_loop_init(&uv_default_loop_); -} - - void uv__once_init(void) { uv_once(&uv_init_guard_, uv_init); } uv_loop_t* uv_default_loop(void) { - uv_once(&uv_default_loop_init_guard_, uv_default_loop_init); - return &uv_default_loop_; + if (default_loop_ptr != NULL) + return default_loop_ptr; + + if (uv_loop_init(&default_loop_struct)) + return NULL; + + default_loop_ptr = &default_loop_struct; + return default_loop_ptr; } static void uv__loop_close(uv_loop_t* loop) { + size_t i; + /* 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); - } + 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); + + CloseHandle(loop->iocp); } @@ -242,6 +237,8 @@ int uv_loop_close(uv_loop_t* loop) { #ifndef NDEBUG memset(loop, -1, sizeof(*loop)); #endif + if (loop == default_loop_ptr) + default_loop_ptr = NULL; return 0; } @@ -265,9 +262,12 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { - int err = uv_loop_close(loop); + uv_loop_t* default_loop; + int err; + default_loop = default_loop_ptr; + err = uv_loop_close(loop); assert(err == 0); - if (loop != &uv_default_loop_) + if (loop != default_loop) free(loop); } @@ -313,13 +313,17 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else { - /* 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. + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout is reflected in the loop time. */ uv__time_forward(loop, timeout); } @@ -346,13 +350,17 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); uv_insert_pending_req(loop, req); } + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } else if (timeout > 0) { - /* 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. + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout is reflected in the loop time. */ uv__time_forward(loop, timeout); } @@ -411,7 +419,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * the check. */ - uv_update_time(loop); uv_process_timers(loop); } @@ -428,3 +435,68 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { return r; } + + +int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { + uv_os_fd_t fd_out; + + switch (handle->type) { + case UV_TCP: + fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket; + break; + + case UV_NAMED_PIPE: + fd_out = ((uv_pipe_t*) handle)->handle; + break; + + case UV_TTY: + fd_out = ((uv_tty_t*) handle)->handle; + break; + + case UV_UDP: + fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket; + break; + + case UV_POLL: + fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket; + break; + + default: + return UV_EINVAL; + } + + if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE) + return UV_EBADF; + + *fd = fd_out; + return 0; +} + + +int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { + int r; + int len; + SOCKET socket; + + if (handle == NULL || value == NULL) + return UV_EINVAL; + + if (handle->type == UV_TCP) + socket = ((uv_tcp_t*) handle)->socket; + else if (handle->type == UV_UDP) + socket = ((uv_udp_t*) handle)->socket; + else + return UV_ENOTSUP; + + len = sizeof(*value); + + if (*value == 0) + r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len); + else + r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len); + + if (r == SOCKET_ERROR) + return uv_translate_sys_error(WSAGetLastError()); + + return 0; +} diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 8b52e610f..d3801460e 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -36,11 +36,15 @@ #include "req-inl.h" #include "handle-inl.h" +#include <wincrypt.h> + #define UV_FS_FREE_PATHS 0x0002 #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 +static const int uv__fs_dirent_slide = 0x20; + #define QUEUE_FS_TP_JOB(loop, req) \ do { \ @@ -721,88 +725,75 @@ void fs__mkdir(uv_fs_t* req) { } -/* Some parts of the implementation were borrowed from glibc. */ +/* OpenBSD original: lib/libc/stdio/mktemp.c */ void fs__mkdtemp(uv_fs_t* req) { - static const WCHAR letters[] = + static const WCHAR *tempchars = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + WCHAR *cp, *ep; + unsigned int tries, i; size_t len; - 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 + HCRYPTPROV h_crypt_prov; + uint64_t v; + BOOL released; len = wcslen(req->pathw); - if (len < 6 || wcsncmp(&req->pathw[len - 6], L"XXXXXX", 6)) { + ep = req->pathw + len; + if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER); return; } - /* 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; + if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } - /* 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]; + tries = TMP_MAX; + do { + if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + break; + } - fd = _wmkdir(req->pathw); + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } - if (fd >= 0) { + if (_wmkdir(req->pathw) == 0) { len = strlen(req->path); - wcstombs((char*) req->path + len - 6, template_part, 6); + wcstombs((char*) req->path + len - num_x, ep - num_x, num_x); SET_REQ_RESULT(req, 0); - return; + break; } else if (errno != EEXIST) { SET_REQ_RESULT(req, -1); - return; + break; } - } + } while (--tries); - /* We got out of the loop because we ran out of combinations to try. */ - SET_REQ_RESULT(req, -1); + released = CryptReleaseContext(h_crypt_prov, 0); + assert(released); + if (tries == 0) { + SET_REQ_RESULT(req, -1); + } } void fs__readdir(uv_fs_t* req) { WCHAR* pathw = req->pathw; size_t len = wcslen(pathw); - int result, size; - WCHAR* buf = NULL, *ptr, *name; + int result; + WCHAR* name; HANDLE dir; WIN32_FIND_DATAW ent = { 0 }; - size_t buf_char_len = 4096; WCHAR* path2; const WCHAR* fmt; + uv__dirent_t** dents; + int dent_size; if (len == 0) { fmt = L"./*"; @@ -821,7 +812,8 @@ void fs__readdir(uv_fs_t* req) { path2 = (WCHAR*)malloc(sizeof(WCHAR) * (len + 4)); if (!path2) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + return; } _snwprintf(path2, len + 3, fmt, pathw); @@ -834,71 +826,81 @@ void fs__readdir(uv_fs_t* req) { } result = 0; + dents = NULL; + dent_size = 0; do { - name = ent.cFileName; - - if (name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2]))) { - len = wcslen(name); + uv__dirent_t* dent; + int utf8_len; - if (!buf) { - buf = (WCHAR*)malloc(buf_char_len * sizeof(WCHAR)); - if (!buf) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } + name = ent.cFileName; - ptr = buf; - } + if (!(name[0] != L'.' || (name[1] && (name[1] != L'.' || name[2])))) + continue; - while ((ptr - buf) + len + 1 > buf_char_len) { - buf_char_len *= 2; - path2 = buf; - buf = (WCHAR*)realloc(buf, buf_char_len * sizeof(WCHAR)); - if (!buf) { - uv_fatal_error(ERROR_OUTOFMEMORY, "realloc"); - } + /* Grow dents buffer, if needed */ + if (result >= dent_size) { + uv__dirent_t** tmp; - ptr = buf + (ptr - path2); + dent_size += uv__fs_dirent_slide; + tmp = realloc(dents, dent_size * sizeof(*dents)); + if (tmp == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto fatal; } - - wcscpy(ptr, name); - ptr += len + 1; - result++; + dents = tmp; } - } while(FindNextFileW(dir, &ent)); - FindClose(dir); - - if (buf) { - /* Convert result to UTF8. */ - size = uv_utf16_to_utf8(buf, buf_char_len, NULL, 0); - if (!size) { + /* Allocate enough space to fit utf8 encoding of file name */ + len = wcslen(name); + utf8_len = uv_utf16_to_utf8(name, len, NULL, 0); + if (!utf8_len) { SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + goto fatal; } - req->ptr = (char*)malloc(size + 1); - if (!req->ptr) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + dent = malloc(sizeof(*dent) + utf8_len + 1); + if (dent == NULL) { + SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); + goto fatal; } - size = uv_utf16_to_utf8(buf, buf_char_len, (char*)req->ptr, size); - if (!size) { - free(buf); - free(req->ptr); - req->ptr = NULL; + /* Copy file name */ + utf8_len = uv_utf16_to_utf8(name, len, dent->d_name, utf8_len); + if (!utf8_len) { + free(dent); SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + goto fatal; } - free(buf); + dent->d_name[utf8_len] = '\0'; - ((char*)req->ptr)[size] = '\0'; + /* Copy file type */ + if ((ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + dent->d_type = UV__DT_DIR; + else if ((ent.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) + dent->d_type = UV__DT_LINK; + else + dent->d_type = UV__DT_FILE; + + dents[result++] = dent; + } while(FindNextFileW(dir, &ent)); + + FindClose(dir); + + if (dents != NULL) req->flags |= UV_FS_FREE_PTR; - } else { - req->ptr = NULL; - } + /* NOTE: nbufs will be used as index */ + req->nbufs = 0; + req->ptr = dents; SET_REQ_RESULT(req, result); + return; + +fatal: + /* Deallocate dents */ + for (result--; result >= 0; result--) + free(dents[result]); + free(dents); } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 086200a9e..787cfd536 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -26,6 +26,25 @@ #include "internal.h" #include "req-inl.h" +/* EAI_* constants. */ +#include <winsock2.h> + + +int uv__getaddrinfo_translate_error(int sys_err) { + switch (sys_err) { + case 0: return 0; + case WSATRY_AGAIN: return UV_EAI_AGAIN; + case WSAEINVAL: return UV_EAI_BADFLAGS; + case WSANO_RECOVERY: return UV_EAI_FAIL; + case WSAEAFNOSUPPORT: return UV_EAI_FAMILY; + case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY; + case WSAHOST_NOT_FOUND: return UV_EAI_NONAME; + case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE; + case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE; + default: return uv_translate_sys_error(sys_err); + } +} + /* * MinGW is missing this diff --git a/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c index 45608dae8..52cc79088 100644 --- a/deps/uv/src/win/getnameinfo.c +++ b/deps/uv/src/win/getnameinfo.c @@ -46,13 +46,15 @@ static void uv__getnameinfo_work(struct uv__work* w) { int ret = 0; req = container_of(w, uv_getnameinfo_t, work_req); - ret = GetNameInfoW((struct sockaddr*)&req->storage, - sizeof(req->storage), - host, - ARRAY_SIZE(host), - service, - ARRAY_SIZE(service), - req->flags); + if (GetNameInfoW((struct sockaddr*)&req->storage, + sizeof(req->storage), + host, + ARRAY_SIZE(host), + service, + ARRAY_SIZE(service), + req->flags)) { + ret = WSAGetLastError(); + } req->retcode = uv__getaddrinfo_translate_error(ret); /* convert results to UTF-8 */ diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 9eadb7123..d87402b73 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -65,7 +65,6 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; /* Used by all handles. */ #define UV_HANDLE_CLOSED 0x00000002 #define UV_HANDLE_ENDGAME_QUEUED 0x00000004 -#define UV_HANDLE_ACTIVE 0x00000010 /* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ /* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ @@ -100,6 +99,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; /* Only used by uv_pipe_t handles. */ #define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 #define UV_HANDLE_PIPESERVER 0x02000000 +#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000 /* Only used by uv_tty_t handles. */ #define UV_HANDLE_TTY_READABLE 0x01000000 @@ -181,6 +181,9 @@ int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb); +void uv__pipe_pause_read(uv_pipe_t* handle); +void uv__pipe_unpause_read(uv_pipe_t* handle); +void uv__pipe_stop_read(uv_pipe_t* handle); void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); @@ -319,6 +322,7 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); */ void uv__util_init(); +uint64_t uv__hrtime(double scale); int uv_parent_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index eb49f7cbc..20e4509f8 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -49,7 +49,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { \ assert(handle->type == UV_##NAME); \ \ - if (handle->flags & UV_HANDLE_ACTIVE) \ + if (uv__is_active(handle)) \ return 0; \ \ if (cb == NULL) \ @@ -67,7 +67,6 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { loop->name##_handles = handle; \ \ handle->name##_cb = cb; \ - handle->flags |= UV_HANDLE_ACTIVE; \ uv__handle_start(handle); \ \ return 0; \ @@ -79,7 +78,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { \ assert(handle->type == UV_##NAME); \ \ - if (!(handle->flags & UV_HANDLE_ACTIVE)) \ + if (!uv__is_active(handle)) \ return 0; \ \ /* Update loop head if needed */ \ @@ -99,7 +98,6 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { handle->name##_next->name##_prev = handle->name##_prev; \ } \ \ - handle->flags &= ~UV_HANDLE_ACTIVE; \ uv__handle_stop(handle); \ \ return 0; \ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 3bf2a220d..c78051db7 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -101,6 +101,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { handle->pending_ipc_info.queue_len = 0; handle->ipc = ipc; handle->non_overlapped_writes_tail = NULL; + handle->readfile_thread = NULL; uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req); @@ -112,6 +113,12 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) { uv_connection_init((uv_stream_t*) handle); handle->read_req.data = handle; handle->eof_timer = NULL; + assert(!(handle->flags & UV_HANDLE_PIPESERVER)); + if (pCancelSynchronousIo && + handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + uv_mutex_init(&handle->readfile_mutex); + handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE; + } } @@ -321,6 +328,11 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { FILE_PIPE_LOCAL_INFORMATION pipe_info; uv__ipc_queue_item_t* item; + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE; + uv_mutex_destroy(&handle->readfile_mutex); + } + if ((handle->flags & UV_HANDLE_CONNECTION) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { @@ -658,12 +670,49 @@ error: } +void uv__pipe_pause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + /* Pause the ReadFile task briefly, to work + around the Windows kernel bug that causes + any access to a NamedPipe to deadlock if + any process has called ReadFile */ + HANDLE h; + uv_mutex_lock(&handle->readfile_mutex); + h = handle->readfile_thread; + while (h) { + /* spinlock: we expect this to finish quickly, + or we are probably about to deadlock anyways + (in the kernel), so it doesn't matter */ + pCancelSynchronousIo(h); + SwitchToThread(); /* yield thread control briefly */ + h = handle->readfile_thread; + } + } +} + + +void uv__pipe_unpause_read(uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_unlock(&handle->readfile_mutex); + } +} + + +void uv__pipe_stop_read(uv_pipe_t* handle) { + handle->flags &= ~UV_HANDLE_READING; + uv__pipe_pause_read((uv_pipe_t*)handle); + uv__pipe_unpause_read((uv_pipe_t*)handle); +} + + /* Cleans up uv_pipe_t (server or connection) and all resources associated */ /* with it. */ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; + uv__pipe_stop_read(handle); + if (handle->name) { free(handle->name); handle->name = NULL; @@ -689,6 +738,7 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { CloseHandle(handle->handle); handle->handle = INVALID_HANDLE_VALUE; } + } @@ -867,19 +917,61 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { uv_read_t* req = (uv_read_t*) parameter; uv_pipe_t* handle = (uv_pipe_t*) req->data; uv_loop_t* loop = handle->loop; + HANDLE hThread = NULL; + DWORD err; + uv_mutex_t *m = &handle->readfile_mutex; assert(req != NULL); assert(req->type == UV_READ); assert(handle->type == UV_NAMED_PIPE); + if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ + if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hThread, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + handle->readfile_thread = hThread; + } else { + hThread = NULL; + } + uv_mutex_unlock(m); + } +restart_readfile: result = ReadFile(handle->handle, &uv_zero_, 0, &bytes, NULL); + if (!result) { + err = GetLastError(); + if (err == ERROR_OPERATION_ABORTED && + handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + if (handle->flags & UV_HANDLE_READING) { + /* just a brief break to do something else */ + handle->readfile_thread = NULL; + /* resume after it is finished */ + uv_mutex_lock(m); + handle->readfile_thread = hThread; + uv_mutex_unlock(m); + goto restart_readfile; + } else { + result = 1; /* successfully stopped reading */ + } + } + } + if (hThread) { + assert(hThread == handle->readfile_thread); + /* mutex does not control clearing readfile_thread */ + handle->readfile_thread = NULL; + uv_mutex_lock(m); + /* only when we hold the mutex lock is it safe to + open or close the handle */ + CloseHandle(hThread); + uv_mutex_unlock(m); + } if (!result) { - SET_REQ_ERROR(req, GetLastError()); + SET_REQ_ERROR(req, err); } POST_COMPLETION_FOR_REQ(loop, req); @@ -1836,6 +1928,8 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { return UV_EINVAL; } + uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */ + nt_status = pNtQueryInformationFile(handle->handle, &io_status, &tmp_name_info, @@ -1846,7 +1940,8 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { name_info = malloc(name_size); if (!name_info) { *len = 0; - return UV_ENOMEM; + err = UV_ENOMEM; + goto cleanup; } nt_status = pNtQueryInformationFile(handle->handle, @@ -1918,10 +2013,14 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { buf[addrlen++] = '\0'; *len = addrlen; - return 0; + err = 0; + goto cleanup; error: free(name_info); + +cleanup: + uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */ return err; } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 40023e557..4d04a0e90 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -171,8 +171,10 @@ static WCHAR* search_path_join_test(const WCHAR* dir, size_t cwd_len) { WCHAR *result, *result_pos; DWORD attrs; - - if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { + if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') { + /* It's a UNC path so ignore cwd */ + cwd_len = 0; + } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { /* It's a full path without drive letter, use cwd's drive letter only */ cwd_len = 2; } else if (dir_len >= 2 && dir[1] == L':' && @@ -331,7 +333,11 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir, * file that is not readable/executable; if the spawn fails it will not * continue searching. * - * TODO: correctly interpret UNC paths + * UNC path support: we are dealing with UNC paths in both the path and the + * filename. This is a deviation from what cmd.exe does (it does not let you + * start a program by specifying an UNC path on the command line) but this is + * really a pointless restriction. + * */ static WCHAR* search_path(const WCHAR *file, WCHAR *cwd, @@ -794,10 +800,8 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { 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); + wmemcpy(ptr, *ptr_copy, len); ptr_copy++; if (cmp == 0) i++; diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 6553ab11d..057f72eca 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -106,7 +106,11 @@ int uv_read_stop(uv_stream_t* handle) { if (handle->type == UV_TTY) { err = uv_tty_read_stop((uv_tty_t*) handle); } else { - handle->flags &= ~UV_HANDLE_READING; + if (handle->type == UV_NAMED_PIPE) { + uv__pipe_stop_read((uv_pipe_t*) handle); + } else { + handle->flags &= ~UV_HANDLE_READING; + } DECREASE_ACTIVE_COUNT(handle->loop, handle); } diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index a213ad63e..23fadc220 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -196,6 +196,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { closesocket(handle->socket); + handle->socket = INVALID_SOCKET; handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } @@ -1368,6 +1369,7 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { if (close_socket) { closesocket(tcp->socket); + tcp->socket = INVALID_SOCKET; tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index c229d4c89..0da541a2c 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -28,39 +28,17 @@ #include "handle-inl.h" -void uv_update_time(uv_loop_t* loop) { - DWORD ticks; - ULARGE_INTEGER time; - - ticks = GetTickCount(); +/* The number of milliseconds in one second. */ +#define UV__MILLISEC 1000 - 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. - */ - time.LowPart = ticks; - if (ticks < loop->last_tick_count) - time.HighPart++; - - /* 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. - */ - if (loop->time < time.QuadPart) - loop->time = time.QuadPart; +void uv_update_time(uv_loop_t* loop) { + uint64_t new_time = uv__hrtime(UV__MILLISEC); + if (new_time > loop->time) { + loop->time = new_time; + } } - void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { loop->time += msecs; } @@ -119,14 +97,15 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, uv_loop_t* loop = handle->loop; uv_timer_t* old; - if (handle->flags & UV_HANDLE_ACTIVE) { - RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); - } + if (timer_cb == NULL) + return UV_EINVAL; + + if (uv__is_active(handle)) + uv_timer_stop(handle); handle->timer_cb = timer_cb; handle->due = get_clamped_due_time(loop->time, timeout); handle->repeat = repeat; - handle->flags |= UV_HANDLE_ACTIVE; uv__handle_start(handle); /* start_id is the second index to be compared in uv__timer_cmp() */ @@ -142,12 +121,10 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, int uv_timer_stop(uv_timer_t* handle) { uv_loop_t* loop = handle->loop; - if (!(handle->flags & UV_HANDLE_ACTIVE)) + if (!uv__is_active(handle)) return 0; RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); - - handle->flags &= ~UV_HANDLE_ACTIVE; uv__handle_stop(handle); return 0; @@ -155,28 +132,14 @@ int uv_timer_stop(uv_timer_t* handle) { int uv_timer_again(uv_timer_t* handle) { - uv_loop_t* loop = handle->loop; - /* If timer_cb is NULL that means that the timer was never started. */ if (!handle->timer_cb) { return UV_EINVAL; } - if (handle->flags & UV_HANDLE_ACTIVE) { - RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); - handle->flags &= ~UV_HANDLE_ACTIVE; - uv__handle_stop(handle); - } - if (handle->repeat) { - handle->due = get_clamped_due_time(loop->time, handle->repeat); - - if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { - uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); - } - - handle->flags |= UV_HANDLE_ACTIVE; - uv__handle_start(handle); + uv_timer_stop(handle); + uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); } return 0; @@ -206,16 +169,9 @@ DWORD uv__next_timeout(const uv_loop_t* loop) { timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); if (timer) { delta = timer->due - loop->time; - if (delta >= UINT_MAX >> 1) { - /* A timeout value of UINT_MAX means infinite, so that's no good. 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; + if (delta >= UINT_MAX - 1) { + /* A timeout value of UINT_MAX means infinite, so that's no good. */ + return UINT_MAX - 1; } else if (delta < 0) { /* Negative timeout values are not allowed */ return 0; @@ -236,23 +192,9 @@ void uv_process_timers(uv_loop_t* loop) { for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); timer != NULL && timer->due <= loop->time; timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { - RB_REMOVE(uv_timer_tree_s, &loop->timers, timer); - - if (timer->repeat != 0) { - /* If it is a repeating timer, reschedule with repeat timeout. */ - timer->due = get_clamped_due_time(timer->due, timer->repeat); - if (timer->due < loop->time) { - timer->due = loop->time; - } - if (RB_INSERT(uv_timer_tree_s, &loop->timers, timer) != NULL) { - uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); - } - } else { - /* If non-repeating, mark the timer as inactive. */ - timer->flags &= ~UV_HANDLE_ACTIVE; - uv__handle_stop(timer); - } + uv_timer_stop(timer); + uv_timer_again(timer); timer->timer_cb((uv_timer_t*) timer); } } diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 6b8297cbd..6d6709f79 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -1903,6 +1903,7 @@ void uv_tty_close(uv_tty_t* handle) { if (handle->flags & UV_HANDLE_READING) uv_tty_read_stop(handle); + handle->handle = INVALID_HANDLE_VALUE; handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); uv__handle_closing(handle); diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index ef63dd73d..99fd80fce 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -144,6 +144,7 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { uv_udp_recv_stop(handle); closesocket(handle->socket); + handle->socket = INVALID_SOCKET; uv__handle_closing(handle); @@ -505,9 +506,13 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, } else if (err == WSAEWOULDBLOCK) { /* Kernel buffer empty */ handle->recv_cb(handle, 0, &buf, NULL, 0); - } else if (err != WSAECONNRESET && err != WSAENETRESET) { - /* Serious error. WSAECONNRESET/WSANETRESET is ignored because this */ - /* just indicates that a previous sendto operation failed. */ + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* WSAECONNRESET/WSANETRESET is ignored because this just indicates + * that a previous sendto operation failed. + */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else { + /* Any other error that we want to report back to the user. */ uv_udp_recv_stop(handle); handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); } @@ -572,7 +577,9 @@ static int uv__udp_set_membership4(uv_udp_t* handle, memset(&mreq, 0, sizeof mreq); if (interface_addr) { - mreq.imr_interface.s_addr = inet_addr(interface_addr); + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; } else { mreq.imr_interface.s_addr = htonl(INADDR_ANY); } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index a56fbea50..8d1aefc53 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -52,16 +52,15 @@ #define MAX_TITLE_LENGTH 8192 /* The number of nanoseconds in one second. */ -#undef NANOSEC -#define NANOSEC 1000000000 +#define UV__NANOSEC 1000000000 /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; static CRITICAL_SECTION process_title_lock; -/* Frequency (ticks per nanosecond) of the high-resolution clock. */ -static double hrtime_frequency_ = 0; +/* Interval (in seconds) of the high-resolution clock. */ +static double hrtime_interval_ = 0; /* @@ -73,11 +72,14 @@ void uv__util_init() { /* Initialize process title access mutex. */ InitializeCriticalSection(&process_title_lock); - /* Retrieve high-resolution timer frequency. */ - if (QueryPerformanceFrequency(&perf_frequency)) - hrtime_frequency_ = (double) perf_frequency.QuadPart / (double) NANOSEC; - else - hrtime_frequency_= 0; + /* Retrieve high-resolution timer frequency + * and precompute its reciprocal. + */ + if (QueryPerformanceFrequency(&perf_frequency)) { + hrtime_interval_ = 1.0 / perf_frequency.QuadPart; + } else { + hrtime_interval_= 0; + } } @@ -463,26 +465,27 @@ int uv_get_process_title(char* buffer, size_t size) { uint64_t uv_hrtime(void) { - LARGE_INTEGER counter; - uv__once_init(); + return uv__hrtime(UV__NANOSEC); +} + +uint64_t uv__hrtime(double scale) { + LARGE_INTEGER counter; - /* If the performance frequency is zero, there's no support. */ - if (hrtime_frequency_ == 0) { - /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */ + /* If the performance interval is zero, there's no support. */ + if (hrtime_interval_ == 0) { return 0; } if (!QueryPerformanceCounter(&counter)) { - /* uv__set_sys_error(loop, GetLastError()); */ return 0; } /* Because we have no guarantee about the order of magnitude of the - * performance counter frequency, integer math could cause this computation + * performance counter interval, integer math could cause this computation * to overflow. Therefore we resort to floating point math. */ - return (uint64_t) ((double) counter.QuadPart / hrtime_frequency_); + return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale); } diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 3e439ea5b..84ce73e3a 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -51,6 +51,7 @@ sSleepConditionVariableCS pSleepConditionVariableCS; sSleepConditionVariableSRW pSleepConditionVariableSRW; sWakeAllConditionVariable pWakeAllConditionVariable; sWakeConditionVariable pWakeConditionVariable; +sCancelSynchronousIo pCancelSynchronousIo; void uv_winapi_init() { @@ -156,4 +157,7 @@ void uv_winapi_init() { pWakeConditionVariable = (sWakeConditionVariable) GetProcAddress(kernel32_module, "WakeConditionVariable"); + + pCancelSynchronousIo = (sCancelSynchronousIo) + GetProcAddress(kernel32_module, "CancelSynchronousIo"); } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 21d7fe4ac..1bb0e9aae 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4617,6 +4617,8 @@ typedef VOID (WINAPI* sWakeAllConditionVariable) typedef VOID (WINAPI* sWakeConditionVariable) (PCONDITION_VARIABLE ConditionVariable); +typedef BOOL (WINAPI* sCancelSynchronousIo) + (HANDLE hThread); /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; @@ -4644,5 +4646,6 @@ extern sSleepConditionVariableCS pSleepConditionVariableCS; extern sSleepConditionVariableSRW pSleepConditionVariableSRW; extern sWakeAllConditionVariable pWakeAllConditionVariable; extern sWakeConditionVariable pWakeConditionVariable; +extern sCancelSynchronousIo pCancelSynchronousIo; #endif /* UV_WIN_WINAPI_H_ */ diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c index f0937ccaa..f223981c2 100644 --- a/deps/uv/test/echo-server.c +++ b/deps/uv/test/echo-server.c @@ -51,20 +51,21 @@ static void after_write(uv_write_t* req, int status) { /* Free the read/write buffer and the request */ wr = (write_req_t*) req; free(wr->buf.base); + free(wr); - if (status == 0) { - free(wr); + if (status == 0) return; - } fprintf(stderr, "uv_write error: %s - %s\n", uv_err_name(status), uv_strerror(status)); +} - if (!uv_is_closing((uv_handle_t*) req->handle)) - uv_close((uv_handle_t*) req->handle, on_close); - free(wr); + +static void after_shutdown(uv_shutdown_t* req, int status) { + uv_close((uv_handle_t*) req->handle, on_close); + free(req); } @@ -73,16 +74,15 @@ static void after_read(uv_stream_t* handle, const uv_buf_t* buf) { int i; write_req_t *wr; + uv_shutdown_t* sreq; if (nread < 0) { /* Error or EOF */ ASSERT(nread == UV_EOF); - if (buf->base) { - free(buf->base); - } - - uv_close((uv_handle_t*) handle, on_close); + free(buf->base); + sreq = malloc(sizeof* sreq); + ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown)); return; } diff --git a/deps/uv/test/test-default-loop-close.c b/deps/uv/test/test-default-loop-close.c new file mode 100644 index 000000000..fd11cfa8c --- /dev/null +++ b/deps/uv/test/test-default-loop-close.c @@ -0,0 +1,59 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +static int timer_cb_called; + + +static void timer_cb(uv_timer_t* timer) { + timer_cb_called++; + uv_close((uv_handle_t*) timer, NULL); +} + + +TEST_IMPL(default_loop_close) { + uv_loop_t* loop; + uv_timer_t timer_handle; + + loop = uv_default_loop(); + ASSERT(loop != NULL); + + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(1 == timer_cb_called); + ASSERT(0 == uv_loop_close(loop)); + + loop = uv_default_loop(); + ASSERT(loop != NULL); + + ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(2 == timer_cb_called); + ASSERT(0 == uv_loop_close(loop)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 4c6ccfab2..a06ddada8 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -417,12 +417,16 @@ static void rmdir_cb(uv_fs_t* req) { static void readdir_cb(uv_fs_t* req) { + uv_dirent_t dent; ASSERT(req == &readdir_req); ASSERT(req->fs_type == UV_FS_READDIR); ASSERT(req->result == 2); ASSERT(req->ptr); - ASSERT(memcmp(req->ptr, "file1\0file2\0", 12) == 0 - || memcmp(req->ptr, "file2\0file1\0", 12) == 0); + + while (UV_EOF != uv_fs_readdir_next(req, &dent)) { + ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); + ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN); + } readdir_cb_count++; ASSERT(req->path); ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); @@ -802,6 +806,7 @@ TEST_IMPL(fs_file_write_null_buffer) { TEST_IMPL(fs_async_dir) { int r; + uv_dirent_t dent; /* Setup */ unlink("test_dir/file1"); @@ -844,8 +849,10 @@ TEST_IMPL(fs_async_dir) { ASSERT(r == 2); ASSERT(readdir_req.result == 2); ASSERT(readdir_req.ptr); - ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 - || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) { + ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); + ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN); + } uv_fs_req_cleanup(&readdir_req); ASSERT(!readdir_req.ptr); @@ -1521,6 +1528,7 @@ TEST_IMPL(fs_symlink_dir) { uv_fs_t req; int r; char* test_dir; + uv_dirent_t dent; /* set-up */ unlink("test_dir/file1"); @@ -1597,8 +1605,10 @@ TEST_IMPL(fs_symlink_dir) { ASSERT(r == 2); ASSERT(readdir_req.result == 2); ASSERT(readdir_req.ptr); - ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 - || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) { + ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); + ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN); + } uv_fs_req_cleanup(&readdir_req); ASSERT(!readdir_req.ptr); @@ -1615,8 +1625,10 @@ TEST_IMPL(fs_symlink_dir) { ASSERT(r == 2); ASSERT(readdir_req.result == 2); ASSERT(readdir_req.ptr); - ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 - || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + while (UV_EOF != uv_fs_readdir_next(&readdir_req, &dent)) { + ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); + ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN); + } uv_fs_req_cleanup(&readdir_req); ASSERT(!readdir_req.ptr); diff --git a/deps/uv/test/test-handle-fileno.c b/deps/uv/test/test-handle-fileno.c new file mode 100644 index 000000000..df5e984ab --- /dev/null +++ b/deps/uv/test/test-handle-fileno.c @@ -0,0 +1,120 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +static int get_tty_fd(void) { + /* Make sure we have an FD that refers to a tty */ +#ifdef _WIN32 + HANDLE handle; + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (handle == INVALID_HANDLE_VALUE) + return -1; + return _open_osfhandle((intptr_t) handle, 0); +#else /* unix */ + return open("/dev/tty", O_RDONLY, 0); +#endif +} + + +TEST_IMPL(handle_fileno) { + int r; + int tty_fd; + struct sockaddr_in addr; + uv_os_fd_t fd; + uv_tcp_t tcp; + uv_udp_t udp; + uv_pipe_t pipe; + uv_tty_t tty; + uv_idle_t idle; + uv_loop_t* loop; + + loop = uv_default_loop(); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_idle_init(loop, &idle); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &idle, &fd); + ASSERT(r == UV_EINVAL); + uv_close((uv_handle_t*) &idle, NULL); + + r = uv_tcp_init(loop, &tcp); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &tcp, &fd); + ASSERT(r == UV_EBADF); + r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &tcp, &fd); + ASSERT(r == 0); + uv_close((uv_handle_t*) &tcp, NULL); + r = uv_fileno((uv_handle_t*) &tcp, &fd); + ASSERT(r == UV_EBADF); + + r = uv_udp_init(loop, &udp); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &udp, &fd); + ASSERT(r == UV_EBADF); + r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &udp, &fd); + ASSERT(r == 0); + uv_close((uv_handle_t*) &udp, NULL); + r = uv_fileno((uv_handle_t*) &udp, &fd); + ASSERT(r == UV_EBADF); + + r = uv_pipe_init(loop, &pipe, 0); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &pipe, &fd); + ASSERT(r == UV_EBADF); + r = uv_pipe_bind(&pipe, TEST_PIPENAME); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &pipe, &fd); + ASSERT(r == 0); + uv_close((uv_handle_t*) &pipe, NULL); + r = uv_fileno((uv_handle_t*) &pipe, &fd); + ASSERT(r == UV_EBADF); + + tty_fd = get_tty_fd(); + if (tty_fd < 0) { + LOGF("Cannot open a TTY fd"); + } else { + r = uv_tty_init(loop, &tty, tty_fd, 0); + ASSERT(r == 0); + r = uv_fileno((uv_handle_t*) &tty, &fd); + ASSERT(r == 0); + uv_close((uv_handle_t*) &tty, NULL); + r = uv_fileno((uv_handle_t*) &tty, &fd); + ASSERT(r == UV_EBADF); + } + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 6dbe22307..9cb65c393 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -29,6 +29,7 @@ TEST_DECLARE (loop_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) +TEST_DECLARE (default_loop_close) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) @@ -55,6 +56,9 @@ TEST_DECLARE (tcp_ping_pong_v6) TEST_DECLARE (pipe_ping_pong) TEST_DECLARE (delayed_accept) TEST_DECLARE (multiple_listen) +#ifndef _WIN32 +TEST_DECLARE (tcp_write_after_connect) +#endif TEST_DECLARE (tcp_writealot) TEST_DECLARE (tcp_try_write) TEST_DECLARE (tcp_write_queue_order) @@ -89,6 +93,7 @@ TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_send_and_recv) TEST_DECLARE (udp_send_immediate) +TEST_DECLARE (udp_send_unreachable) TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_join6) TEST_DECLARE (udp_multicast_ttl) @@ -109,6 +114,7 @@ TEST_DECLARE (pipe_connect_bad_name) TEST_DECLARE (pipe_connect_to_file) TEST_DECLARE (pipe_getsockname) TEST_DECLARE (pipe_getsockname_abstract) +TEST_DECLARE (pipe_getsockname_blocking) TEST_DECLARE (pipe_sendmsg) TEST_DECLARE (pipe_server_close) TEST_DECLARE (connection_fail) @@ -128,6 +134,7 @@ TEST_DECLARE (timer_huge_timeout) TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) TEST_DECLARE (timer_from_check) +TEST_DECLARE (timer_null_callback) TEST_DECLARE (idle_starvation) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) @@ -155,6 +162,9 @@ TEST_DECLARE (pipe_ref) TEST_DECLARE (pipe_ref2) TEST_DECLARE (pipe_ref3) TEST_DECLARE (pipe_ref4) +#ifndef _WIN32 +TEST_DECLARE (pipe_close_stdout_read_stdin) +#endif TEST_DECLARE (process_ref) TEST_DECLARE (has_ref) TEST_DECLARE (active) @@ -165,6 +175,7 @@ TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) +TEST_DECLARE (handle_fileno) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_basic) @@ -175,6 +186,7 @@ TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_udp) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) +TEST_DECLARE (socket_buffer_size) TEST_DECLARE (spawn_fails) TEST_DECLARE (spawn_exit_code) TEST_DECLARE (spawn_stdout) @@ -275,6 +287,7 @@ TEST_DECLARE (closed_fd_events) #endif #ifdef __APPLE__ TEST_DECLARE (osx_select) +TEST_DECLARE (osx_select_many_fds) #endif HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp6_echo_server) @@ -296,6 +309,7 @@ TASK_LIST_START TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) + TEST_ENTRY (default_loop_close) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) @@ -312,6 +326,9 @@ TASK_LIST_START TEST_ENTRY (pipe_connect_to_file) TEST_ENTRY (pipe_server_close) +#ifndef _WIN32 + TEST_ENTRY (pipe_close_stdout_read_stdin) +#endif TEST_ENTRY (tty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) @@ -335,6 +352,10 @@ TASK_LIST_START TEST_ENTRY (delayed_accept) TEST_ENTRY (multiple_listen) +#ifndef _WIN32 + TEST_ENTRY (tcp_write_after_connect) +#endif + TEST_ENTRY (tcp_writealot) TEST_HELPER (tcp_writealot, tcp4_echo_server) @@ -381,6 +402,7 @@ TASK_LIST_START TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_send_and_recv) TEST_ENTRY (udp_send_immediate) + TEST_ENTRY (udp_send_unreachable) TEST_ENTRY (udp_dgram_too_big) TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_ipv6_only) @@ -402,6 +424,7 @@ TASK_LIST_START TEST_ENTRY (pipe_listen_without_bind) TEST_ENTRY (pipe_getsockname) TEST_ENTRY (pipe_getsockname_abstract) + TEST_ENTRY (pipe_getsockname_blocking) TEST_ENTRY (pipe_sendmsg) TEST_ENTRY (connection_fail) @@ -432,6 +455,7 @@ TASK_LIST_START TEST_ENTRY (timer_huge_repeat) TEST_ENTRY (timer_run_once) TEST_ENTRY (timer_from_check) + TEST_ENTRY (timer_null_callback) TEST_ENTRY (idle_starvation) @@ -487,6 +511,8 @@ TASK_LIST_START TEST_ENTRY (get_loadavg) + TEST_ENTRY (handle_fileno) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) @@ -504,6 +530,8 @@ TASK_LIST_START TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) + TEST_ENTRY (socket_buffer_size) + TEST_ENTRY (spawn_fails) TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) @@ -549,6 +577,7 @@ TASK_LIST_START #ifdef __APPLE__ TEST_ENTRY (osx_select) + TEST_ENTRY (osx_select_many_fds) #endif TEST_ENTRY (fs_file_noent) diff --git a/deps/uv/test/test-osx-select.c b/deps/uv/test/test-osx-select.c index e5e1bf8b4..68e5a8416 100644 --- a/deps/uv/test/test-osx-select.c +++ b/deps/uv/test/test-osx-select.c @@ -79,4 +79,52 @@ TEST_IMPL(osx_select) { return 0; } + +TEST_IMPL(osx_select_many_fds) { + int r; + int fd; + size_t i; + size_t len; + const char* str; + struct sockaddr_in addr; + uv_tty_t tty; + uv_tcp_t tcps[1500]; + + r = uv_ip4_addr("127.0.0.1", 0, &addr); + ASSERT(r == 0); + + for (i = 0; i < ARRAY_SIZE(tcps); i++) { + r = uv_tcp_init(uv_default_loop(), &tcps[i]); + ASSERT(r == 0); + r = uv_tcp_bind(&tcps[i], (const struct sockaddr *) &addr, 0); + ASSERT(r == 0); + uv_unref((uv_handle_t*) &tcps[i]); + } + + fd = open("/dev/tty", O_RDONLY); + ASSERT(fd >= 0); + + r = uv_tty_init(uv_default_loop(), &tty, fd, 1); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb); + ASSERT(r == 0); + + /* Emulate user-input */ + str = "got some input\n" + "with a couple of lines\n" + "feel pretty happy\n"; + for (i = 0, len = strlen(str); i < len; i++) { + r = ioctl(fd, TIOCSTI, str + i); + ASSERT(r == 0); + } + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(read_count == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + #endif /* __APPLE__ */ diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c new file mode 100644 index 000000000..26a1ee76c --- /dev/null +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -0,0 +1,103 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _WIN32 + +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> +#include <sys/types.h> + +#include "uv.h" +#include "task.h" + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf) +{ + static char buffer[1024]; + + buf->base = buffer; + buf->len = sizeof(buffer); +} + +void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf) +{ + if (nread < 0) { + uv_close((uv_handle_t*)stream, NULL); + return; + } +} + +/* + * This test is a reproduction of joyent/libuv#1419 . + */ +TEST_IMPL(pipe_close_stdout_read_stdin) { + int r = -1; + int pid; + int fd[2]; + int status; + + pipe(fd); + + if ((pid = fork()) == 0) { + /* + * Make the read side of the pipe our stdin. + * The write side will be closed by the parent process. + */ + close(fd[1]); + close(0); + dup(fd[0]); + + /* Create a stream that reads from the pipe. */ + uv_pipe_t stdin_pipe; + + r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0); + ASSERT(r == 0); + + r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin); + ASSERT(r == 0); + + /* + * Because the other end of the pipe was closed, there should + * be no event left to process after one run of the event loop. + * Otherwise, it means that events were not processed correctly. + */ + ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0); + } else { + /* + * Close both ends of the pipe so that the child + * get a POLLHUP event when it tries to read from + * the other end. + */ + close(fd[1]); + close(fd[0]); + + waitpid(pid, &status, 0); + ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* ifndef _WIN32 */ diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 396f72577..d4010f3b5 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -32,6 +32,8 @@ #ifndef _WIN32 # include <unistd.h> /* close */ +#else +# include <fcntl.h> #endif @@ -120,3 +122,59 @@ TEST_IMPL(pipe_getsockname_abstract) { #endif } +TEST_IMPL(pipe_getsockname_blocking) { +#ifdef _WIN32 + uv_pipe_t reader; + HANDLE readh, writeh; + int readfd; + char buf1[1024], buf2[1024]; + size_t len1, len2; + int r; + + r = CreatePipe(&readh, &writeh, NULL, 65536); + ASSERT(r != 0); + + r = uv_pipe_init(uv_default_loop(), &reader, 0); + ASSERT(r == 0); + readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY); + ASSERT(r != -1); + r = uv_pipe_open(&reader, readfd); + ASSERT(r == 0); + r = uv_read_start((uv_stream_t*)&reader, NULL, NULL); + ASSERT(r == 0); + Sleep(100); + r = uv_read_stop((uv_stream_t*)&reader); + ASSERT(r == 0); + + len1 = sizeof buf1; + r = uv_pipe_getsockname(&reader, buf1, &len1); + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&reader, NULL, NULL); + ASSERT(r == 0); + Sleep(100); + + len2 = sizeof buf2; + r = uv_pipe_getsockname(&reader, buf2, &len2); + ASSERT(r == 0); + + r = uv_read_stop((uv_stream_t*)&reader); + ASSERT(r == 0); + + ASSERT(len1 == len2); + ASSERT(memcmp(buf1, buf2, len1) == 0); + + close_cb_called = 0; + uv_close((uv_handle_t*)&reader, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + _close(readfd); + CloseHandle(writeh); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-socket-buffer-size.c b/deps/uv/test/test-socket-buffer-size.c new file mode 100644 index 000000000..72f8c2524 --- /dev/null +++ b/deps/uv/test/test-socket-buffer-size.c @@ -0,0 +1,77 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static uv_udp_t udp; +static uv_tcp_t tcp; +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + + +static void check_buffer_size(uv_handle_t* handle) { + int value; + + value = 0; + ASSERT(0 == uv_recv_buffer_size(handle, &value)); + ASSERT(value > 0); + + value = 10000; + ASSERT(0 == uv_recv_buffer_size(handle, &value)); + + value = 0; + ASSERT(0 == uv_recv_buffer_size(handle, &value)); + /* linux sets double the value */ + ASSERT(value == 10000 || value == 20000); +} + + +TEST_IMPL(socket_buffer_size) { + struct sockaddr_in addr; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp)); + ASSERT(0 == uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0)); + check_buffer_size((uv_handle_t*) &tcp); + uv_close((uv_handle_t*) &tcp, close_cb); + + ASSERT(0 == uv_udp_init(uv_default_loop(), &udp)); + ASSERT(0 == uv_udp_bind(&udp, (struct sockaddr*) &addr, 0)); + check_buffer_size((uv_handle_t*) &udp); + uv_close((uv_handle_t*) &udp, close_cb); + + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 57f0862f9..11f43bdf1 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1295,23 +1295,25 @@ TEST_IMPL(closed_fd_events) { TEST_IMPL(spawn_reads_child_path) { int r; int len; + char file[64]; 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--); + strcpy(file, exepath + len); exepath[len] = 0; strcpy(path, "PATH="); strcpy(path + 5, exepath); + options.file = file; + options.args[0] = file; options.env = env; r = uv_spawn(uv_default_loop(), &process, &options); diff --git a/deps/uv/test/test-tcp-write-after-connect.c b/deps/uv/test/test-tcp-write-after-connect.c new file mode 100644 index 000000000..aa03228f1 --- /dev/null +++ b/deps/uv/test/test-tcp-write-after-connect.c @@ -0,0 +1,68 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _WIN32 + +#include "uv.h" +#include "task.h" + +uv_loop_t loop; +uv_tcp_t tcp_client; +uv_connect_t connection_request; +uv_write_t write_request; +uv_buf_t buf = { "HELLO", 4 }; + + +static void write_cb(uv_write_t *req, int status) { + ASSERT(status == UV_ECANCELED); + uv_close((uv_handle_t*) req->handle, NULL); +} + + +static void connect_cb(uv_connect_t *req, int status) { + ASSERT(status == UV_ECONNREFUSED); +} + + +TEST_IMPL(tcp_write_after_connect) { + struct sockaddr_in sa; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); + + ASSERT(0 == uv_tcp_connect(&connection_request, + &tcp_client, + (const struct sockaddr *) + &sa, + connect_cb)); + + ASSERT(0 == uv_write(&write_request, + (uv_stream_t *)&tcp_client, + &buf, 1, + write_cb)); + + uv_run(&loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c index 18e1f192b..aa4d2acc2 100644 --- a/deps/uv/test/test-tcp-write-queue-order.c +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -26,7 +26,7 @@ #include "uv.h" #include "task.h" -#define REQ_COUNT 100000 +#define REQ_COUNT 10000 static uv_timer_t timer; static uv_tcp_t server; diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c index f26dae577..aba050fd6 100644 --- a/deps/uv/test/test-timer.c +++ b/deps/uv/test/test-timer.c @@ -290,3 +290,14 @@ TEST_IMPL(timer_run_once) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(timer_null_callback) { + uv_timer_t handle; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); + ASSERT(UV_EINVAL == uv_timer_start(&handle, NULL, 100, 100)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 0e2fe2dcf..0ca9f4dcf 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -147,12 +147,19 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { TEST_IMPL(udp_dual_stack) { +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + RETURN_SKIP("dual stack not enabled by default in this OS."); +#else do_test(ipv6_recv_ok, 0); ASSERT(recv_cb_called == 1); ASSERT(send_cb_called == 1); return 0; +#endif } diff --git a/deps/uv/test/test-udp-multicast-interface6.c b/deps/uv/test/test-udp-multicast-interface6.c index e58d77119..e54e738b0 100644 --- a/deps/uv/test/test-udp-multicast-interface6.c +++ b/deps/uv/test/test-udp-multicast-interface6.c @@ -69,7 +69,7 @@ TEST_IMPL(udp_multicast_interface6) { r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); ASSERT(r == 0); -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) r = uv_udp_set_multicast_interface(&server, "::1%lo0"); #else r = uv_udp_set_multicast_interface(&server, NULL); diff --git a/deps/uv/test/test-udp-send-unreachable.c b/deps/uv/test/test-udp-send-unreachable.c new file mode 100644 index 000000000..c6500320d --- /dev/null +++ b/deps/uv/test/test-udp-send-unreachable.c @@ -0,0 +1,150 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &client) + +static uv_udp_t client; +static uv_timer_t timer; + +static int send_cb_called; +static int recv_cb_called; +static int close_cb_called; +static int alloc_cb_called; +static int timer_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); + alloc_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(1 == uv_is_closing(handle)); + close_cb_called++; +} + + +static void send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + send_cb_called++; +} + + +static void recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + recv_cb_called++; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } else if (nread == 0) { + /* Returning unused buffer */ + ASSERT(addr == NULL); + } else { + ASSERT(addr != NULL); + } +} + + +static void timer_cb(uv_timer_t* h) { + ASSERT(h == &timer); + timer_cb_called++; + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) h, close_cb); +} + + +TEST_IMPL(udp_send_unreachable) { + struct sockaddr_in addr; + struct sockaddr_in addr2; + uv_udp_send_t req1, req2; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2)); + + r = uv_timer_init( uv_default_loop(), &timer ); + ASSERT(r == 0); + + r = uv_timer_start( &timer, timer_cb, 1000, 0 ); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_udp_bind(&client, (const struct sockaddr*) &addr2, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&client, alloc_cb, recv_cb); + ASSERT(r == 0); + + /* client sends "PING", then "PANG" */ + buf = uv_buf_init("PING", 4); + + r = uv_udp_send(&req1, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); + + buf = uv_buf_init("PANG", 4); + + r = uv_udp_send(&req2, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(send_cb_called == 2); + ASSERT(recv_cb_called == alloc_cb_called); + ASSERT(timer_cb_called == 1); + ASSERT(close_cb_called == 2); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-watcher-cross-stop.c b/deps/uv/test/test-watcher-cross-stop.c index bf765cb00..910ed0fb6 100644 --- a/deps/uv/test/test-watcher-cross-stop.c +++ b/deps/uv/test/test-watcher-cross-stop.c @@ -92,10 +92,10 @@ TEST_IMPL(watcher_cross_stop) { uv_close((uv_handle_t*) &sockets[i], close_cb); ASSERT(recv_cb_called > 0); - ASSERT(ARRAY_SIZE(sockets) == send_cb_called); uv_run(loop, UV_RUN_DEFAULT); + ASSERT(ARRAY_SIZE(sockets) == send_cb_called); ASSERT(ARRAY_SIZE(sockets) == close_cb_called); MAKE_VALGRIND_HAPPY(); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 5b4d69a92..444182b62 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -26,6 +26,30 @@ ], }], ], + 'xcode_settings': { + 'conditions': [ + [ 'clang==1', { + 'WARNING_CFLAGS': [ + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wno-dollar-in-identifier-extension' + ]}, { + 'WARNING_CFLAGS': [ + '-Wall', + '-Wextra', + '-Wno-unused-parameter' + ]} + ] + ], + 'OTHER_LDFLAGS': [ + ], + 'OTHER_CFLAGS': [ + '-g', + '--std=gnu89', + '-pedantic' + ], + } }, 'targets': [ @@ -53,9 +77,6 @@ }], ], }, - 'defines': [ - 'HAVE_CONFIG_H' - ], 'sources': [ 'common.gypi', 'include/uv.h', @@ -179,7 +200,7 @@ 'link_settings': { # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR # in src/version.c - 'libraries': [ '-Wl,-soname,libuv.so.0.11' ], + 'libraries': [ '-Wl,-soname,libuv.so.1.0' ], }, }], ], @@ -195,6 +216,7 @@ ], 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', + '_DARWIN_UNLIMITED_SELECT=1', ] }], [ 'OS!="mac"', { @@ -312,6 +334,7 @@ 'test/test-close-order.c', 'test/test-connection-fail.c', 'test/test-cwd-and-chdir.c', + 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', 'test/test-error.c', 'test/test-embed.c', @@ -324,6 +347,7 @@ 'test/test-getaddrinfo.c', 'test/test-getnameinfo.c', 'test/test-getsockname.c', + 'test/test-handle-fileno.c', 'test/test-hrtime.c', 'test/test-idle.c', 'test/test-ip6-addr.c', @@ -346,6 +370,7 @@ 'test/test-pipe-getsockname.c', 'test/test-pipe-sendmsg.c', 'test/test-pipe-server-close.c', + 'test/test-pipe-close-stdout-read-stdin.c', 'test/test-platform-output.c', 'test/test-poll.c', 'test/test-poll-close.c', @@ -360,6 +385,7 @@ 'test/test-shutdown-twice.c', 'test/test-signal.c', 'test/test-signal-multiple-loops.c', + 'test/test-socket-buffer-size.c', 'test/test-spawn.c', 'test/test-fs-poll.c', 'test/test-stdio-over-pipes.c', @@ -376,6 +402,7 @@ 'test/test-tcp-connect6-error.c', 'test/test-tcp-open.c', 'test/test-tcp-write-to-half-open-connection.c', + 'test/test-tcp-write-after-connect.c', 'test/test-tcp-writealot.c', 'test/test-tcp-try-write.c', 'test/test-tcp-unexpected-read.c', @@ -398,6 +425,7 @@ 'test/test-udp-options.c', 'test/test-udp-send-and-recv.c', 'test/test-udp-send-immediate.c', + 'test/test-udp-send-unreachable.c', 'test/test-udp-multicast-join.c', 'test/test-udp-multicast-join6.c', 'test/test-dlerror.c', diff --git a/src/node_file.cc b/src/node_file.cc index 3b287ec1c..8962f8680 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -207,21 +207,26 @@ static void After(uv_fs_t *req) { case UV_FS_READDIR: { - char *namebuf = static_cast<char*>(req->ptr); - int nnames = req->result; - - Local<Array> names = Array::New(env->isolate(), nnames); - - for (int i = 0; i < nnames; i++) { - Local<String> name = String::NewFromUtf8(env->isolate(), namebuf); + int r; + Local<Array> names = Array::New(env->isolate(), 0); + + for (int i = 0; ; i++) { + uv_dirent_t ent; + + r = uv_fs_readdir_next(req, &ent); + if (r == UV_EOF) + break; + if (r != 0) { + argv[0] = UVException(r, + NULL, + req_wrap->syscall(), + static_cast<const char*>(req->path)); + break; + } + + Local<String> name = String::NewFromUtf8(env->isolate(), + ent.name); names->Set(i, name); -#ifndef NDEBUG - namebuf += strlen(namebuf); - assert(*namebuf == '\0'); - namebuf += 1; -#else - namebuf += strlen(namebuf) + 1; -#endif } argv[1] = names; @@ -710,19 +715,21 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { SYNC_CALL(readdir, *path, *path, 0 /*flags*/) assert(SYNC_REQ.result >= 0); - char* namebuf = static_cast<char*>(SYNC_REQ.ptr); - uint32_t nnames = SYNC_REQ.result; - Local<Array> names = Array::New(env->isolate(), nnames); - - for (uint32_t i = 0; i < nnames; ++i) { - names->Set(i, String::NewFromUtf8(env->isolate(), namebuf)); -#ifndef NDEBUG - namebuf += strlen(namebuf); - assert(*namebuf == '\0'); - namebuf += 1; -#else - namebuf += strlen(namebuf) + 1; -#endif + int r; + Local<Array> names = Array::New(env->isolate(), 0); + + for (int i = 0; ; i++) { + uv_dirent_t ent; + + r = uv_fs_readdir_next(&SYNC_REQ, &ent); + if (r == UV_EOF) + break; + if (r != 0) + return env->ThrowUVException(r, "readdir", "", *path); + + Local<String> name = String::NewFromUtf8(env->isolate(), + ent.name); + names->Set(i, name); } args.GetReturnValue().Set(names); |