mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-23 07:28:51 -06:00
Merge topic 'import-libuv'
39ac889dcmake: Add trivial usage of libuv7cf369feDo not build libuv on HP-UX075cae51Do not build libuv on SPARC9a53af40Do not build libuv on Cygwin219f7411Do not build libuv on Mac OS X 10.4 and lower8a5beef3Add option to build CMake against a system libuve56aa462FindLibUV: Add module to find libuv package551d5aedlibuv: Fix unused variable warning in uv_loop_closef4f8074blibuv: Avoid including macOS CoreServices header globallya63aaaedlibuv: Always include our own header first9130b53alibuv: Conditionally declare Windows APIs for VS 2008 and belowb52afa46libuv: Fix anonymous union syntax05dbc204libuv: Fix Windows API function typedef syntax75139374libuv: Install LICENSE file with CMake documentation95dcc4e4libuv: Disable warnings to avoid changing 3rd party code13b7e758libuv: Build the library within CMake ...
This commit is contained in:
@@ -112,7 +112,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
|
||||
|
||||
# Allow the user to enable/disable all system utility library options by
|
||||
# defining CMAKE_USE_SYSTEM_LIBRARIES or CMAKE_USE_SYSTEM_LIBRARY_${util}.
|
||||
set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA ZLIB)
|
||||
set(UTILITIES BZIP2 CURL EXPAT FORM JSONCPP LIBARCHIVE LIBLZMA LIBUV ZLIB)
|
||||
foreach(util ${UTILITIES})
|
||||
if(NOT DEFINED CMAKE_USE_SYSTEM_LIBRARY_${util}
|
||||
AND DEFINED CMAKE_USE_SYSTEM_LIBRARIES)
|
||||
@@ -152,6 +152,7 @@ macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
|
||||
"${CMAKE_USE_SYSTEM_LIBRARY_LIBLZMA}" "NOT CMAKE_USE_SYSTEM_LIBARCHIVE" ON)
|
||||
option(CMAKE_USE_SYSTEM_FORM "Use system-installed libform" "${CMAKE_USE_SYSTEM_LIBRARY_FORM}")
|
||||
option(CMAKE_USE_SYSTEM_JSONCPP "Use system-installed jsoncpp" "${CMAKE_USE_SYSTEM_LIBRARY_JSONCPP}")
|
||||
option(CMAKE_USE_SYSTEM_LIBUV "Use system-installed libuv" "${CMAKE_USE_SYSTEM_LIBRARY_LIBUV}")
|
||||
|
||||
# For now use system KWIML only if explicitly requested rather
|
||||
# than activating via the general system libs options.
|
||||
@@ -463,6 +464,55 @@ macro (CMAKE_BUILD_UTILITIES)
|
||||
CMAKE_SET_TARGET_FOLDER(cmjsoncpp "Utilities/3rdParty")
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Build libuv library.
|
||||
if(NOT DEFINED CMAKE_USE_LIBUV)
|
||||
set(CMAKE_USE_LIBUV 1)
|
||||
if(APPLE)
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#ifndef MAC_OS_X_VERSION_10_5
|
||||
#error \"MAC_OS_X_VERSION_10_5 is not defined\"
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
" HAVE_CoreServices_OS_X_10_5)
|
||||
if(NOT HAVE_CoreServices_OS_X_10_5)
|
||||
set(CMAKE_USE_LIBUV 0)
|
||||
endif()
|
||||
elseif(CYGWIN)
|
||||
# libuv does not support Cygwin
|
||||
set(CMAKE_USE_LIBUV 0)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "HP-UX")
|
||||
# Disable until it can be ported.
|
||||
set(CMAKE_USE_LIBUV 0)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "sparc")
|
||||
# Disable until it can be ported.
|
||||
set(CMAKE_USE_LIBUV 0)
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_USE_LIBUV)
|
||||
if(CMAKE_USE_SYSTEM_LIBUV)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.0)
|
||||
include(${CMake_SOURCE_DIR}/Source/Modules/FindLibUV.cmake)
|
||||
else()
|
||||
message(FATAL_ERROR "CMAKE_USE_SYSTEM_LIBUV requires CMake >= 3.0")
|
||||
endif()
|
||||
if(NOT LIBUV_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!")
|
||||
endif()
|
||||
set(CMAKE_LIBUV_LIBRARIES LibUV::LibUV)
|
||||
else()
|
||||
set(CMAKE_LIBUV_LIBRARIES cmlibuv)
|
||||
add_subdirectory(Utilities/cmlibuv)
|
||||
CMAKE_SET_TARGET_FOLDER(cmlibuv "Utilities/3rdParty")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_LIBUV_LIBRARIES)
|
||||
endif()
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Build XMLRPC library for CMake and CTest.
|
||||
if(CTEST_USE_XMLRPC)
|
||||
|
||||
@@ -582,6 +582,7 @@ target_link_libraries(CMakeLib cmsys
|
||||
${CMAKE_TAR_LIBRARIES} ${CMAKE_COMPRESS_LIBRARIES}
|
||||
${CMAKE_CURL_LIBRARIES}
|
||||
${CMAKE_JSONCPP_LIBRARIES}
|
||||
${CMAKE_LIBUV_LIBRARIES}
|
||||
${CMake_KWIML_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
131
Source/Modules/FindLibUV.cmake
Normal file
131
Source/Modules/FindLibUV.cmake
Normal file
@@ -0,0 +1,131 @@
|
||||
#[=======================================================================[.rst:
|
||||
FindLibUV
|
||||
---------
|
||||
|
||||
Find libuv includes and library.
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
An :ref:`imported target <Imported targets>` named
|
||||
``LibUV::LibUV`` is provided if libuv has been found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module defines the following variables:
|
||||
|
||||
``LibUV_FOUND``
|
||||
True if libuv was found, false otherwise.
|
||||
``LibUV_INCLUDE_DIRS``
|
||||
Include directories needed to include libuv headers.
|
||||
``LibUV_LIBRARIES``
|
||||
Libraries needed to link to libuv.
|
||||
``LibUV_VERSION``
|
||||
The version of libuv found.
|
||||
``LibUV_VERSION_MAJOR``
|
||||
The major version of libuv.
|
||||
``LibUV_VERSION_MINOR``
|
||||
The minor version of libuv.
|
||||
``LibUV_VERSION_PATCH``
|
||||
The patch version of libuv.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
This module uses the following cache variables:
|
||||
|
||||
``LibUV_LIBRARY``
|
||||
The location of the libuv library file.
|
||||
``LibUV_INCLUDE_DIR``
|
||||
The location of the libuv include directory containing ``uv.h``.
|
||||
|
||||
The cache variables should not be used by project code.
|
||||
They may be set by end users to point at libuv components.
|
||||
#]=======================================================================]
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014-2016 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
find_library(LibUV_LIBRARY
|
||||
NAMES uv
|
||||
)
|
||||
mark_as_advanced(LibUV_LIBRARY)
|
||||
|
||||
find_path(LibUV_INCLUDE_DIR
|
||||
NAMES uv.h
|
||||
)
|
||||
mark_as_advanced(LibUV_INCLUDE_DIR)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Extract version number if possible.
|
||||
set(_LibUV_H_REGEX "#[ \t]*define[ \t]+UV_VERSION_(MAJOR|MINOR|PATCH)[ \t]+[0-9]+")
|
||||
if(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv-version.h")
|
||||
file(STRINGS "${LibUV_INCLUDE_DIR}/uv-version.h" _LibUV_H REGEX "${_LibUV_H_REGEX}")
|
||||
elseif(LibUV_INCLUDE_DIR AND EXISTS "${LibUV_INCLUDE_DIR}/uv.h")
|
||||
file(STRINGS "${LibUV_INCLUDE_DIR}/uv.h" _LibUV_H REGEX "${_LibUV_H_REGEX}")
|
||||
else()
|
||||
set(_LibUV_H "")
|
||||
endif()
|
||||
foreach(c MAJOR MINOR PATCH)
|
||||
if(_LibUV_H MATCHES "#[ \t]*define[ \t]+UV_VERSION_${c}[ \t]+([0-9]+)")
|
||||
set(_LibUV_VERSION_${c} "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
unset(_LibUV_VERSION_${c})
|
||||
endif()
|
||||
endforeach()
|
||||
if(DEFINED _LibUV_VERSION_MAJOR AND DEFINED _LibUV_VERSION_MINOR)
|
||||
set(LibUV_VERSION_MAJOR "${_LibUV_VERSION_MAJOR}")
|
||||
set(LibUV_VERSION_MINOR "${_LibUV_VERSION_MINOR}")
|
||||
set(LibUV_VERSION "${LibUV_VERSION_MAJOR}.${LibUV_VERSION_MINOR}")
|
||||
if(DEFINED _LibUV_VERSION_PATCH)
|
||||
set(LibUV_VERSION_PATCH "${_LibUV_VERSION_PATCH}")
|
||||
set(LibUV_VERSION "${LibUV_VERSION}.${LibUV_VERSION_PATCH}")
|
||||
else()
|
||||
unset(LibUV_VERSION_PATCH)
|
||||
endif()
|
||||
else()
|
||||
set(LibUV_VERSION_MAJOR "")
|
||||
set(LibUV_VERSION_MINOR "")
|
||||
set(LibUV_VERSION_PATCH "")
|
||||
set(LibUV_VERSION "")
|
||||
endif()
|
||||
unset(_LibUV_VERSION_MAJOR)
|
||||
unset(_LibUV_VERSION_MINOR)
|
||||
unset(_LibUV_VERSION_PATCH)
|
||||
unset(_LibUV_H_REGEX)
|
||||
unset(_LibUV_H)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUV
|
||||
FOUND_VAR LibUV_FOUND
|
||||
REQUIRED_VARS LibUV_LIBRARY LibUV_INCLUDE_DIR
|
||||
VERSION_VAR LibUV_VERSION
|
||||
)
|
||||
set(LIBUV_FOUND ${LibUV_FOUND})
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Provide documented result variables and targets.
|
||||
if(LibUV_FOUND)
|
||||
set(LibUV_INCLUDE_DIRS ${LibUV_INCLUDE_DIR})
|
||||
set(LibUV_LIBRARIES ${LibUV_LIBRARY})
|
||||
if(NOT TARGET LibUV::LibUV)
|
||||
add_library(LibUV::LibUV UNKNOWN IMPORTED)
|
||||
set_target_properties(LibUV::LibUV PROPERTIES
|
||||
IMPORTED_LOCATION "${LibUV_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LibUV_INCLUDE_DIRS}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -28,6 +28,7 @@
|
||||
#cmakedefine HAVE_UNSETENV
|
||||
#cmakedefine CMAKE_USE_ELF_PARSER
|
||||
#cmakedefine CMAKE_USE_MACH_PARSER
|
||||
#cmakedefine CMAKE_USE_LIBUV
|
||||
#cmakedefine CMAKE_ENCODING_UTF8
|
||||
#cmakedefine CMake_HAVE_CXX_NULLPTR
|
||||
#cmakedefine CMake_HAVE_CXX_OVERRIDE
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include "cmcmd.h"
|
||||
#include <cmsys/Encoding.hxx>
|
||||
|
||||
#ifdef CMAKE_USE_LIBUV
|
||||
#include "cm_uv.h"
|
||||
#endif
|
||||
|
||||
#ifdef CMAKE_BUILD_WITH_CMAKE
|
||||
static const char* cmDocumentationName[][2] = {
|
||||
{ CM_NULLPTR, " cmake - Cross-Platform Makefile Generator." },
|
||||
@@ -171,6 +175,9 @@ int main(int ac, char const* const* av)
|
||||
int ret = do_cmake(ac, av);
|
||||
#ifdef CMAKE_BUILD_WITH_CMAKE
|
||||
cmDynamicLoader::FlushCache();
|
||||
#endif
|
||||
#ifdef CMAKE_USE_LIBUV
|
||||
uv_loop_close(uv_default_loop());
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1373,6 +1373,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
|
||||
add_subdirectory(FindJsonCpp)
|
||||
endif()
|
||||
|
||||
if(CMake_TEST_FindLibUV)
|
||||
add_subdirectory(FindLibUV)
|
||||
endif()
|
||||
|
||||
if(CMake_TEST_FindLTTngUST)
|
||||
add_subdirectory(FindLTTngUST)
|
||||
endif()
|
||||
|
||||
10
Tests/FindLibUV/CMakeLists.txt
Normal file
10
Tests/FindLibUV/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
add_test(NAME FindLibUV.Test COMMAND
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/FindLibUV/Test"
|
||||
"${CMake_BINARY_DIR}/Tests/FindLibUV/Test"
|
||||
${build_generator_args}
|
||||
--build-project TestFindLibUV
|
||||
--build-options ${build_options}
|
||||
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
|
||||
)
|
||||
17
Tests/FindLibUV/Test/CMakeLists.txt
Normal file
17
Tests/FindLibUV/Test/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(TestFindLibUV C)
|
||||
include(CTest)
|
||||
|
||||
# CMake does not actually provide FindLibUV publicly.
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Modules)
|
||||
|
||||
find_package(LibUV REQUIRED)
|
||||
|
||||
add_executable(test_libuv_tgt main.c)
|
||||
target_link_libraries(test_libuv_tgt LibUV::LibUV)
|
||||
add_test(NAME test_libuv_tgt COMMAND test_libuv_tgt)
|
||||
|
||||
add_executable(test_libuv_var main.c)
|
||||
target_include_directories(test_libuv_var PRIVATE ${LibUV_INCLUDE_DIRS})
|
||||
target_link_libraries(test_libuv_var PRIVATE ${LibUV_LIBRARIES})
|
||||
add_test(NAME test_libuv_var COMMAND test_libuv_var)
|
||||
7
Tests/FindLibUV/Test/main.c
Normal file
7
Tests/FindLibUV/Test/main.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
uv_loop_close(uv_default_loop());
|
||||
return 0;
|
||||
}
|
||||
26
Utilities/Scripts/update-libuv.bash
Executable file
26
Utilities/Scripts/update-libuv.bash
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
shopt -s dotglob
|
||||
|
||||
readonly name="libuv"
|
||||
readonly ownership="libuv upstream <libuv@googlegroups.com>"
|
||||
readonly subtree="Utilities/cmlibuv"
|
||||
readonly repo="https://github.com/libuv/libuv.git"
|
||||
readonly tag="v1.x"
|
||||
readonly shortlog=false
|
||||
readonly paths="
|
||||
LICENSE
|
||||
include
|
||||
src
|
||||
"
|
||||
|
||||
extract_source () {
|
||||
git_archive
|
||||
pushd "${extractdir}/${name}-reduced"
|
||||
echo "* -whitespace" > .gitattributes
|
||||
popd
|
||||
}
|
||||
|
||||
. "${BASH_SOURCE%/*}/update-third-party.bash"
|
||||
@@ -22,6 +22,7 @@
|
||||
#cmakedefine CMAKE_USE_SYSTEM_LIBLZMA
|
||||
#cmakedefine CMAKE_USE_SYSTEM_FORM
|
||||
#cmakedefine CMAKE_USE_SYSTEM_JSONCPP
|
||||
#cmakedefine CMAKE_USE_SYSTEM_LIBUV
|
||||
#cmakedefine CTEST_USE_XMLRPC
|
||||
|
||||
#endif
|
||||
|
||||
23
Utilities/cm_uv.h
Normal file
23
Utilities/cm_uv.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
|
||||
|
||||
Distributed under the OSI-approved BSD License (the "License");
|
||||
see accompanying file Copyright.txt for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the License for more information.
|
||||
============================================================================*/
|
||||
#ifndef cm_uv_h
|
||||
#define cm_uv_h
|
||||
|
||||
/* Use the libuv library configured for CMake. */
|
||||
#include "cmThirdParty.h"
|
||||
#ifdef CMAKE_USE_SYSTEM_LIBUV
|
||||
#include <uv.h>
|
||||
#else
|
||||
#include <cmlibuv/include/uv.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1
Utilities/cmlibuv/.gitattributes
vendored
Normal file
1
Utilities/cmlibuv/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* -whitespace
|
||||
227
Utilities/cmlibuv/CMakeLists.txt
Normal file
227
Utilities/cmlibuv/CMakeLists.txt
Normal file
@@ -0,0 +1,227 @@
|
||||
project(libuv C)
|
||||
|
||||
# Disable warnings to avoid changing 3rd party code.
|
||||
if(CMAKE_C_COMPILER_ID MATCHES
|
||||
"^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
|
||||
endif()
|
||||
|
||||
find_package(Threads)
|
||||
|
||||
set(uv_libraries ${CMAKE_THREAD_LIBS_INIT})
|
||||
set(uv_includes include src)
|
||||
set(uv_headers
|
||||
include/uv.h
|
||||
include/uv-errno.h
|
||||
include/uv-threadpool.h
|
||||
include/uv-version.h
|
||||
)
|
||||
set(uv_sources
|
||||
src/fs-poll.c
|
||||
src/heap-inl.h
|
||||
src/inet.c
|
||||
src/queue.h
|
||||
src/threadpool.c
|
||||
src/uv-common.c
|
||||
src/uv-common.h
|
||||
src/version.c
|
||||
)
|
||||
if(WIN32)
|
||||
list(APPEND uv_libraries
|
||||
ws2_32
|
||||
psapi
|
||||
iphlpapi
|
||||
shell32
|
||||
userenv
|
||||
)
|
||||
list(APPEND uv_includes
|
||||
src/win
|
||||
)
|
||||
list(APPEND uv_defines
|
||||
WIN32_LEAN_AND_MEAN
|
||||
_WIN32_WINNT=0x0600
|
||||
)
|
||||
list(APPEND uv_headers
|
||||
include/uv-win.h
|
||||
include/tree.h
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/win/async.c
|
||||
src/win/atomicops-inl.h
|
||||
src/win/core.c
|
||||
src/win/detect-wakeup.c
|
||||
src/win/dl.c
|
||||
src/win/error.c
|
||||
src/win/fs-event.c
|
||||
src/win/fs.c
|
||||
src/win/getaddrinfo.c
|
||||
src/win/getnameinfo.c
|
||||
src/win/handle.c
|
||||
src/win/handle-inl.h
|
||||
src/win/internal.h
|
||||
src/win/loop-watcher.c
|
||||
src/win/pipe.c
|
||||
src/win/poll.c
|
||||
src/win/process-stdio.c
|
||||
src/win/process.c
|
||||
src/win/req.c
|
||||
src/win/req-inl.h
|
||||
src/win/signal.c
|
||||
src/win/snprintf.c
|
||||
src/win/stream.c
|
||||
src/win/stream-inl.h
|
||||
src/win/tcp.c
|
||||
src/win/thread.c
|
||||
src/win/timer.c
|
||||
src/win/tty.c
|
||||
src/win/udp.c
|
||||
src/win/util.c
|
||||
src/win/winapi.c
|
||||
src/win/winapi.h
|
||||
src/win/winsock.c
|
||||
src/win/winsock.h
|
||||
)
|
||||
else()
|
||||
list(APPEND uv_includes
|
||||
src/unix
|
||||
)
|
||||
list(APPEND uv_headers
|
||||
include/uv-unix.h
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/async.c
|
||||
src/unix/atomic-ops.h
|
||||
src/unix/core.c
|
||||
src/unix/dl.c
|
||||
src/unix/fs.c
|
||||
src/unix/getaddrinfo.c
|
||||
src/unix/getnameinfo.c
|
||||
src/unix/internal.h
|
||||
src/unix/loop-watcher.c
|
||||
src/unix/loop.c
|
||||
src/unix/pipe.c
|
||||
src/unix/poll.c
|
||||
src/unix/process.c
|
||||
src/unix/signal.c
|
||||
src/unix/spinlock.h
|
||||
src/unix/stream.c
|
||||
src/unix/tcp.c
|
||||
src/unix/thread.c
|
||||
src/unix/timer.c
|
||||
src/unix/tty.c
|
||||
src/unix/udp.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
|
||||
list(APPEND uv_libraries
|
||||
perfstat
|
||||
)
|
||||
list(APPEND uv_headers
|
||||
include/uv-aix.h
|
||||
)
|
||||
list(APPEND uv_defines
|
||||
_ALL_SOURCE
|
||||
_XOPEN_SOURCE=500
|
||||
_LINUX_SOURCE_COMPAT
|
||||
_THREAD_SAFE
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/aix.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
list(APPEND uv_headers
|
||||
include/uv-darwin.h
|
||||
include/pthread-barrier.h
|
||||
)
|
||||
list(APPEND uv_defines
|
||||
_DARWIN_USE_64_BIT_INODE=1
|
||||
_DARWIN_UNLIMITED_SELECT=1
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/darwin.c
|
||||
src/unix/darwin-proctitle.c
|
||||
src/unix/fsevents.c
|
||||
src/unix/kqueue.c
|
||||
src/unix/proctitle.c
|
||||
src/unix/pthread-barrier.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND uv_libraries dl rt)
|
||||
list(APPEND uv_headers
|
||||
include/uv-linux.h
|
||||
)
|
||||
list(APPEND uv_defines _GNU_SOURCE)
|
||||
list(APPEND uv_sources
|
||||
src/unix/linux-core.c
|
||||
src/unix/linux-inotify.c
|
||||
src/unix/linux-syscalls.c
|
||||
src/unix/linux-syscalls.h
|
||||
src/unix/proctitle.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
list(APPEND uv_headers
|
||||
include/uv-bsd.h
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/freebsd.c
|
||||
src/unix/kqueue.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
|
||||
list(APPEND uv_headers
|
||||
include/uv-bsd.h
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/netbsd.c
|
||||
src/unix/kqueue.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
list(APPEND uv_headers
|
||||
include/uv-bsd.h
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/openbsd.c
|
||||
src/unix/kqueue.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
list(APPEND uv_libraries
|
||||
kstat
|
||||
nsl
|
||||
sendfile
|
||||
socket
|
||||
)
|
||||
list(APPEND uv_headers
|
||||
include/uv-sunos.h
|
||||
)
|
||||
list(APPEND uv_defines
|
||||
__EXTENSIONS__
|
||||
_XOPEN_SOURCE=500
|
||||
)
|
||||
list(APPEND uv_sources
|
||||
src/unix/sunos.c
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${uv_includes}
|
||||
${KWSYS_HEADER_ROOT}
|
||||
)
|
||||
add_library(cmlibuv STATIC ${uv_sources})
|
||||
target_link_libraries(cmlibuv ${uv_libraries})
|
||||
set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines})
|
||||
|
||||
install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmlibuv)
|
||||
70
Utilities/cmlibuv/LICENSE
Normal file
70
Utilities/cmlibuv/LICENSE
Normal file
@@ -0,0 +1,70 @@
|
||||
libuv is licensed for use as follows:
|
||||
|
||||
====
|
||||
Copyright (c) 2015-present libuv project contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
====
|
||||
|
||||
This license applies to parts of libuv originating from the
|
||||
https://github.com/joyent/libuv repository:
|
||||
|
||||
====
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
This license applies to all parts of libuv that are not externally
|
||||
maintained libraries.
|
||||
|
||||
The externally maintained libraries used by libuv are:
|
||||
|
||||
- tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.
|
||||
|
||||
- inet_pton and inet_ntop implementations, contained in src/inet.c, are
|
||||
copyright the Internet Systems Consortium, Inc., and licensed under the ISC
|
||||
license.
|
||||
|
||||
- stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
|
||||
clause BSD license.
|
||||
|
||||
- pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
|
||||
Communications AB. Three clause BSD license.
|
||||
|
||||
- android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
|
||||
Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
|
||||
n° 289016). Three clause BSD license.
|
||||
54
Utilities/cmlibuv/include/android-ifaddrs.h
Normal file
54
Utilities/cmlibuv/include/android-ifaddrs.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _IFADDRS_H_
|
||||
#define _IFADDRS_H_
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
|
||||
* to be included it must be included before this header file.
|
||||
*/
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
extern int getifaddrs(struct ifaddrs **ifap);
|
||||
extern void freeifaddrs(struct ifaddrs *ifa);
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
66
Utilities/cmlibuv/include/pthread-barrier.h
Normal file
66
Utilities/cmlibuv/include/pthread-barrier.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _UV_PTHREAD_BARRIER_
|
||||
#define _UV_PTHREAD_BARRIER_
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h> /* sem_t */
|
||||
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
|
||||
|
||||
/*
|
||||
* To maintain ABI compatibility with
|
||||
* libuv v1.x struct is padded according
|
||||
* to target platform
|
||||
*/
|
||||
#if defined(__ANDROID__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
sizeof(pthread_cond_t) + \
|
||||
sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#elif defined(__APPLE__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
2 * sizeof(sem_t) + \
|
||||
2 * sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#else
|
||||
# define UV_BARRIER_STRUCT_PADDING 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
unsigned threshold;
|
||||
unsigned in;
|
||||
unsigned out;
|
||||
} _uv_barrier;
|
||||
|
||||
typedef struct {
|
||||
_uv_barrier* b;
|
||||
char _pad[UV_BARRIER_STRUCT_PADDING];
|
||||
} pthread_barrier_t;
|
||||
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count);
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier);
|
||||
int pthread_barrier_destroy(pthread_barrier_t *barrier);
|
||||
|
||||
#endif /* _UV_PTHREAD_BARRIER_ */
|
||||
247
Utilities/cmlibuv/include/stdint-msvc2008.h
Normal file
247
Utilities/cmlibuv/include/stdint-msvc2008.h
Normal file
@@ -0,0 +1,247 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2008 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
768
Utilities/cmlibuv/include/tree.h
Normal file
768
Utilities/cmlibuv/include/tree.h
Normal file
@@ -0,0 +1,768 @@
|
||||
/*-
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UV_TREE_H_
|
||||
#define UV_TREE_H_
|
||||
|
||||
#ifndef UV__UNUSED
|
||||
# if __GNUC__
|
||||
# define UV__UNUSED __attribute__((unused))
|
||||
# else
|
||||
# define UV__UNUSED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file defines data structures for different types of trees:
|
||||
* splay trees and red-black trees.
|
||||
*
|
||||
* A splay tree is a self-organizing data structure. Every operation
|
||||
* on the tree causes a splay to happen. The splay moves the requested
|
||||
* node to the root of the tree and partly rebalances it.
|
||||
*
|
||||
* This has the benefit that request locality causes faster lookups as
|
||||
* the requested nodes move to the top of the tree. On the other hand,
|
||||
* every lookup causes memory writes.
|
||||
*
|
||||
* The Balance Theorem bounds the total access time for m operations
|
||||
* and n inserts on an initially empty tree as O((m + n)lg n). The
|
||||
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
|
||||
*
|
||||
* A red-black tree is a binary search tree with the node color as an
|
||||
* extra attribute. It fulfills a set of conditions:
|
||||
* - every search path from the root to a leaf consists of the
|
||||
* same number of black nodes,
|
||||
* - each red node (except for the root) has a black parent,
|
||||
* - each leaf node is black.
|
||||
*
|
||||
* Every operation on a red-black tree is bounded as O(lg n).
|
||||
* The maximum height of a red-black tree is 2lg (n+1).
|
||||
*/
|
||||
|
||||
#define SPLAY_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sph_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define SPLAY_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define SPLAY_INIT(root) do { \
|
||||
(root)->sph_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *spe_left; /* left element */ \
|
||||
struct type *spe_right; /* right element */ \
|
||||
}
|
||||
|
||||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||
#define SPLAY_ROOT(head) (head)->sph_root
|
||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||
|
||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
|
||||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||
void name##_SPLAY(struct name *, struct type *); \
|
||||
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return(NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||
return (head->sph_root); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
name##_SPLAY(head, elm); \
|
||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||
elm = SPLAY_RIGHT(elm, field); \
|
||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||
elm = SPLAY_LEFT(elm, field); \
|
||||
} \
|
||||
} else \
|
||||
elm = NULL; \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_MIN_MAX(struct name *head, int val) \
|
||||
{ \
|
||||
name##_SPLAY_MINMAX(head, val); \
|
||||
return (SPLAY_ROOT(head)); \
|
||||
}
|
||||
|
||||
/* Main splay operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||
struct type * \
|
||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
if (SPLAY_EMPTY(head)) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||
} else { \
|
||||
int __comp; \
|
||||
name##_SPLAY(head, elm); \
|
||||
__comp = (cmp)(elm, (head)->sph_root); \
|
||||
if(__comp < 0) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||
} else if (__comp > 0) { \
|
||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||
} else \
|
||||
return ((head)->sph_root); \
|
||||
} \
|
||||
(head)->sph_root = (elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
struct type * \
|
||||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *__tmp; \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return (NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
} else { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
name##_SPLAY(head, elm); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
name##_SPLAY(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
int __comp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) > 0){ \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
} \
|
||||
\
|
||||
/* Splay with either the minimum or the maximum element \
|
||||
* Used to find minimum or maximum element in tree. \
|
||||
*/ \
|
||||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while (1) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp > 0) { \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
}
|
||||
|
||||
#define SPLAY_NEGINF -1
|
||||
#define SPLAY_INF 1
|
||||
|
||||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||
|
||||
#define SPLAY_FOREACH(x, name, head) \
|
||||
for ((x) = SPLAY_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = SPLAY_NEXT(name, head, x))
|
||||
|
||||
/* Macros that define a red-black tree */
|
||||
#define RB_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *rbh_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define RB_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define RB_INIT(root) do { \
|
||||
(root)->rbh_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_BLACK 0
|
||||
#define RB_RED 1
|
||||
#define RB_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *rbe_left; /* left element */ \
|
||||
struct type *rbe_right; /* right element */ \
|
||||
struct type *rbe_parent; /* parent element */ \
|
||||
int rbe_color; /* node color */ \
|
||||
}
|
||||
|
||||
#define RB_LEFT(elm, field) (elm)->field.rbe_left
|
||||
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
|
||||
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
|
||||
#define RB_COLOR(elm, field) (elm)->field.rbe_color
|
||||
#define RB_ROOT(head) (head)->rbh_root
|
||||
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
||||
|
||||
#define RB_SET(elm, parent, field) do { \
|
||||
RB_PARENT(elm, field) = parent; \
|
||||
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
||||
RB_COLOR(elm, field) = RB_RED; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_SET_BLACKRED(black, red, field) do { \
|
||||
RB_COLOR(black, field) = RB_BLACK; \
|
||||
RB_COLOR(red, field) = RB_RED; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#ifndef RB_AUGMENT
|
||||
#define RB_AUGMENT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_RIGHT(elm, field); \
|
||||
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_LEFT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_LEFT(elm, field); \
|
||||
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_RIGHT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
/* Generates prototypes and inline functions */
|
||||
#define RB_PROTOTYPE(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
|
||||
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
|
||||
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
|
||||
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_FIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NEXT(struct type *); \
|
||||
attr struct type *name##_RB_PREV(struct type *); \
|
||||
attr struct type *name##_RB_MINMAX(struct name *, int); \
|
||||
\
|
||||
|
||||
/* Main rb operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define RB_GENERATE(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
|
||||
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void \
|
||||
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *parent, *gparent, *tmp; \
|
||||
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
||||
RB_COLOR(parent, field) == RB_RED) { \
|
||||
gparent = RB_PARENT(parent, field); \
|
||||
if (parent == RB_LEFT(gparent, field)) { \
|
||||
tmp = RB_RIGHT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_RIGHT(parent, field) == elm) { \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
||||
} else { \
|
||||
tmp = RB_LEFT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_LEFT(head, gparent, tmp, field); \
|
||||
} \
|
||||
} \
|
||||
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr void \
|
||||
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
|
||||
struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp; \
|
||||
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
||||
elm != RB_ROOT(head)) { \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
|
||||
struct type *oleft; \
|
||||
if ((oleft = RB_LEFT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oleft, field) = RB_BLACK; \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_RIGHT(tmp, field)) \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
|
||||
struct type *oright; \
|
||||
if ((oright = RB_RIGHT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oright, field) = RB_BLACK; \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_LEFT(head, tmp, oright, field); \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_LEFT(tmp, field)) \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (elm) \
|
||||
RB_COLOR(elm, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *child, *parent, *old = elm; \
|
||||
int color; \
|
||||
if (RB_LEFT(elm, field) == NULL) \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
else if (RB_RIGHT(elm, field) == NULL) \
|
||||
child = RB_LEFT(elm, field); \
|
||||
else { \
|
||||
struct type *left; \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while ((left = RB_LEFT(elm, field)) != NULL) \
|
||||
elm = left; \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
if (RB_PARENT(elm, field) == old) \
|
||||
parent = elm; \
|
||||
(elm)->field = (old)->field; \
|
||||
if (RB_PARENT(old, field)) { \
|
||||
if (RB_LEFT(RB_PARENT(old, field), field) == old) \
|
||||
RB_LEFT(RB_PARENT(old, field), field) = elm; \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(old, field), field) = elm; \
|
||||
RB_AUGMENT(RB_PARENT(old, field)); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
||||
if (RB_RIGHT(old, field)) \
|
||||
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
||||
if (parent) { \
|
||||
left = parent; \
|
||||
do { \
|
||||
RB_AUGMENT(left); \
|
||||
} while ((left = RB_PARENT(left, field)) != NULL); \
|
||||
} \
|
||||
goto color; \
|
||||
} \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
color: \
|
||||
if (color == RB_BLACK) \
|
||||
name##_RB_REMOVE_COLOR(head, parent, child); \
|
||||
return (old); \
|
||||
} \
|
||||
\
|
||||
/* Inserts a node into the RB tree */ \
|
||||
attr struct type * \
|
||||
name##_RB_INSERT(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp; \
|
||||
struct type *parent = NULL; \
|
||||
int comp = 0; \
|
||||
tmp = RB_ROOT(head); \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
comp = (cmp)(elm, parent); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
RB_SET(elm, parent, field); \
|
||||
if (parent != NULL) { \
|
||||
if (comp < 0) \
|
||||
RB_LEFT(parent, field) = elm; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = elm; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
name##_RB_INSERT_COLOR(head, elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
attr struct type * \
|
||||
name##_RB_FIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the first node greater than or equal to the search key */ \
|
||||
attr struct type * \
|
||||
name##_RB_NFIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *res = NULL; \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) { \
|
||||
res = tmp; \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
} \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (res); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_NEXT(struct type *elm) \
|
||||
{ \
|
||||
if (RB_RIGHT(elm, field)) { \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while (RB_LEFT(elm, field)) \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_PREV(struct type *elm) \
|
||||
{ \
|
||||
if (RB_LEFT(elm, field)) { \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
while (RB_RIGHT(elm, field)) \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_MINMAX(struct name *head, int val) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *parent = NULL; \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
if (val < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
} \
|
||||
return (parent); \
|
||||
}
|
||||
|
||||
#define RB_NEGINF -1
|
||||
#define RB_INF 1
|
||||
|
||||
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
|
||||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||
|
||||
#define RB_FOREACH(x, name, head) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_NEXT(x))
|
||||
|
||||
#define RB_FOREACH_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE(x, name, head) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_PREV(x))
|
||||
|
||||
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#endif /* UV_TREE_H_ */
|
||||
32
Utilities/cmlibuv/include/uv-aix.h
Normal file
32
Utilities/cmlibuv/include/uv-aix.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_AIX_H
|
||||
#define UV_AIX_H
|
||||
|
||||
#define UV_PLATFORM_LOOP_FIELDS \
|
||||
int fs_fd; \
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
uv__io_t event_watcher; \
|
||||
char *dir_filename; \
|
||||
|
||||
#endif /* UV_AIX_H */
|
||||
34
Utilities/cmlibuv/include/uv-bsd.h
Normal file
34
Utilities/cmlibuv/include/uv-bsd.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_BSD_H
|
||||
#define UV_BSD_H
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
uv__io_t event_watcher; \
|
||||
|
||||
#define UV_IO_PRIVATE_PLATFORM_FIELDS \
|
||||
int rcount; \
|
||||
int wcount; \
|
||||
|
||||
#define UV_HAVE_KQUEUE 1
|
||||
|
||||
#endif /* UV_BSD_H */
|
||||
61
Utilities/cmlibuv/include/uv-darwin.h
Normal file
61
Utilities/cmlibuv/include/uv-darwin.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_DARWIN_H
|
||||
#define UV_DARWIN_H
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
# include <mach/mach.h>
|
||||
# include <mach/task.h>
|
||||
# include <mach/semaphore.h>
|
||||
# include <TargetConditionals.h>
|
||||
# define UV_PLATFORM_SEM_T semaphore_t
|
||||
#endif
|
||||
|
||||
#define UV_IO_PRIVATE_PLATFORM_FIELDS \
|
||||
int rcount; \
|
||||
int wcount; \
|
||||
|
||||
#define UV_PLATFORM_LOOP_FIELDS \
|
||||
uv_thread_t cf_thread; \
|
||||
void* _cf_reserved; \
|
||||
void* cf_state; \
|
||||
uv_mutex_t cf_mutex; \
|
||||
uv_sem_t cf_sem; \
|
||||
void* cf_signals[2]; \
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
uv__io_t event_watcher; \
|
||||
char* realpath; \
|
||||
int realpath_len; \
|
||||
int cf_flags; \
|
||||
uv_async_t* cf_cb; \
|
||||
void* cf_events[2]; \
|
||||
void* cf_member[2]; \
|
||||
int cf_error; \
|
||||
uv_mutex_t cf_mutex; \
|
||||
|
||||
#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
|
||||
void* select; \
|
||||
|
||||
#define UV_HAVE_KQUEUE 1
|
||||
|
||||
#endif /* UV_DARWIN_H */
|
||||
419
Utilities/cmlibuv/include/uv-errno.h
Normal file
419
Utilities/cmlibuv/include/uv-errno.h
Normal file
@@ -0,0 +1,419 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_ERRNO_H_
|
||||
#define UV_ERRNO_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define UV__EOF (-4095)
|
||||
#define UV__UNKNOWN (-4094)
|
||||
|
||||
#define UV__EAI_ADDRFAMILY (-3000)
|
||||
#define UV__EAI_AGAIN (-3001)
|
||||
#define UV__EAI_BADFLAGS (-3002)
|
||||
#define UV__EAI_CANCELED (-3003)
|
||||
#define UV__EAI_FAIL (-3004)
|
||||
#define UV__EAI_FAMILY (-3005)
|
||||
#define UV__EAI_MEMORY (-3006)
|
||||
#define UV__EAI_NODATA (-3007)
|
||||
#define UV__EAI_NONAME (-3008)
|
||||
#define UV__EAI_OVERFLOW (-3009)
|
||||
#define UV__EAI_SERVICE (-3010)
|
||||
#define UV__EAI_SOCKTYPE (-3011)
|
||||
#define UV__EAI_BADHINTS (-3013)
|
||||
#define UV__EAI_PROTOCOL (-3014)
|
||||
|
||||
/* Only map to the system errno on non-Windows platforms. It's apparently
|
||||
* a fairly common practice for Windows programmers to redefine errno codes.
|
||||
*/
|
||||
#if defined(E2BIG) && !defined(_WIN32)
|
||||
# define UV__E2BIG (-E2BIG)
|
||||
#else
|
||||
# define UV__E2BIG (-4093)
|
||||
#endif
|
||||
|
||||
#if defined(EACCES) && !defined(_WIN32)
|
||||
# define UV__EACCES (-EACCES)
|
||||
#else
|
||||
# define UV__EACCES (-4092)
|
||||
#endif
|
||||
|
||||
#if defined(EADDRINUSE) && !defined(_WIN32)
|
||||
# define UV__EADDRINUSE (-EADDRINUSE)
|
||||
#else
|
||||
# define UV__EADDRINUSE (-4091)
|
||||
#endif
|
||||
|
||||
#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
|
||||
# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
|
||||
#else
|
||||
# define UV__EADDRNOTAVAIL (-4090)
|
||||
#endif
|
||||
|
||||
#if defined(EAFNOSUPPORT) && !defined(_WIN32)
|
||||
# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
|
||||
#else
|
||||
# define UV__EAFNOSUPPORT (-4089)
|
||||
#endif
|
||||
|
||||
#if defined(EAGAIN) && !defined(_WIN32)
|
||||
# define UV__EAGAIN (-EAGAIN)
|
||||
#else
|
||||
# define UV__EAGAIN (-4088)
|
||||
#endif
|
||||
|
||||
#if defined(EALREADY) && !defined(_WIN32)
|
||||
# define UV__EALREADY (-EALREADY)
|
||||
#else
|
||||
# define UV__EALREADY (-4084)
|
||||
#endif
|
||||
|
||||
#if defined(EBADF) && !defined(_WIN32)
|
||||
# define UV__EBADF (-EBADF)
|
||||
#else
|
||||
# define UV__EBADF (-4083)
|
||||
#endif
|
||||
|
||||
#if defined(EBUSY) && !defined(_WIN32)
|
||||
# define UV__EBUSY (-EBUSY)
|
||||
#else
|
||||
# define UV__EBUSY (-4082)
|
||||
#endif
|
||||
|
||||
#if defined(ECANCELED) && !defined(_WIN32)
|
||||
# define UV__ECANCELED (-ECANCELED)
|
||||
#else
|
||||
# define UV__ECANCELED (-4081)
|
||||
#endif
|
||||
|
||||
#if defined(ECHARSET) && !defined(_WIN32)
|
||||
# define UV__ECHARSET (-ECHARSET)
|
||||
#else
|
||||
# define UV__ECHARSET (-4080)
|
||||
#endif
|
||||
|
||||
#if defined(ECONNABORTED) && !defined(_WIN32)
|
||||
# define UV__ECONNABORTED (-ECONNABORTED)
|
||||
#else
|
||||
# define UV__ECONNABORTED (-4079)
|
||||
#endif
|
||||
|
||||
#if defined(ECONNREFUSED) && !defined(_WIN32)
|
||||
# define UV__ECONNREFUSED (-ECONNREFUSED)
|
||||
#else
|
||||
# define UV__ECONNREFUSED (-4078)
|
||||
#endif
|
||||
|
||||
#if defined(ECONNRESET) && !defined(_WIN32)
|
||||
# define UV__ECONNRESET (-ECONNRESET)
|
||||
#else
|
||||
# define UV__ECONNRESET (-4077)
|
||||
#endif
|
||||
|
||||
#if defined(EDESTADDRREQ) && !defined(_WIN32)
|
||||
# define UV__EDESTADDRREQ (-EDESTADDRREQ)
|
||||
#else
|
||||
# define UV__EDESTADDRREQ (-4076)
|
||||
#endif
|
||||
|
||||
#if defined(EEXIST) && !defined(_WIN32)
|
||||
# define UV__EEXIST (-EEXIST)
|
||||
#else
|
||||
# define UV__EEXIST (-4075)
|
||||
#endif
|
||||
|
||||
#if defined(EFAULT) && !defined(_WIN32)
|
||||
# define UV__EFAULT (-EFAULT)
|
||||
#else
|
||||
# define UV__EFAULT (-4074)
|
||||
#endif
|
||||
|
||||
#if defined(EHOSTUNREACH) && !defined(_WIN32)
|
||||
# define UV__EHOSTUNREACH (-EHOSTUNREACH)
|
||||
#else
|
||||
# define UV__EHOSTUNREACH (-4073)
|
||||
#endif
|
||||
|
||||
#if defined(EINTR) && !defined(_WIN32)
|
||||
# define UV__EINTR (-EINTR)
|
||||
#else
|
||||
# define UV__EINTR (-4072)
|
||||
#endif
|
||||
|
||||
#if defined(EINVAL) && !defined(_WIN32)
|
||||
# define UV__EINVAL (-EINVAL)
|
||||
#else
|
||||
# define UV__EINVAL (-4071)
|
||||
#endif
|
||||
|
||||
#if defined(EIO) && !defined(_WIN32)
|
||||
# define UV__EIO (-EIO)
|
||||
#else
|
||||
# define UV__EIO (-4070)
|
||||
#endif
|
||||
|
||||
#if defined(EISCONN) && !defined(_WIN32)
|
||||
# define UV__EISCONN (-EISCONN)
|
||||
#else
|
||||
# define UV__EISCONN (-4069)
|
||||
#endif
|
||||
|
||||
#if defined(EISDIR) && !defined(_WIN32)
|
||||
# define UV__EISDIR (-EISDIR)
|
||||
#else
|
||||
# define UV__EISDIR (-4068)
|
||||
#endif
|
||||
|
||||
#if defined(ELOOP) && !defined(_WIN32)
|
||||
# define UV__ELOOP (-ELOOP)
|
||||
#else
|
||||
# define UV__ELOOP (-4067)
|
||||
#endif
|
||||
|
||||
#if defined(EMFILE) && !defined(_WIN32)
|
||||
# define UV__EMFILE (-EMFILE)
|
||||
#else
|
||||
# define UV__EMFILE (-4066)
|
||||
#endif
|
||||
|
||||
#if defined(EMSGSIZE) && !defined(_WIN32)
|
||||
# define UV__EMSGSIZE (-EMSGSIZE)
|
||||
#else
|
||||
# define UV__EMSGSIZE (-4065)
|
||||
#endif
|
||||
|
||||
#if defined(ENAMETOOLONG) && !defined(_WIN32)
|
||||
# define UV__ENAMETOOLONG (-ENAMETOOLONG)
|
||||
#else
|
||||
# define UV__ENAMETOOLONG (-4064)
|
||||
#endif
|
||||
|
||||
#if defined(ENETDOWN) && !defined(_WIN32)
|
||||
# define UV__ENETDOWN (-ENETDOWN)
|
||||
#else
|
||||
# define UV__ENETDOWN (-4063)
|
||||
#endif
|
||||
|
||||
#if defined(ENETUNREACH) && !defined(_WIN32)
|
||||
# define UV__ENETUNREACH (-ENETUNREACH)
|
||||
#else
|
||||
# define UV__ENETUNREACH (-4062)
|
||||
#endif
|
||||
|
||||
#if defined(ENFILE) && !defined(_WIN32)
|
||||
# define UV__ENFILE (-ENFILE)
|
||||
#else
|
||||
# define UV__ENFILE (-4061)
|
||||
#endif
|
||||
|
||||
#if defined(ENOBUFS) && !defined(_WIN32)
|
||||
# define UV__ENOBUFS (-ENOBUFS)
|
||||
#else
|
||||
# define UV__ENOBUFS (-4060)
|
||||
#endif
|
||||
|
||||
#if defined(ENODEV) && !defined(_WIN32)
|
||||
# define UV__ENODEV (-ENODEV)
|
||||
#else
|
||||
# define UV__ENODEV (-4059)
|
||||
#endif
|
||||
|
||||
#if defined(ENOENT) && !defined(_WIN32)
|
||||
# define UV__ENOENT (-ENOENT)
|
||||
#else
|
||||
# define UV__ENOENT (-4058)
|
||||
#endif
|
||||
|
||||
#if defined(ENOMEM) && !defined(_WIN32)
|
||||
# define UV__ENOMEM (-ENOMEM)
|
||||
#else
|
||||
# define UV__ENOMEM (-4057)
|
||||
#endif
|
||||
|
||||
#if defined(ENONET) && !defined(_WIN32)
|
||||
# define UV__ENONET (-ENONET)
|
||||
#else
|
||||
# define UV__ENONET (-4056)
|
||||
#endif
|
||||
|
||||
#if defined(ENOSPC) && !defined(_WIN32)
|
||||
# define UV__ENOSPC (-ENOSPC)
|
||||
#else
|
||||
# define UV__ENOSPC (-4055)
|
||||
#endif
|
||||
|
||||
#if defined(ENOSYS) && !defined(_WIN32)
|
||||
# define UV__ENOSYS (-ENOSYS)
|
||||
#else
|
||||
# define UV__ENOSYS (-4054)
|
||||
#endif
|
||||
|
||||
#if defined(ENOTCONN) && !defined(_WIN32)
|
||||
# define UV__ENOTCONN (-ENOTCONN)
|
||||
#else
|
||||
# define UV__ENOTCONN (-4053)
|
||||
#endif
|
||||
|
||||
#if defined(ENOTDIR) && !defined(_WIN32)
|
||||
# define UV__ENOTDIR (-ENOTDIR)
|
||||
#else
|
||||
# define UV__ENOTDIR (-4052)
|
||||
#endif
|
||||
|
||||
#if defined(ENOTEMPTY) && !defined(_WIN32)
|
||||
# define UV__ENOTEMPTY (-ENOTEMPTY)
|
||||
#else
|
||||
# define UV__ENOTEMPTY (-4051)
|
||||
#endif
|
||||
|
||||
#if defined(ENOTSOCK) && !defined(_WIN32)
|
||||
# define UV__ENOTSOCK (-ENOTSOCK)
|
||||
#else
|
||||
# define UV__ENOTSOCK (-4050)
|
||||
#endif
|
||||
|
||||
#if defined(ENOTSUP) && !defined(_WIN32)
|
||||
# define UV__ENOTSUP (-ENOTSUP)
|
||||
#else
|
||||
# define UV__ENOTSUP (-4049)
|
||||
#endif
|
||||
|
||||
#if defined(EPERM) && !defined(_WIN32)
|
||||
# define UV__EPERM (-EPERM)
|
||||
#else
|
||||
# define UV__EPERM (-4048)
|
||||
#endif
|
||||
|
||||
#if defined(EPIPE) && !defined(_WIN32)
|
||||
# define UV__EPIPE (-EPIPE)
|
||||
#else
|
||||
# define UV__EPIPE (-4047)
|
||||
#endif
|
||||
|
||||
#if defined(EPROTO) && !defined(_WIN32)
|
||||
# define UV__EPROTO (-EPROTO)
|
||||
#else
|
||||
# define UV__EPROTO (-4046)
|
||||
#endif
|
||||
|
||||
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
|
||||
# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
|
||||
#else
|
||||
# define UV__EPROTONOSUPPORT (-4045)
|
||||
#endif
|
||||
|
||||
#if defined(EPROTOTYPE) && !defined(_WIN32)
|
||||
# define UV__EPROTOTYPE (-EPROTOTYPE)
|
||||
#else
|
||||
# define UV__EPROTOTYPE (-4044)
|
||||
#endif
|
||||
|
||||
#if defined(EROFS) && !defined(_WIN32)
|
||||
# define UV__EROFS (-EROFS)
|
||||
#else
|
||||
# define UV__EROFS (-4043)
|
||||
#endif
|
||||
|
||||
#if defined(ESHUTDOWN) && !defined(_WIN32)
|
||||
# define UV__ESHUTDOWN (-ESHUTDOWN)
|
||||
#else
|
||||
# define UV__ESHUTDOWN (-4042)
|
||||
#endif
|
||||
|
||||
#if defined(ESPIPE) && !defined(_WIN32)
|
||||
# define UV__ESPIPE (-ESPIPE)
|
||||
#else
|
||||
# define UV__ESPIPE (-4041)
|
||||
#endif
|
||||
|
||||
#if defined(ESRCH) && !defined(_WIN32)
|
||||
# define UV__ESRCH (-ESRCH)
|
||||
#else
|
||||
# define UV__ESRCH (-4040)
|
||||
#endif
|
||||
|
||||
#if defined(ETIMEDOUT) && !defined(_WIN32)
|
||||
# define UV__ETIMEDOUT (-ETIMEDOUT)
|
||||
#else
|
||||
# define UV__ETIMEDOUT (-4039)
|
||||
#endif
|
||||
|
||||
#if defined(ETXTBSY) && !defined(_WIN32)
|
||||
# define UV__ETXTBSY (-ETXTBSY)
|
||||
#else
|
||||
# define UV__ETXTBSY (-4038)
|
||||
#endif
|
||||
|
||||
#if defined(EXDEV) && !defined(_WIN32)
|
||||
# define UV__EXDEV (-EXDEV)
|
||||
#else
|
||||
# define UV__EXDEV (-4037)
|
||||
#endif
|
||||
|
||||
#if defined(EFBIG) && !defined(_WIN32)
|
||||
# define UV__EFBIG (-EFBIG)
|
||||
#else
|
||||
# define UV__EFBIG (-4036)
|
||||
#endif
|
||||
|
||||
#if defined(ENOPROTOOPT) && !defined(_WIN32)
|
||||
# define UV__ENOPROTOOPT (-ENOPROTOOPT)
|
||||
#else
|
||||
# define UV__ENOPROTOOPT (-4035)
|
||||
#endif
|
||||
|
||||
#if defined(ERANGE) && !defined(_WIN32)
|
||||
# define UV__ERANGE (-ERANGE)
|
||||
#else
|
||||
# define UV__ERANGE (-4034)
|
||||
#endif
|
||||
|
||||
#if defined(ENXIO) && !defined(_WIN32)
|
||||
# define UV__ENXIO (-ENXIO)
|
||||
#else
|
||||
# define UV__ENXIO (-4033)
|
||||
#endif
|
||||
|
||||
#if defined(EMLINK) && !defined(_WIN32)
|
||||
# define UV__EMLINK (-EMLINK)
|
||||
#else
|
||||
# define UV__EMLINK (-4032)
|
||||
#endif
|
||||
|
||||
/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
|
||||
* defined. Fortunately, its value is always 64 so it's possible albeit
|
||||
* icky to hard-code it.
|
||||
*/
|
||||
#if defined(EHOSTDOWN) && !defined(_WIN32)
|
||||
# define UV__EHOSTDOWN (-EHOSTDOWN)
|
||||
#elif defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
# define UV__EHOSTDOWN (-64)
|
||||
#else
|
||||
# define UV__EHOSTDOWN (-4031)
|
||||
#endif
|
||||
|
||||
#endif /* UV_ERRNO_H_ */
|
||||
34
Utilities/cmlibuv/include/uv-linux.h
Normal file
34
Utilities/cmlibuv/include/uv-linux.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_LINUX_H
|
||||
#define UV_LINUX_H
|
||||
|
||||
#define UV_PLATFORM_LOOP_FIELDS \
|
||||
uv__io_t inotify_read_watcher; \
|
||||
void* inotify_watchers; \
|
||||
int inotify_fd; \
|
||||
|
||||
#define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
void* watchers[2]; \
|
||||
int wd; \
|
||||
|
||||
#endif /* UV_LINUX_H */
|
||||
27
Utilities/cmlibuv/include/uv-os390.h
Normal file
27
Utilities/cmlibuv/include/uv-os390.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_MVS_H
|
||||
#define UV_MVS_H
|
||||
|
||||
#define UV_PLATFORM_SEM_T int
|
||||
|
||||
#endif /* UV_MVS_H */
|
||||
44
Utilities/cmlibuv/include/uv-sunos.h
Normal file
44
Utilities/cmlibuv/include/uv-sunos.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SUNOS_H
|
||||
#define UV_SUNOS_H
|
||||
|
||||
#include <sys/port.h>
|
||||
#include <port.h>
|
||||
|
||||
/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c,
|
||||
* add the fs_event fields even when this version of SunOS doesn't support
|
||||
* file watching.
|
||||
*/
|
||||
#define UV_PLATFORM_LOOP_FIELDS \
|
||||
uv__io_t fs_event_watcher; \
|
||||
int fs_fd; \
|
||||
|
||||
#if defined(PORT_SOURCE_FILE)
|
||||
|
||||
# define UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
file_obj_t fo; \
|
||||
int fd; \
|
||||
|
||||
#endif /* defined(PORT_SOURCE_FILE) */
|
||||
|
||||
#endif /* UV_SUNOS_H */
|
||||
37
Utilities/cmlibuv/include/uv-threadpool.h
Normal file
37
Utilities/cmlibuv/include/uv-threadpool.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is private to libuv. It provides common functionality to both
|
||||
* Windows and Unix backends.
|
||||
*/
|
||||
|
||||
#ifndef UV_THREADPOOL_H_
|
||||
#define UV_THREADPOOL_H_
|
||||
|
||||
struct uv__work {
|
||||
void (*work)(struct uv__work *w);
|
||||
void (*done)(struct uv__work *w, int status);
|
||||
struct uv_loop_s* loop;
|
||||
void* wq[2];
|
||||
};
|
||||
|
||||
#endif /* UV_THREADPOOL_H_ */
|
||||
371
Utilities/cmlibuv/include/uv-unix.h
Normal file
371
Utilities/cmlibuv/include/uv-unix.h
Normal file
@@ -0,0 +1,371 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_UNIX_H
|
||||
#define UV_UNIX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <termios.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "uv-threadpool.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "uv-linux.h"
|
||||
#elif defined(_AIX)
|
||||
# include "uv-aix.h"
|
||||
#elif defined(__sun)
|
||||
# include "uv-sunos.h"
|
||||
#elif defined(__APPLE__)
|
||||
# include "uv-darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "uv-bsd.h"
|
||||
#endif
|
||||
|
||||
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
|
||||
# include "pthread-barrier.h"
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif
|
||||
|
||||
#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
|
||||
# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
|
||||
#endif
|
||||
|
||||
struct uv__io_s;
|
||||
struct uv__async;
|
||||
struct uv_loop_s;
|
||||
|
||||
typedef void (*uv__io_cb)(struct uv_loop_s* loop,
|
||||
struct uv__io_s* w,
|
||||
unsigned int events);
|
||||
typedef struct uv__io_s uv__io_t;
|
||||
|
||||
struct uv__io_s {
|
||||
uv__io_cb cb;
|
||||
void* pending_queue[2];
|
||||
void* watcher_queue[2];
|
||||
unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
|
||||
unsigned int events; /* Current event mask. */
|
||||
int fd;
|
||||
UV_IO_PRIVATE_PLATFORM_FIELDS
|
||||
};
|
||||
|
||||
typedef void (*uv__async_cb)(struct uv_loop_s* loop,
|
||||
struct uv__async* w,
|
||||
unsigned int nevents);
|
||||
|
||||
struct uv__async {
|
||||
uv__async_cb cb;
|
||||
uv__io_t io_watcher;
|
||||
int wfd;
|
||||
};
|
||||
|
||||
#ifndef UV_PLATFORM_SEM_T
|
||||
# define UV_PLATFORM_SEM_T sem_t
|
||||
#endif
|
||||
|
||||
#ifndef UV_PLATFORM_LOOP_FIELDS
|
||||
# define UV_PLATFORM_LOOP_FIELDS /* empty */
|
||||
#endif
|
||||
|
||||
#ifndef UV_PLATFORM_FS_EVENT_FIELDS
|
||||
# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
|
||||
#endif
|
||||
|
||||
#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS
|
||||
# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */
|
||||
#endif
|
||||
|
||||
/* Note: May be cast to struct iovec. See writev(2). */
|
||||
typedef struct uv_buf_t {
|
||||
char* base;
|
||||
size_t len;
|
||||
} uv_buf_t;
|
||||
|
||||
typedef int uv_file;
|
||||
typedef int uv_os_sock_t;
|
||||
typedef int uv_os_fd_t;
|
||||
|
||||
#define UV_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
typedef pthread_once_t uv_once_t;
|
||||
typedef pthread_t uv_thread_t;
|
||||
typedef pthread_mutex_t uv_mutex_t;
|
||||
typedef pthread_rwlock_t uv_rwlock_t;
|
||||
typedef UV_PLATFORM_SEM_T uv_sem_t;
|
||||
typedef pthread_cond_t uv_cond_t;
|
||||
typedef pthread_key_t uv_key_t;
|
||||
typedef pthread_barrier_t uv_barrier_t;
|
||||
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
typedef gid_t uv_gid_t;
|
||||
typedef uid_t uv_uid_t;
|
||||
|
||||
typedef struct dirent uv__dirent_t;
|
||||
|
||||
#if defined(DT_UNKNOWN)
|
||||
# define HAVE_DIRENT_TYPES
|
||||
# if defined(DT_REG)
|
||||
# define UV__DT_FILE DT_REG
|
||||
# else
|
||||
# define UV__DT_FILE -1
|
||||
# endif
|
||||
# if defined(DT_DIR)
|
||||
# define UV__DT_DIR DT_DIR
|
||||
# else
|
||||
# define UV__DT_DIR -2
|
||||
# endif
|
||||
# if defined(DT_LNK)
|
||||
# define UV__DT_LINK DT_LNK
|
||||
# else
|
||||
# define UV__DT_LINK -3
|
||||
# endif
|
||||
# if defined(DT_FIFO)
|
||||
# define UV__DT_FIFO DT_FIFO
|
||||
# else
|
||||
# define UV__DT_FIFO -4
|
||||
# endif
|
||||
# if defined(DT_SOCK)
|
||||
# define UV__DT_SOCKET DT_SOCK
|
||||
# else
|
||||
# define UV__DT_SOCKET -5
|
||||
# endif
|
||||
# if defined(DT_CHR)
|
||||
# define UV__DT_CHAR DT_CHR
|
||||
# else
|
||||
# define UV__DT_CHAR -6
|
||||
# endif
|
||||
# if defined(DT_BLK)
|
||||
# define UV__DT_BLOCK DT_BLK
|
||||
# else
|
||||
# define UV__DT_BLOCK -7
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Platform-specific definitions for uv_dlopen support. */
|
||||
#define UV_DYNAMIC /* empty */
|
||||
|
||||
typedef struct {
|
||||
void* handle;
|
||||
char* errmsg;
|
||||
} uv_lib_t;
|
||||
|
||||
#define UV_LOOP_PRIVATE_FIELDS \
|
||||
unsigned long flags; \
|
||||
int backend_fd; \
|
||||
void* pending_queue[2]; \
|
||||
void* watcher_queue[2]; \
|
||||
uv__io_t** watchers; \
|
||||
unsigned int nwatchers; \
|
||||
unsigned int nfds; \
|
||||
void* wq[2]; \
|
||||
uv_mutex_t wq_mutex; \
|
||||
uv_async_t wq_async; \
|
||||
uv_rwlock_t cloexec_lock; \
|
||||
uv_handle_t* closing_handles; \
|
||||
void* process_handles[2]; \
|
||||
void* prepare_handles[2]; \
|
||||
void* check_handles[2]; \
|
||||
void* idle_handles[2]; \
|
||||
void* async_handles[2]; \
|
||||
struct uv__async async_watcher; \
|
||||
struct { \
|
||||
void* min; \
|
||||
unsigned int nelts; \
|
||||
} timer_heap; \
|
||||
uint64_t timer_counter; \
|
||||
uint64_t time; \
|
||||
int signal_pipefd[2]; \
|
||||
uv__io_t signal_io_watcher; \
|
||||
uv_signal_t child_watcher; \
|
||||
int emfile_fd; \
|
||||
UV_PLATFORM_LOOP_FIELDS \
|
||||
|
||||
#define UV_REQ_TYPE_PRIVATE /* empty */
|
||||
|
||||
#define UV_REQ_PRIVATE_FIELDS /* empty */
|
||||
|
||||
#define UV_PRIVATE_REQ_TYPES /* empty */
|
||||
|
||||
#define UV_WRITE_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
unsigned int write_index; \
|
||||
uv_buf_t* bufs; \
|
||||
unsigned int nbufs; \
|
||||
int error; \
|
||||
uv_buf_t bufsml[4]; \
|
||||
|
||||
#define UV_CONNECT_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
|
||||
#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
|
||||
|
||||
#define UV_UDP_SEND_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
struct sockaddr_storage addr; \
|
||||
unsigned int nbufs; \
|
||||
uv_buf_t* bufs; \
|
||||
ssize_t status; \
|
||||
uv_udp_send_cb send_cb; \
|
||||
uv_buf_t bufsml[4]; \
|
||||
|
||||
#define UV_HANDLE_PRIVATE_FIELDS \
|
||||
uv_handle_t* next_closing; \
|
||||
unsigned int flags; \
|
||||
|
||||
#define UV_STREAM_PRIVATE_FIELDS \
|
||||
uv_connect_t *connect_req; \
|
||||
uv_shutdown_t *shutdown_req; \
|
||||
uv__io_t io_watcher; \
|
||||
void* write_queue[2]; \
|
||||
void* write_completed_queue[2]; \
|
||||
uv_connection_cb connection_cb; \
|
||||
int delayed_error; \
|
||||
int accepted_fd; \
|
||||
void* queued_fds; \
|
||||
UV_STREAM_PRIVATE_PLATFORM_FIELDS \
|
||||
|
||||
#define UV_TCP_PRIVATE_FIELDS /* empty */
|
||||
|
||||
#define UV_UDP_PRIVATE_FIELDS \
|
||||
uv_alloc_cb alloc_cb; \
|
||||
uv_udp_recv_cb recv_cb; \
|
||||
uv__io_t io_watcher; \
|
||||
void* write_queue[2]; \
|
||||
void* write_completed_queue[2]; \
|
||||
|
||||
#define UV_PIPE_PRIVATE_FIELDS \
|
||||
const char* pipe_fname; /* strdup'ed */
|
||||
|
||||
#define UV_POLL_PRIVATE_FIELDS \
|
||||
uv__io_t io_watcher;
|
||||
|
||||
#define UV_PREPARE_PRIVATE_FIELDS \
|
||||
uv_prepare_cb prepare_cb; \
|
||||
void* queue[2]; \
|
||||
|
||||
#define UV_CHECK_PRIVATE_FIELDS \
|
||||
uv_check_cb check_cb; \
|
||||
void* queue[2]; \
|
||||
|
||||
#define UV_IDLE_PRIVATE_FIELDS \
|
||||
uv_idle_cb idle_cb; \
|
||||
void* queue[2]; \
|
||||
|
||||
#define UV_ASYNC_PRIVATE_FIELDS \
|
||||
uv_async_cb async_cb; \
|
||||
void* queue[2]; \
|
||||
int pending; \
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
uv_timer_cb timer_cb; \
|
||||
void* heap_node[3]; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id;
|
||||
|
||||
#define UV_GETADDRINFO_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
uv_getaddrinfo_cb cb; \
|
||||
struct addrinfo* hints; \
|
||||
char* hostname; \
|
||||
char* service; \
|
||||
struct addrinfo* addrinfo; \
|
||||
int retcode;
|
||||
|
||||
#define UV_GETNAMEINFO_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
uv_getnameinfo_cb getnameinfo_cb; \
|
||||
struct sockaddr_storage storage; \
|
||||
int flags; \
|
||||
char host[NI_MAXHOST]; \
|
||||
char service[NI_MAXSERV]; \
|
||||
int retcode;
|
||||
|
||||
#define UV_PROCESS_PRIVATE_FIELDS \
|
||||
void* queue[2]; \
|
||||
int status; \
|
||||
|
||||
#define UV_FS_PRIVATE_FIELDS \
|
||||
const char *new_path; \
|
||||
uv_file file; \
|
||||
int flags; \
|
||||
mode_t mode; \
|
||||
unsigned int nbufs; \
|
||||
uv_buf_t* bufs; \
|
||||
off_t off; \
|
||||
uv_uid_t uid; \
|
||||
uv_gid_t gid; \
|
||||
double atime; \
|
||||
double mtime; \
|
||||
struct uv__work work_req; \
|
||||
uv_buf_t bufsml[4]; \
|
||||
|
||||
#define UV_WORK_PRIVATE_FIELDS \
|
||||
struct uv__work work_req;
|
||||
|
||||
#define UV_TTY_PRIVATE_FIELDS \
|
||||
struct termios orig_termios; \
|
||||
int mode;
|
||||
|
||||
#define UV_SIGNAL_PRIVATE_FIELDS \
|
||||
/* RB_ENTRY(uv_signal_s) tree_entry; */ \
|
||||
struct { \
|
||||
struct uv_signal_s* rbe_left; \
|
||||
struct uv_signal_s* rbe_right; \
|
||||
struct uv_signal_s* rbe_parent; \
|
||||
int rbe_color; \
|
||||
} tree_entry; \
|
||||
/* Use two counters here so we don have to fiddle with atomics. */ \
|
||||
unsigned int caught_signals; \
|
||||
unsigned int dispatched_signals;
|
||||
|
||||
#define UV_FS_EVENT_PRIVATE_FIELDS \
|
||||
uv_fs_event_cb cb; \
|
||||
UV_PLATFORM_FS_EVENT_FIELDS \
|
||||
|
||||
#endif /* UV_UNIX_H */
|
||||
43
Utilities/cmlibuv/include/uv-version.h
Normal file
43
Utilities/cmlibuv/include/uv-version.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_VERSION_H
|
||||
#define UV_VERSION_H
|
||||
|
||||
/*
|
||||
* Versions with the same major number are ABI stable. API is allowed to
|
||||
* evolve between minor releases, but only in a backwards compatible way.
|
||||
* Make sure you update the -soname directives in configure.ac
|
||||
* and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
|
||||
* not UV_VERSION_PATCH.)
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 9
|
||||
#define UV_VERSION_PATCH 2
|
||||
#define UV_VERSION_IS_RELEASE 0
|
||||
#define UV_VERSION_SUFFIX "dev"
|
||||
|
||||
#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
|
||||
(UV_VERSION_MINOR << 8) | \
|
||||
(UV_VERSION_PATCH))
|
||||
|
||||
#endif /* UV_VERSION_H */
|
||||
660
Utilities/cmlibuv/include/uv-win.h
Normal file
660
Utilities/cmlibuv/include/uv-win.h
Normal file
@@ -0,0 +1,660 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0502
|
||||
#endif
|
||||
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
# define _SSIZE_T_
|
||||
# define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
||||
typedef struct pollfd {
|
||||
SOCKET fd;
|
||||
short events;
|
||||
short revents;
|
||||
} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
|
||||
#endif
|
||||
|
||||
#ifndef LOCALE_INVARIANT
|
||||
# define LOCALE_INVARIANT 0x007f
|
||||
#endif
|
||||
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <process.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "tree.h"
|
||||
#include "uv-threadpool.h"
|
||||
|
||||
#define MAX_PIPENAME_LEN 256
|
||||
|
||||
#ifndef S_IFLNK
|
||||
# define S_IFLNK 0xA000
|
||||
#endif
|
||||
|
||||
/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
|
||||
* the following signals already:
|
||||
*
|
||||
* #define SIGINT 2
|
||||
* #define SIGILL 4
|
||||
* #define SIGABRT_COMPAT 6
|
||||
* #define SIGFPE 8
|
||||
* #define SIGSEGV 11
|
||||
* #define SIGTERM 15
|
||||
* #define SIGBREAK 21
|
||||
* #define SIGABRT 22
|
||||
*
|
||||
* The additional signals have values that are common on other Unix
|
||||
* variants (Linux and Darwin)
|
||||
*/
|
||||
#define SIGHUP 1
|
||||
#define SIGKILL 9
|
||||
#define SIGWINCH 28
|
||||
|
||||
/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
|
||||
/* unix-like platforms. However MinGW doesn't define it, so we do. */
|
||||
#ifndef SIGABRT_COMPAT
|
||||
# define SIGABRT_COMPAT 6
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Guids and typedefs for winsock extension functions
|
||||
* Mingw32 doesn't have these :-(
|
||||
*/
|
||||
#ifndef WSAID_ACCEPTEX
|
||||
# define WSAID_ACCEPTEX \
|
||||
{0xb5367df1, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
#endif
|
||||
|
||||
#ifndef WSAID_CONNECTEX
|
||||
# define WSAID_CONNECTEX \
|
||||
{0x25a207b9, 0xddf3, 0x4660, \
|
||||
{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
|
||||
#endif
|
||||
|
||||
#ifndef WSAID_GETACCEPTEXSOCKADDRS
|
||||
# define WSAID_GETACCEPTEXSOCKADDRS \
|
||||
{0xb5367df2, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
#endif
|
||||
|
||||
#ifndef WSAID_DISCONNECTEX
|
||||
# define WSAID_DISCONNECTEX \
|
||||
{0x7fda2e11, 0x8630, 0x436f, \
|
||||
{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
|
||||
#endif
|
||||
|
||||
#ifndef WSAID_TRANSMITFILE
|
||||
# define WSAID_TRANSMITFILE \
|
||||
{0xb5367df0, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
#endif
|
||||
|
||||
#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \
|
||||
|| (defined(_MSC_VER) && _MSC_VER < 1500)
|
||||
typedef BOOL (PASCAL *LPFN_ACCEPTEX)
|
||||
(SOCKET sListenSocket,
|
||||
SOCKET sAcceptSocket,
|
||||
PVOID lpOutputBuffer,
|
||||
DWORD dwReceiveDataLength,
|
||||
DWORD dwLocalAddressLength,
|
||||
DWORD dwRemoteAddressLength,
|
||||
LPDWORD lpdwBytesReceived,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef BOOL (PASCAL *LPFN_CONNECTEX)
|
||||
(SOCKET s,
|
||||
const struct sockaddr* name,
|
||||
int namelen,
|
||||
PVOID lpSendBuffer,
|
||||
DWORD dwSendDataLength,
|
||||
LPDWORD lpdwBytesSent,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS)
|
||||
(PVOID lpOutputBuffer,
|
||||
DWORD dwReceiveDataLength,
|
||||
DWORD dwLocalAddressLength,
|
||||
DWORD dwRemoteAddressLength,
|
||||
LPSOCKADDR* LocalSockaddr,
|
||||
LPINT LocalSockaddrLength,
|
||||
LPSOCKADDR* RemoteSockaddr,
|
||||
LPINT RemoteSockaddrLength);
|
||||
|
||||
typedef BOOL (PASCAL *LPFN_DISCONNECTEX)
|
||||
(SOCKET hSocket,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
DWORD dwFlags,
|
||||
DWORD reserved);
|
||||
|
||||
typedef BOOL (PASCAL *LPFN_TRANSMITFILE)
|
||||
(SOCKET hSocket,
|
||||
HANDLE hFile,
|
||||
DWORD nNumberOfBytesToWrite,
|
||||
DWORD nNumberOfBytesPerSend,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
|
||||
DWORD dwFlags);
|
||||
|
||||
typedef PVOID RTL_SRWLOCK;
|
||||
typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
|
||||
#endif
|
||||
|
||||
typedef int (WSAAPI* LPFN_WSARECV)
|
||||
(SOCKET socket,
|
||||
LPWSABUF buffers,
|
||||
DWORD buffer_count,
|
||||
LPDWORD bytes,
|
||||
LPDWORD flags,
|
||||
LPWSAOVERLAPPED overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||
|
||||
typedef int (WSAAPI* LPFN_WSARECVFROM)
|
||||
(SOCKET socket,
|
||||
LPWSABUF buffers,
|
||||
DWORD buffer_count,
|
||||
LPDWORD bytes,
|
||||
LPDWORD flags,
|
||||
struct sockaddr* addr,
|
||||
LPINT addr_len,
|
||||
LPWSAOVERLAPPED overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||
|
||||
#ifndef _NTDEF_
|
||||
typedef LONG NTSTATUS;
|
||||
typedef NTSTATUS *PNTSTATUS;
|
||||
#endif
|
||||
|
||||
#ifndef RTL_CONDITION_VARIABLE_INIT
|
||||
typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
|
||||
#endif
|
||||
|
||||
typedef struct _AFD_POLL_HANDLE_INFO {
|
||||
HANDLE Handle;
|
||||
ULONG Events;
|
||||
NTSTATUS Status;
|
||||
} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
|
||||
|
||||
typedef struct _AFD_POLL_INFO {
|
||||
LARGE_INTEGER Timeout;
|
||||
ULONG NumberOfHandles;
|
||||
ULONG Exclusive;
|
||||
AFD_POLL_HANDLE_INFO Handles[1];
|
||||
} AFD_POLL_INFO, *PAFD_POLL_INFO;
|
||||
|
||||
#define UV_MSAFD_PROVIDER_COUNT 3
|
||||
|
||||
|
||||
/**
|
||||
* It should be possible to cast uv_buf_t[] to WSABUF[]
|
||||
* see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx
|
||||
*/
|
||||
typedef struct uv_buf_t {
|
||||
ULONG len;
|
||||
char* base;
|
||||
} uv_buf_t;
|
||||
|
||||
typedef int uv_file;
|
||||
typedef SOCKET uv_os_sock_t;
|
||||
typedef HANDLE uv_os_fd_t;
|
||||
|
||||
typedef HANDLE uv_thread_t;
|
||||
|
||||
typedef HANDLE uv_sem_t;
|
||||
|
||||
typedef CRITICAL_SECTION uv_mutex_t;
|
||||
|
||||
/* This condition variable implementation is based on the SetEvent solution
|
||||
* (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||
* We could not use the SignalObjectAndWait solution (section 3.4) because
|
||||
* it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
|
||||
* uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
CONDITION_VARIABLE cond_var;
|
||||
struct {
|
||||
unsigned int waiters_count;
|
||||
CRITICAL_SECTION waiters_count_lock;
|
||||
HANDLE signal_event;
|
||||
HANDLE broadcast_event;
|
||||
} fallback;
|
||||
} uv_cond_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned int num_readers_;
|
||||
CRITICAL_SECTION num_readers_lock_;
|
||||
HANDLE write_semaphore_;
|
||||
} state_;
|
||||
/* TODO: remove me in v2.x. */
|
||||
struct {
|
||||
SRWLOCK unused_;
|
||||
} unused1_;
|
||||
/* TODO: remove me in v2.x. */
|
||||
struct {
|
||||
uv_mutex_t unused1_;
|
||||
uv_mutex_t unused2_;
|
||||
} unused2_;
|
||||
} uv_rwlock_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int n;
|
||||
unsigned int count;
|
||||
uv_mutex_t mutex;
|
||||
uv_sem_t turnstile1;
|
||||
uv_sem_t turnstile2;
|
||||
} uv_barrier_t;
|
||||
|
||||
typedef struct {
|
||||
DWORD tls_index;
|
||||
} uv_key_t;
|
||||
|
||||
#define UV_ONCE_INIT { 0, NULL }
|
||||
|
||||
typedef struct uv_once_s {
|
||||
unsigned char ran;
|
||||
HANDLE event;
|
||||
} uv_once_t;
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
typedef unsigned char uv_uid_t;
|
||||
typedef unsigned char uv_gid_t;
|
||||
|
||||
typedef struct uv__dirent_s {
|
||||
int d_type;
|
||||
char d_name[1];
|
||||
} uv__dirent_t;
|
||||
|
||||
#define HAVE_DIRENT_TYPES
|
||||
#define UV__DT_DIR UV_DIRENT_DIR
|
||||
#define UV__DT_FILE UV_DIRENT_FILE
|
||||
#define UV__DT_LINK UV_DIRENT_LINK
|
||||
#define UV__DT_FIFO UV_DIRENT_FIFO
|
||||
#define UV__DT_SOCKET UV_DIRENT_SOCKET
|
||||
#define UV__DT_CHAR UV_DIRENT_CHAR
|
||||
#define UV__DT_BLOCK UV_DIRENT_BLOCK
|
||||
|
||||
/* Platform-specific definitions for uv_dlopen support. */
|
||||
#define UV_DYNAMIC FAR WINAPI
|
||||
typedef struct {
|
||||
HMODULE handle;
|
||||
char* errmsg;
|
||||
} uv_lib_t;
|
||||
|
||||
RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
|
||||
#define UV_LOOP_PRIVATE_FIELDS \
|
||||
/* The loop's I/O completion port */ \
|
||||
HANDLE iocp; \
|
||||
/* The current time according to the event loop. in msecs. */ \
|
||||
uint64_t time; \
|
||||
/* Tail of a single-linked circular queue of pending reqs. If the queue */ \
|
||||
/* is empty, tail_ is NULL. If there is only one item, */ \
|
||||
/* tail_->next_req == tail_ */ \
|
||||
uv_req_t* pending_reqs_tail; \
|
||||
/* Head of a single-linked list of closed handles */ \
|
||||
uv_handle_t* endgame_handles; \
|
||||
/* The head of the timers tree */ \
|
||||
struct uv_timer_tree_s timers; \
|
||||
/* Lists of active loop (prepare / check / idle) watchers */ \
|
||||
uv_prepare_t* prepare_handles; \
|
||||
uv_check_t* check_handles; \
|
||||
uv_idle_t* idle_handles; \
|
||||
/* This pointer will refer to the prepare/check/idle handle whose */ \
|
||||
/* callback is scheduled to be called next. This is needed to allow */ \
|
||||
/* safe removal from one of the lists above while that list being */ \
|
||||
/* iterated over. */ \
|
||||
uv_prepare_t* next_prepare_handle; \
|
||||
uv_check_t* next_check_handle; \
|
||||
uv_idle_t* next_idle_handle; \
|
||||
/* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
|
||||
SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
|
||||
/* Counter to keep track of active tcp streams */ \
|
||||
unsigned int active_tcp_streams; \
|
||||
/* Counter to keep track of active udp streams */ \
|
||||
unsigned int active_udp_streams; \
|
||||
/* Counter to started timer */ \
|
||||
uint64_t timer_counter; \
|
||||
/* Threadpool */ \
|
||||
void* wq[2]; \
|
||||
uv_mutex_t wq_mutex; \
|
||||
uv_async_t wq_async;
|
||||
|
||||
#define UV_REQ_TYPE_PRIVATE \
|
||||
/* TODO: remove the req suffix */ \
|
||||
UV_ACCEPT, \
|
||||
UV_FS_EVENT_REQ, \
|
||||
UV_POLL_REQ, \
|
||||
UV_PROCESS_EXIT, \
|
||||
UV_READ, \
|
||||
UV_UDP_RECV, \
|
||||
UV_WAKEUP, \
|
||||
UV_SIGNAL_REQ,
|
||||
|
||||
#define UV_REQ_PRIVATE_FIELDS \
|
||||
union { \
|
||||
/* Used by I/O operations */ \
|
||||
struct { \
|
||||
OVERLAPPED overlapped; \
|
||||
size_t queued_bytes; \
|
||||
} io; \
|
||||
} u; \
|
||||
struct uv_req_s* next_req;
|
||||
|
||||
#define UV_WRITE_PRIVATE_FIELDS \
|
||||
int ipc_header; \
|
||||
uv_buf_t write_buffer; \
|
||||
HANDLE event_handle; \
|
||||
HANDLE wait_handle;
|
||||
|
||||
#define UV_CONNECT_PRIVATE_FIELDS \
|
||||
/* empty */
|
||||
|
||||
#define UV_SHUTDOWN_PRIVATE_FIELDS \
|
||||
/* empty */
|
||||
|
||||
#define UV_UDP_SEND_PRIVATE_FIELDS \
|
||||
/* empty */
|
||||
|
||||
#define UV_PRIVATE_REQ_TYPES \
|
||||
typedef struct uv_pipe_accept_s { \
|
||||
UV_REQ_FIELDS \
|
||||
HANDLE pipeHandle; \
|
||||
struct uv_pipe_accept_s* next_pending; \
|
||||
} uv_pipe_accept_t; \
|
||||
\
|
||||
typedef struct uv_tcp_accept_s { \
|
||||
UV_REQ_FIELDS \
|
||||
SOCKET accept_socket; \
|
||||
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
|
||||
HANDLE event_handle; \
|
||||
HANDLE wait_handle; \
|
||||
struct uv_tcp_accept_s* next_pending; \
|
||||
} uv_tcp_accept_t; \
|
||||
\
|
||||
typedef struct uv_read_s { \
|
||||
UV_REQ_FIELDS \
|
||||
HANDLE event_handle; \
|
||||
HANDLE wait_handle; \
|
||||
} uv_read_t;
|
||||
|
||||
#define uv_stream_connection_fields \
|
||||
unsigned int write_reqs_pending; \
|
||||
uv_shutdown_t* shutdown_req;
|
||||
|
||||
#define uv_stream_server_fields \
|
||||
uv_connection_cb connection_cb;
|
||||
|
||||
#define UV_STREAM_PRIVATE_FIELDS \
|
||||
unsigned int reqs_pending; \
|
||||
int activecnt; \
|
||||
uv_read_t read_req; \
|
||||
union { \
|
||||
struct { uv_stream_connection_fields } conn; \
|
||||
struct { uv_stream_server_fields } serv; \
|
||||
} stream;
|
||||
|
||||
#define uv_tcp_server_fields \
|
||||
uv_tcp_accept_t* accept_reqs; \
|
||||
unsigned int processed_accepts; \
|
||||
uv_tcp_accept_t* pending_accepts; \
|
||||
LPFN_ACCEPTEX func_acceptex;
|
||||
|
||||
#define uv_tcp_connection_fields \
|
||||
uv_buf_t read_buffer; \
|
||||
LPFN_CONNECTEX func_connectex;
|
||||
|
||||
#define UV_TCP_PRIVATE_FIELDS \
|
||||
SOCKET socket; \
|
||||
int delayed_error; \
|
||||
union { \
|
||||
struct { uv_tcp_server_fields } serv; \
|
||||
struct { uv_tcp_connection_fields } conn; \
|
||||
} tcp;
|
||||
|
||||
#define UV_UDP_PRIVATE_FIELDS \
|
||||
SOCKET socket; \
|
||||
unsigned int reqs_pending; \
|
||||
int activecnt; \
|
||||
uv_req_t recv_req; \
|
||||
uv_buf_t recv_buffer; \
|
||||
struct sockaddr_storage recv_from; \
|
||||
int recv_from_len; \
|
||||
uv_udp_recv_cb recv_cb; \
|
||||
uv_alloc_cb alloc_cb; \
|
||||
LPFN_WSARECV func_wsarecv; \
|
||||
LPFN_WSARECVFROM func_wsarecvfrom;
|
||||
|
||||
#define uv_pipe_server_fields \
|
||||
int pending_instances; \
|
||||
uv_pipe_accept_t* accept_reqs; \
|
||||
uv_pipe_accept_t* pending_accepts;
|
||||
|
||||
#define uv_pipe_connection_fields \
|
||||
uv_timer_t* eof_timer; \
|
||||
uv_write_t ipc_header_write_req; \
|
||||
int ipc_pid; \
|
||||
uint64_t remaining_ipc_rawdata_bytes; \
|
||||
struct { \
|
||||
void* queue[2]; \
|
||||
int queue_len; \
|
||||
} pending_ipc_info; \
|
||||
uv_write_t* non_overlapped_writes_tail; \
|
||||
uv_mutex_t readfile_mutex; \
|
||||
volatile HANDLE readfile_thread;
|
||||
|
||||
#define UV_PIPE_PRIVATE_FIELDS \
|
||||
HANDLE handle; \
|
||||
WCHAR* name; \
|
||||
union { \
|
||||
struct { uv_pipe_server_fields } serv; \
|
||||
struct { uv_pipe_connection_fields } conn; \
|
||||
} pipe;
|
||||
|
||||
/* TODO: put the parser states in an union - TTY handles are always */
|
||||
/* half-duplex so read-state can safely overlap write-state. */
|
||||
#define UV_TTY_PRIVATE_FIELDS \
|
||||
HANDLE handle; \
|
||||
union { \
|
||||
struct { \
|
||||
/* Used for readable TTY handles */ \
|
||||
/* TODO: remove me in v2.x. */ \
|
||||
HANDLE unused_; \
|
||||
uv_buf_t read_line_buffer; \
|
||||
HANDLE read_raw_wait; \
|
||||
/* Fields used for translating win keystrokes into vt100 characters */ \
|
||||
char last_key[8]; \
|
||||
unsigned char last_key_offset; \
|
||||
unsigned char last_key_len; \
|
||||
WCHAR last_utf16_high_surrogate; \
|
||||
INPUT_RECORD last_input_record; \
|
||||
} rd; \
|
||||
struct { \
|
||||
/* Used for writable TTY handles */ \
|
||||
/* utf8-to-utf16 conversion state */ \
|
||||
unsigned int utf8_codepoint; \
|
||||
unsigned char utf8_bytes_left; \
|
||||
/* eol conversion state */ \
|
||||
unsigned char previous_eol; \
|
||||
/* ansi parser state */ \
|
||||
unsigned char ansi_parser_state; \
|
||||
unsigned char ansi_csi_argc; \
|
||||
unsigned short ansi_csi_argv[4]; \
|
||||
COORD saved_position; \
|
||||
WORD saved_attributes; \
|
||||
} wr; \
|
||||
} tty;
|
||||
|
||||
#define UV_POLL_PRIVATE_FIELDS \
|
||||
SOCKET socket; \
|
||||
/* Used in fast mode */ \
|
||||
SOCKET peer_socket; \
|
||||
AFD_POLL_INFO afd_poll_info_1; \
|
||||
AFD_POLL_INFO afd_poll_info_2; \
|
||||
/* Used in fast and slow mode. */ \
|
||||
uv_req_t poll_req_1; \
|
||||
uv_req_t poll_req_2; \
|
||||
unsigned char submitted_events_1; \
|
||||
unsigned char submitted_events_2; \
|
||||
unsigned char mask_events_1; \
|
||||
unsigned char mask_events_2; \
|
||||
unsigned char events;
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
RB_ENTRY(uv_timer_s) tree_entry; \
|
||||
uint64_t due; \
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id; \
|
||||
uv_timer_cb timer_cb;
|
||||
|
||||
#define UV_ASYNC_PRIVATE_FIELDS \
|
||||
struct uv_req_s async_req; \
|
||||
uv_async_cb async_cb; \
|
||||
/* char to avoid alignment issues */ \
|
||||
char volatile async_sent;
|
||||
|
||||
#define UV_PREPARE_PRIVATE_FIELDS \
|
||||
uv_prepare_t* prepare_prev; \
|
||||
uv_prepare_t* prepare_next; \
|
||||
uv_prepare_cb prepare_cb;
|
||||
|
||||
#define UV_CHECK_PRIVATE_FIELDS \
|
||||
uv_check_t* check_prev; \
|
||||
uv_check_t* check_next; \
|
||||
uv_check_cb check_cb;
|
||||
|
||||
#define UV_IDLE_PRIVATE_FIELDS \
|
||||
uv_idle_t* idle_prev; \
|
||||
uv_idle_t* idle_next; \
|
||||
uv_idle_cb idle_cb;
|
||||
|
||||
#define UV_HANDLE_PRIVATE_FIELDS \
|
||||
uv_handle_t* endgame_next; \
|
||||
unsigned int flags;
|
||||
|
||||
#define UV_GETADDRINFO_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
uv_getaddrinfo_cb getaddrinfo_cb; \
|
||||
void* alloc; \
|
||||
WCHAR* node; \
|
||||
WCHAR* service; \
|
||||
/* The addrinfoW field is used to store a pointer to the hints, and */ \
|
||||
/* later on to store the result of GetAddrInfoW. The final result will */ \
|
||||
/* be converted to struct addrinfo* and stored in the addrinfo field. */ \
|
||||
struct addrinfoW* addrinfow; \
|
||||
struct addrinfo* addrinfo; \
|
||||
int retcode;
|
||||
|
||||
#define UV_GETNAMEINFO_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
uv_getnameinfo_cb getnameinfo_cb; \
|
||||
struct sockaddr_storage storage; \
|
||||
int flags; \
|
||||
char host[NI_MAXHOST]; \
|
||||
char service[NI_MAXSERV]; \
|
||||
int retcode;
|
||||
|
||||
#define UV_PROCESS_PRIVATE_FIELDS \
|
||||
struct uv_process_exit_s { \
|
||||
UV_REQ_FIELDS \
|
||||
} exit_req; \
|
||||
BYTE* child_stdio_buffer; \
|
||||
int exit_signal; \
|
||||
HANDLE wait_handle; \
|
||||
HANDLE process_handle; \
|
||||
volatile char exit_cb_pending;
|
||||
|
||||
#define UV_FS_PRIVATE_FIELDS \
|
||||
struct uv__work work_req; \
|
||||
int flags; \
|
||||
DWORD sys_errno_; \
|
||||
union { \
|
||||
/* TODO: remove me in 0.9. */ \
|
||||
WCHAR* pathw; \
|
||||
int fd; \
|
||||
} file; \
|
||||
union { \
|
||||
struct { \
|
||||
int mode; \
|
||||
WCHAR* new_pathw; \
|
||||
int file_flags; \
|
||||
int fd_out; \
|
||||
unsigned int nbufs; \
|
||||
uv_buf_t* bufs; \
|
||||
int64_t offset; \
|
||||
uv_buf_t bufsml[4]; \
|
||||
} info; \
|
||||
struct { \
|
||||
double atime; \
|
||||
double mtime; \
|
||||
} time; \
|
||||
} fs;
|
||||
|
||||
#define UV_WORK_PRIVATE_FIELDS \
|
||||
struct uv__work work_req;
|
||||
|
||||
#define UV_FS_EVENT_PRIVATE_FIELDS \
|
||||
struct uv_fs_event_req_s { \
|
||||
UV_REQ_FIELDS \
|
||||
} req; \
|
||||
HANDLE dir_handle; \
|
||||
int req_pending; \
|
||||
uv_fs_event_cb cb; \
|
||||
WCHAR* filew; \
|
||||
WCHAR* short_filew; \
|
||||
WCHAR* dirw; \
|
||||
char* buffer;
|
||||
|
||||
#define UV_SIGNAL_PRIVATE_FIELDS \
|
||||
RB_ENTRY(uv_signal_s) tree_entry; \
|
||||
struct uv_req_s signal_req; \
|
||||
unsigned long pending_signum;
|
||||
|
||||
#ifndef F_OK
|
||||
#define F_OK 0
|
||||
#endif
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#endif
|
||||
#ifndef W_OK
|
||||
#define W_OK 2
|
||||
#endif
|
||||
#ifndef X_OK
|
||||
#define X_OK 1
|
||||
#endif
|
||||
1499
Utilities/cmlibuv/include/uv.h
Normal file
1499
Utilities/cmlibuv/include/uv.h
Normal file
File diff suppressed because it is too large
Load Diff
256
Utilities/cmlibuv/src/fs-poll.c
Normal file
256
Utilities/cmlibuv/src/fs-poll.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct poll_ctx {
|
||||
uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
|
||||
int busy_polling;
|
||||
unsigned int interval;
|
||||
uint64_t start_time;
|
||||
uv_loop_t* loop;
|
||||
uv_fs_poll_cb poll_cb;
|
||||
uv_timer_t timer_handle;
|
||||
uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
|
||||
uv_stat_t statbuf;
|
||||
char path[1]; /* variable length */
|
||||
};
|
||||
|
||||
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
|
||||
static void poll_cb(uv_fs_t* req);
|
||||
static void timer_cb(uv_timer_t* timer);
|
||||
static void timer_close_cb(uv_handle_t* handle);
|
||||
|
||||
static uv_stat_t zero_statbuf;
|
||||
|
||||
|
||||
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_poll_start(uv_fs_poll_t* handle,
|
||||
uv_fs_poll_cb cb,
|
||||
const char* path,
|
||||
unsigned int interval) {
|
||||
struct poll_ctx* ctx;
|
||||
uv_loop_t* loop;
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
loop = handle->loop;
|
||||
len = strlen(path);
|
||||
ctx = uv__calloc(1, sizeof(*ctx) + len);
|
||||
|
||||
if (ctx == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
ctx->loop = loop;
|
||||
ctx->poll_cb = cb;
|
||||
ctx->interval = interval ? interval : 1;
|
||||
ctx->start_time = uv_now(loop);
|
||||
ctx->parent_handle = handle;
|
||||
memcpy(ctx->path, path, len + 1);
|
||||
|
||||
err = uv_timer_init(loop, &ctx->timer_handle);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
|
||||
uv__handle_unref(&ctx->timer_handle);
|
||||
|
||||
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
handle->poll_ctx = ctx;
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv__free(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_poll_stop(uv_fs_poll_t* handle) {
|
||||
struct poll_ctx* ctx;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
ctx = handle->poll_ctx;
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->parent_handle != NULL);
|
||||
ctx->parent_handle = NULL;
|
||||
handle->poll_ctx = NULL;
|
||||
|
||||
/* Close the timer if it's active. If it's inactive, there's a stat request
|
||||
* in progress and poll_cb will take care of the cleanup.
|
||||
*/
|
||||
if (uv__is_active(&ctx->timer_handle))
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
|
||||
struct poll_ctx* ctx;
|
||||
size_t required_len;
|
||||
|
||||
if (!uv__is_active(handle)) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
ctx = handle->poll_ctx;
|
||||
assert(ctx != NULL);
|
||||
|
||||
required_len = strlen(ctx->path);
|
||||
if (required_len >= *size) {
|
||||
*size = required_len + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, ctx->path, required_len);
|
||||
*size = required_len;
|
||||
buffer[required_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_poll_close(uv_fs_poll_t* handle) {
|
||||
uv_fs_poll_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void timer_cb(uv_timer_t* timer) {
|
||||
struct poll_ctx* ctx;
|
||||
|
||||
ctx = container_of(timer, struct poll_ctx, timer_handle);
|
||||
assert(ctx->parent_handle != NULL);
|
||||
assert(ctx->parent_handle->poll_ctx == ctx);
|
||||
ctx->start_time = uv_now(ctx->loop);
|
||||
|
||||
if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void poll_cb(uv_fs_t* req) {
|
||||
uv_stat_t* statbuf;
|
||||
struct poll_ctx* ctx;
|
||||
uint64_t interval;
|
||||
|
||||
ctx = container_of(req, struct poll_ctx, fs_req);
|
||||
|
||||
if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
uv_fs_req_cleanup(req);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->result != 0) {
|
||||
if (ctx->busy_polling != req->result) {
|
||||
ctx->poll_cb(ctx->parent_handle,
|
||||
req->result,
|
||||
&ctx->statbuf,
|
||||
&zero_statbuf);
|
||||
ctx->busy_polling = req->result;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
statbuf = &req->statbuf;
|
||||
|
||||
if (ctx->busy_polling != 0)
|
||||
if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
|
||||
ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
|
||||
|
||||
ctx->statbuf = *statbuf;
|
||||
ctx->busy_polling = 1;
|
||||
|
||||
out:
|
||||
uv_fs_req_cleanup(req);
|
||||
|
||||
if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reschedule timer, subtract the delay from doing the stat(). */
|
||||
interval = ctx->interval;
|
||||
interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
|
||||
|
||||
if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void timer_close_cb(uv_handle_t* handle) {
|
||||
uv__free(container_of(handle, struct poll_ctx, timer_handle));
|
||||
}
|
||||
|
||||
|
||||
static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
|
||||
return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
|
||||
&& a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
|
||||
&& a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
|
||||
&& a->st_ctim.tv_sec == b->st_ctim.tv_sec
|
||||
&& a->st_mtim.tv_sec == b->st_mtim.tv_sec
|
||||
&& a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
|
||||
&& a->st_size == b->st_size
|
||||
&& a->st_mode == b->st_mode
|
||||
&& a->st_uid == b->st_uid
|
||||
&& a->st_gid == b->st_gid
|
||||
&& a->st_ino == b->st_ino
|
||||
&& a->st_dev == b->st_dev
|
||||
&& a->st_flags == b->st_flags
|
||||
&& a->st_gen == b->st_gen;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "win/internal.h"
|
||||
#include "win/handle-inl.h"
|
||||
|
||||
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
245
Utilities/cmlibuv/src/heap-inl.h
Normal file
245
Utilities/cmlibuv/src/heap-inl.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SRC_HEAP_H_
|
||||
#define UV_SRC_HEAP_H_
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
|
||||
#else
|
||||
# define HEAP_EXPORT(declaration) static declaration
|
||||
#endif
|
||||
|
||||
struct heap_node {
|
||||
struct heap_node* left;
|
||||
struct heap_node* right;
|
||||
struct heap_node* parent;
|
||||
};
|
||||
|
||||
/* A binary min heap. The usual properties hold: the root is the lowest
|
||||
* element in the set, the height of the tree is at most log2(nodes) and
|
||||
* it's always a complete binary tree.
|
||||
*
|
||||
* The heap function try hard to detect corrupted tree nodes at the cost
|
||||
* of a minor reduction in performance. Compile with -DNDEBUG to disable.
|
||||
*/
|
||||
struct heap {
|
||||
struct heap_node* min;
|
||||
unsigned int nelts;
|
||||
};
|
||||
|
||||
/* Return non-zero if a < b. */
|
||||
typedef int (*heap_compare_fn)(const struct heap_node* a,
|
||||
const struct heap_node* b);
|
||||
|
||||
/* Public functions. */
|
||||
HEAP_EXPORT(void heap_init(struct heap* heap));
|
||||
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
|
||||
HEAP_EXPORT(void heap_insert(struct heap* heap,
|
||||
struct heap_node* newnode,
|
||||
heap_compare_fn less_than));
|
||||
HEAP_EXPORT(void heap_remove(struct heap* heap,
|
||||
struct heap_node* node,
|
||||
heap_compare_fn less_than));
|
||||
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
|
||||
|
||||
/* Implementation follows. */
|
||||
|
||||
HEAP_EXPORT(void heap_init(struct heap* heap)) {
|
||||
heap->min = NULL;
|
||||
heap->nelts = 0;
|
||||
}
|
||||
|
||||
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
|
||||
return heap->min;
|
||||
}
|
||||
|
||||
/* Swap parent with child. Child moves closer to the root, parent moves away. */
|
||||
static void heap_node_swap(struct heap* heap,
|
||||
struct heap_node* parent,
|
||||
struct heap_node* child) {
|
||||
struct heap_node* sibling;
|
||||
struct heap_node t;
|
||||
|
||||
t = *parent;
|
||||
*parent = *child;
|
||||
*child = t;
|
||||
|
||||
parent->parent = child;
|
||||
if (child->left == child) {
|
||||
child->left = parent;
|
||||
sibling = child->right;
|
||||
} else {
|
||||
child->right = parent;
|
||||
sibling = child->left;
|
||||
}
|
||||
if (sibling != NULL)
|
||||
sibling->parent = child;
|
||||
|
||||
if (parent->left != NULL)
|
||||
parent->left->parent = parent;
|
||||
if (parent->right != NULL)
|
||||
parent->right->parent = parent;
|
||||
|
||||
if (child->parent == NULL)
|
||||
heap->min = child;
|
||||
else if (child->parent->left == parent)
|
||||
child->parent->left = child;
|
||||
else
|
||||
child->parent->right = child;
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_insert(struct heap* heap,
|
||||
struct heap_node* newnode,
|
||||
heap_compare_fn less_than)) {
|
||||
struct heap_node** parent;
|
||||
struct heap_node** child;
|
||||
unsigned int path;
|
||||
unsigned int n;
|
||||
unsigned int k;
|
||||
|
||||
newnode->left = NULL;
|
||||
newnode->right = NULL;
|
||||
newnode->parent = NULL;
|
||||
|
||||
/* Calculate the path from the root to the insertion point. This is a min
|
||||
* heap so we always insert at the left-most free node of the bottom row.
|
||||
*/
|
||||
path = 0;
|
||||
for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
|
||||
path = (path << 1) | (n & 1);
|
||||
|
||||
/* Now traverse the heap using the path we calculated in the previous step. */
|
||||
parent = child = &heap->min;
|
||||
while (k > 0) {
|
||||
parent = child;
|
||||
if (path & 1)
|
||||
child = &(*child)->right;
|
||||
else
|
||||
child = &(*child)->left;
|
||||
path >>= 1;
|
||||
k -= 1;
|
||||
}
|
||||
|
||||
/* Insert the new node. */
|
||||
newnode->parent = *parent;
|
||||
*child = newnode;
|
||||
heap->nelts += 1;
|
||||
|
||||
/* Walk up the tree and check at each node if the heap property holds.
|
||||
* It's a min heap so parent < child must be true.
|
||||
*/
|
||||
while (newnode->parent != NULL && less_than(newnode, newnode->parent))
|
||||
heap_node_swap(heap, newnode->parent, newnode);
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_remove(struct heap* heap,
|
||||
struct heap_node* node,
|
||||
heap_compare_fn less_than)) {
|
||||
struct heap_node* smallest;
|
||||
struct heap_node** max;
|
||||
struct heap_node* child;
|
||||
unsigned int path;
|
||||
unsigned int k;
|
||||
unsigned int n;
|
||||
|
||||
if (heap->nelts == 0)
|
||||
return;
|
||||
|
||||
/* Calculate the path from the min (the root) to the max, the left-most node
|
||||
* of the bottom row.
|
||||
*/
|
||||
path = 0;
|
||||
for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
|
||||
path = (path << 1) | (n & 1);
|
||||
|
||||
/* Now traverse the heap using the path we calculated in the previous step. */
|
||||
max = &heap->min;
|
||||
while (k > 0) {
|
||||
if (path & 1)
|
||||
max = &(*max)->right;
|
||||
else
|
||||
max = &(*max)->left;
|
||||
path >>= 1;
|
||||
k -= 1;
|
||||
}
|
||||
|
||||
heap->nelts -= 1;
|
||||
|
||||
/* Unlink the max node. */
|
||||
child = *max;
|
||||
*max = NULL;
|
||||
|
||||
if (child == node) {
|
||||
/* We're removing either the max or the last node in the tree. */
|
||||
if (child == heap->min) {
|
||||
heap->min = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace the to be deleted node with the max node. */
|
||||
child->left = node->left;
|
||||
child->right = node->right;
|
||||
child->parent = node->parent;
|
||||
|
||||
if (child->left != NULL) {
|
||||
child->left->parent = child;
|
||||
}
|
||||
|
||||
if (child->right != NULL) {
|
||||
child->right->parent = child;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
heap->min = child;
|
||||
} else if (node->parent->left == node) {
|
||||
node->parent->left = child;
|
||||
} else {
|
||||
node->parent->right = child;
|
||||
}
|
||||
|
||||
/* Walk down the subtree and check at each node if the heap property holds.
|
||||
* It's a min heap so parent < child must be true. If the parent is bigger,
|
||||
* swap it with the smallest child.
|
||||
*/
|
||||
for (;;) {
|
||||
smallest = child;
|
||||
if (child->left != NULL && less_than(child->left, smallest))
|
||||
smallest = child->left;
|
||||
if (child->right != NULL && less_than(child->right, smallest))
|
||||
smallest = child->right;
|
||||
if (smallest == child)
|
||||
break;
|
||||
heap_node_swap(heap, child, smallest);
|
||||
}
|
||||
|
||||
/* Walk up the subtree and check that each parent is less than the node
|
||||
* this is required, because `max` node is not guaranteed to be the
|
||||
* actual maximum in tree
|
||||
*/
|
||||
while (child->parent != NULL && less_than(child, child->parent))
|
||||
heap_node_swap(heap, child->parent, child);
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
|
||||
heap_remove(heap, heap->min, less_than);
|
||||
}
|
||||
|
||||
#undef HEAP_EXPORT
|
||||
|
||||
#endif /* UV_SRC_HEAP_H_ */
|
||||
309
Utilities/cmlibuv/src/inet.c
Normal file
309
Utilities/cmlibuv/src/inet.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
* Copyright (c) 1996-1999 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#define UV__INET_ADDRSTRLEN 16
|
||||
#define UV__INET6_ADDRSTRLEN 46
|
||||
|
||||
|
||||
static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
|
||||
static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
|
||||
static int inet_pton4(const char *src, unsigned char *dst);
|
||||
static int inet_pton6(const char *src, unsigned char *dst);
|
||||
|
||||
|
||||
int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_ntop4(src, dst, size));
|
||||
case AF_INET6:
|
||||
return (inet_ntop6(src, dst, size));
|
||||
default:
|
||||
return UV_EAFNOSUPPORT;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
|
||||
static const char fmt[] = "%u.%u.%u.%u";
|
||||
char tmp[UV__INET_ADDRSTRLEN];
|
||||
int l;
|
||||
|
||||
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
|
||||
if (l <= 0 || (size_t) l >= size) {
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strncpy(dst, tmp, size);
|
||||
dst[size - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
|
||||
/*
|
||||
* Note that int32_t and int16_t need only be "at least" large enough
|
||||
* to contain a value of the specified size. On some systems, like
|
||||
* Crays, there is no such thing as an integer variable with 16 bits.
|
||||
* Keep this in mind if you think this function should have been coded
|
||||
* to use pointer overlays. All the world's not a VAX.
|
||||
*/
|
||||
char tmp[UV__INET6_ADDRSTRLEN], *tp;
|
||||
struct { int base, len; } best, cur;
|
||||
unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Preprocess:
|
||||
* Copy the input (bytewise) array into a wordwise array.
|
||||
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
||||
*/
|
||||
memset(words, '\0', sizeof words);
|
||||
for (i = 0; i < (int) sizeof(struct in6_addr); i++)
|
||||
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
|
||||
best.base = -1;
|
||||
best.len = 0;
|
||||
cur.base = -1;
|
||||
cur.len = 0;
|
||||
for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
|
||||
if (words[i] == 0) {
|
||||
if (cur.base == -1)
|
||||
cur.base = i, cur.len = 1;
|
||||
else
|
||||
cur.len++;
|
||||
} else {
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
cur.base = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
}
|
||||
if (best.base != -1 && best.len < 2)
|
||||
best.base = -1;
|
||||
|
||||
/*
|
||||
* Format the result.
|
||||
*/
|
||||
tp = tmp;
|
||||
for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
|
||||
/* Are we inside the best run of 0x00's? */
|
||||
if (best.base != -1 && i >= best.base &&
|
||||
i < (best.base + best.len)) {
|
||||
if (i == best.base)
|
||||
*tp++ = ':';
|
||||
continue;
|
||||
}
|
||||
/* Are we following an initial run of 0x00s or any real hex? */
|
||||
if (i != 0)
|
||||
*tp++ = ':';
|
||||
/* Is this address an encapsulated IPv4? */
|
||||
if (i == 6 && best.base == 0 && (best.len == 6 ||
|
||||
(best.len == 7 && words[7] != 0x0001) ||
|
||||
(best.len == 5 && words[5] == 0xffff))) {
|
||||
int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
|
||||
if (err)
|
||||
return err;
|
||||
tp += strlen(tp);
|
||||
break;
|
||||
}
|
||||
tp += sprintf(tp, "%x", words[i]);
|
||||
}
|
||||
/* Was it a trailing run of 0x00's? */
|
||||
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((size_t)(tp - tmp) > size) {
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strcpy(dst, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_inet_pton(int af, const char* src, void* dst) {
|
||||
if (src == NULL || dst == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_pton4(src, dst));
|
||||
case AF_INET6: {
|
||||
int len;
|
||||
char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
|
||||
s = (char*) src;
|
||||
p = strchr(src, '%');
|
||||
if (p != NULL) {
|
||||
s = tmp;
|
||||
len = p - src;
|
||||
if (len > UV__INET6_ADDRSTRLEN-1)
|
||||
return UV_EINVAL;
|
||||
memcpy(s, src, len);
|
||||
s[len] = '\0';
|
||||
}
|
||||
return inet_pton6(s, dst);
|
||||
}
|
||||
default:
|
||||
return UV_EAFNOSUPPORT;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
static int inet_pton4(const char *src, unsigned char *dst) {
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, octets, ch;
|
||||
unsigned char tmp[sizeof(struct in_addr)], *tp;
|
||||
|
||||
saw_digit = 0;
|
||||
octets = 0;
|
||||
*(tp = tmp) = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr(digits, ch)) != NULL) {
|
||||
unsigned int nw = *tp * 10 + (pch - digits);
|
||||
|
||||
if (saw_digit && *tp == 0)
|
||||
return UV_EINVAL;
|
||||
if (nw > 255)
|
||||
return UV_EINVAL;
|
||||
*tp = nw;
|
||||
if (!saw_digit) {
|
||||
if (++octets > 4)
|
||||
return UV_EINVAL;
|
||||
saw_digit = 1;
|
||||
}
|
||||
} else if (ch == '.' && saw_digit) {
|
||||
if (octets == 4)
|
||||
return UV_EINVAL;
|
||||
*++tp = 0;
|
||||
saw_digit = 0;
|
||||
} else
|
||||
return UV_EINVAL;
|
||||
}
|
||||
if (octets < 4)
|
||||
return UV_EINVAL;
|
||||
memcpy(dst, tmp, sizeof(struct in_addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int inet_pton6(const char *src, unsigned char *dst) {
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
|
||||
const char *xdigits, *curtok;
|
||||
int ch, seen_xdigits;
|
||||
unsigned int val;
|
||||
|
||||
memset((tp = tmp), '\0', sizeof tmp);
|
||||
endp = tp + sizeof tmp;
|
||||
colonp = NULL;
|
||||
/* Leading :: requires some special handling. */
|
||||
if (*src == ':')
|
||||
if (*++src != ':')
|
||||
return UV_EINVAL;
|
||||
curtok = src;
|
||||
seen_xdigits = 0;
|
||||
val = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
|
||||
pch = strchr((xdigits = xdigits_u), ch);
|
||||
if (pch != NULL) {
|
||||
val <<= 4;
|
||||
val |= (pch - xdigits);
|
||||
if (++seen_xdigits > 4)
|
||||
return UV_EINVAL;
|
||||
continue;
|
||||
}
|
||||
if (ch == ':') {
|
||||
curtok = src;
|
||||
if (!seen_xdigits) {
|
||||
if (colonp)
|
||||
return UV_EINVAL;
|
||||
colonp = tp;
|
||||
continue;
|
||||
} else if (*src == '\0') {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
if (tp + sizeof(uint16_t) > endp)
|
||||
return UV_EINVAL;
|
||||
*tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||
*tp++ = (unsigned char) val & 0xff;
|
||||
seen_xdigits = 0;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
|
||||
int err = inet_pton4(curtok, tp);
|
||||
if (err == 0) {
|
||||
tp += sizeof(struct in_addr);
|
||||
seen_xdigits = 0;
|
||||
break; /*%< '\\0' was seen by inet_pton4(). */
|
||||
}
|
||||
}
|
||||
return UV_EINVAL;
|
||||
}
|
||||
if (seen_xdigits) {
|
||||
if (tp + sizeof(uint16_t) > endp)
|
||||
return UV_EINVAL;
|
||||
*tp++ = (unsigned char) (val >> 8) & 0xff;
|
||||
*tp++ = (unsigned char) val & 0xff;
|
||||
}
|
||||
if (colonp != NULL) {
|
||||
/*
|
||||
* Since some memmove()'s erroneously fail to handle
|
||||
* overlapping regions, we'll do the shift by hand.
|
||||
*/
|
||||
const int n = tp - colonp;
|
||||
int i;
|
||||
|
||||
if (tp == endp)
|
||||
return UV_EINVAL;
|
||||
for (i = 1; i <= n; i++) {
|
||||
endp[- i] = colonp[n - i];
|
||||
colonp[n - i] = 0;
|
||||
}
|
||||
tp = endp;
|
||||
}
|
||||
if (tp != endp)
|
||||
return UV_EINVAL;
|
||||
memcpy(dst, tmp, sizeof tmp);
|
||||
return 0;
|
||||
}
|
||||
108
Utilities/cmlibuv/src/queue.h
Normal file
108
Utilities/cmlibuv/src/queue.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H_
|
||||
#define QUEUE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void *QUEUE[2];
|
||||
|
||||
/* Private macros. */
|
||||
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
|
||||
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
|
||||
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
|
||||
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
|
||||
|
||||
/* Public macros. */
|
||||
#define QUEUE_DATA(ptr, type, field) \
|
||||
((type *) ((char *) (ptr) - offsetof(type, field)))
|
||||
|
||||
/* Important note: mutating the list while QUEUE_FOREACH is
|
||||
* iterating over its elements results in undefined behavior.
|
||||
*/
|
||||
#define QUEUE_FOREACH(q, h) \
|
||||
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_EMPTY(q) \
|
||||
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_HEAD(q) \
|
||||
(QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_INIT(q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (q); \
|
||||
QUEUE_PREV(q) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_ADD(h, n) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
|
||||
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(n); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_SPLIT(h, q, n) \
|
||||
do { \
|
||||
QUEUE_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(n) = (n); \
|
||||
QUEUE_NEXT(n) = (q); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(q); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
QUEUE_PREV(q) = (n); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_MOVE(h, n) \
|
||||
do { \
|
||||
if (QUEUE_EMPTY(h)) \
|
||||
QUEUE_INIT(n); \
|
||||
else { \
|
||||
QUEUE* q = QUEUE_HEAD(h); \
|
||||
QUEUE_SPLIT(h, q, n); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_INSERT_HEAD(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
|
||||
QUEUE_PREV(q) = (h); \
|
||||
QUEUE_NEXT_PREV(q) = (q); \
|
||||
QUEUE_NEXT(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_INSERT_TAIL(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (h); \
|
||||
QUEUE_PREV(q) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(q) = (q); \
|
||||
QUEUE_PREV(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_REMOVE(q) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
|
||||
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif /* QUEUE_H_ */
|
||||
303
Utilities/cmlibuv/src/threadpool.c
Normal file
303
Utilities/cmlibuv/src/threadpool.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv-common.h"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# include "unix/internal.h"
|
||||
#else
|
||||
# include "win/req-inl.h"
|
||||
/* TODO(saghul): unify internal req functions */
|
||||
static void uv__req_init(uv_loop_t* loop,
|
||||
uv_req_t* req,
|
||||
uv_req_type type) {
|
||||
uv_req_init(loop, req);
|
||||
req->type = type;
|
||||
uv__req_register(loop, req);
|
||||
}
|
||||
# define uv__req_init(loop, req, type) \
|
||||
uv__req_init((loop), (uv_req_t*)(req), (type))
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_THREADPOOL_SIZE 128
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uv_cond_t cond;
|
||||
static uv_mutex_t mutex;
|
||||
static unsigned int idle_threads;
|
||||
static unsigned int nthreads;
|
||||
static uv_thread_t* threads;
|
||||
static uv_thread_t default_threads[4];
|
||||
static QUEUE exit_message;
|
||||
static QUEUE wq;
|
||||
static volatile int initialized;
|
||||
|
||||
|
||||
static void uv__cancelled(struct uv__work* w) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
/* To avoid deadlock with uv_cancel() it's crucial that the worker
|
||||
* never holds the global mutex and the loop-local mutex at the same time.
|
||||
*/
|
||||
static void worker(void* arg) {
|
||||
struct uv__work* w;
|
||||
QUEUE* q;
|
||||
|
||||
(void) arg;
|
||||
|
||||
for (;;) {
|
||||
uv_mutex_lock(&mutex);
|
||||
|
||||
while (QUEUE_EMPTY(&wq)) {
|
||||
idle_threads += 1;
|
||||
uv_cond_wait(&cond, &mutex);
|
||||
idle_threads -= 1;
|
||||
}
|
||||
|
||||
q = QUEUE_HEAD(&wq);
|
||||
|
||||
if (q == &exit_message)
|
||||
uv_cond_signal(&cond);
|
||||
else {
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
|
||||
executing. */
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (q == &exit_message)
|
||||
break;
|
||||
|
||||
w = QUEUE_DATA(q, struct uv__work, wq);
|
||||
w->work(w);
|
||||
|
||||
uv_mutex_lock(&w->loop->wq_mutex);
|
||||
w->work = NULL; /* Signal uv_cancel() that the work req is done
|
||||
executing. */
|
||||
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
|
||||
uv_async_send(&w->loop->wq_async);
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void post(QUEUE* q) {
|
||||
uv_mutex_lock(&mutex);
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
uv_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
UV_DESTRUCTOR(static void cleanup(void)) {
|
||||
unsigned int i;
|
||||
|
||||
if (initialized == 0)
|
||||
return;
|
||||
|
||||
post(&exit_message);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
if (uv_thread_join(threads + i))
|
||||
abort();
|
||||
|
||||
if (threads != default_threads)
|
||||
uv__free(threads);
|
||||
|
||||
uv_mutex_destroy(&mutex);
|
||||
uv_cond_destroy(&cond);
|
||||
|
||||
threads = NULL;
|
||||
nthreads = 0;
|
||||
initialized = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void init_once(void) {
|
||||
unsigned int i;
|
||||
const char* val;
|
||||
|
||||
nthreads = ARRAY_SIZE(default_threads);
|
||||
val = getenv("UV_THREADPOOL_SIZE");
|
||||
if (val != NULL)
|
||||
nthreads = atoi(val);
|
||||
if (nthreads == 0)
|
||||
nthreads = 1;
|
||||
if (nthreads > MAX_THREADPOOL_SIZE)
|
||||
nthreads = MAX_THREADPOOL_SIZE;
|
||||
|
||||
threads = default_threads;
|
||||
if (nthreads > ARRAY_SIZE(default_threads)) {
|
||||
threads = uv__malloc(nthreads * sizeof(threads[0]));
|
||||
if (threads == NULL) {
|
||||
nthreads = ARRAY_SIZE(default_threads);
|
||||
threads = default_threads;
|
||||
}
|
||||
}
|
||||
|
||||
if (uv_cond_init(&cond))
|
||||
abort();
|
||||
|
||||
if (uv_mutex_init(&mutex))
|
||||
abort();
|
||||
|
||||
QUEUE_INIT(&wq);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
if (uv_thread_create(threads + i, worker, NULL))
|
||||
abort();
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work* w,
|
||||
void (*work)(struct uv__work* w),
|
||||
void (*done)(struct uv__work* w, int status)) {
|
||||
uv_once(&once, init_once);
|
||||
w->loop = loop;
|
||||
w->work = work;
|
||||
w->done = done;
|
||||
post(&w->wq);
|
||||
}
|
||||
|
||||
|
||||
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
||||
int cancelled;
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
uv_mutex_lock(&w->loop->wq_mutex);
|
||||
|
||||
cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
|
||||
if (cancelled)
|
||||
QUEUE_REMOVE(&w->wq);
|
||||
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (!cancelled)
|
||||
return UV_EBUSY;
|
||||
|
||||
w->work = uv__cancelled;
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
|
||||
uv_async_send(&loop->wq_async);
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__work_done(uv_async_t* handle) {
|
||||
struct uv__work* w;
|
||||
uv_loop_t* loop;
|
||||
QUEUE* q;
|
||||
QUEUE wq;
|
||||
int err;
|
||||
|
||||
loop = container_of(handle, uv_loop_t, wq_async);
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
QUEUE_MOVE(&loop->wq, &wq);
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
|
||||
while (!QUEUE_EMPTY(&wq)) {
|
||||
q = QUEUE_HEAD(&wq);
|
||||
QUEUE_REMOVE(q);
|
||||
|
||||
w = container_of(q, struct uv__work, wq);
|
||||
err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
|
||||
w->done(w, err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__queue_work(struct uv__work* w) {
|
||||
uv_work_t* req = container_of(w, uv_work_t, work_req);
|
||||
|
||||
req->work_cb(req);
|
||||
}
|
||||
|
||||
|
||||
static void uv__queue_done(struct uv__work* w, int err) {
|
||||
uv_work_t* req;
|
||||
|
||||
req = container_of(w, uv_work_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
|
||||
if (req->after_work_cb == NULL)
|
||||
return;
|
||||
|
||||
req->after_work_cb(req, err);
|
||||
}
|
||||
|
||||
|
||||
int uv_queue_work(uv_loop_t* loop,
|
||||
uv_work_t* req,
|
||||
uv_work_cb work_cb,
|
||||
uv_after_work_cb after_work_cb) {
|
||||
if (work_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__req_init(loop, req, UV_WORK);
|
||||
req->loop = loop;
|
||||
req->work_cb = work_cb;
|
||||
req->after_work_cb = after_work_cb;
|
||||
uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cancel(uv_req_t* req) {
|
||||
struct uv__work* wreq;
|
||||
uv_loop_t* loop;
|
||||
|
||||
switch (req->type) {
|
||||
case UV_FS:
|
||||
loop = ((uv_fs_t*) req)->loop;
|
||||
wreq = &((uv_fs_t*) req)->work_req;
|
||||
break;
|
||||
case UV_GETADDRINFO:
|
||||
loop = ((uv_getaddrinfo_t*) req)->loop;
|
||||
wreq = &((uv_getaddrinfo_t*) req)->work_req;
|
||||
break;
|
||||
case UV_GETNAMEINFO:
|
||||
loop = ((uv_getnameinfo_t*) req)->loop;
|
||||
wreq = &((uv_getnameinfo_t*) req)->work_req;
|
||||
break;
|
||||
case UV_WORK:
|
||||
loop = ((uv_work_t*) req)->loop;
|
||||
wreq = &((uv_work_t*) req)->work_req;
|
||||
break;
|
||||
default:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
return uv__work_cancel(loop, req, wreq);
|
||||
}
|
||||
1154
Utilities/cmlibuv/src/unix/aix.c
Normal file
1154
Utilities/cmlibuv/src/unix/aix.c
Normal file
File diff suppressed because it is too large
Load Diff
703
Utilities/cmlibuv/src/unix/android-ifaddrs.c
Normal file
703
Utilities/cmlibuv/src/unix/android-ifaddrs.c
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
Copyright (c) 2013, Kenneth MacKay
|
||||
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "android-ifaddrs.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
struct NetlinkList *m_next;
|
||||
struct nlmsghdr *m_data;
|
||||
unsigned int m_size;
|
||||
} NetlinkList;
|
||||
|
||||
static int netlink_socket(void)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return l_socket;
|
||||
}
|
||||
|
||||
static int netlink_send(int p_socket, int p_request)
|
||||
{
|
||||
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
|
||||
|
||||
struct nlmsghdr *l_hdr;
|
||||
struct rtgenmsg *l_msg;
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
memset(l_buffer, 0, sizeof(l_buffer));
|
||||
|
||||
l_hdr = (struct nlmsghdr *)l_buffer;
|
||||
l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
|
||||
|
||||
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
|
||||
l_hdr->nlmsg_type = p_request;
|
||||
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
l_hdr->nlmsg_pid = 0;
|
||||
l_hdr->nlmsg_seq = p_socket;
|
||||
l_msg->rtgen_family = AF_UNSPEC;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
|
||||
}
|
||||
|
||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
struct msghdr l_msg;
|
||||
|
||||
struct iovec l_iov;
|
||||
l_iov.iov_base = p_buffer;
|
||||
l_iov.iov_len = p_len;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int l_result;
|
||||
l_msg.msg_name = (void *)&l_addr;
|
||||
l_msg.msg_namelen = sizeof(l_addr);
|
||||
l_msg.msg_iov = &l_iov;
|
||||
l_msg.msg_iovlen = 1;
|
||||
l_msg.msg_control = NULL;
|
||||
l_msg.msg_controllen = 0;
|
||||
l_msg.msg_flags = 0;
|
||||
l_result = recvmsg(p_socket, &l_msg, 0);
|
||||
|
||||
if(l_result < 0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Buffer was too small */
|
||||
if(l_msg.msg_flags & MSG_TRUNC)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
|
||||
{
|
||||
size_t l_size = 4096;
|
||||
void *l_buffer = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int l_read;
|
||||
|
||||
uv__free(l_buffer);
|
||||
l_buffer = uv__malloc(l_size);
|
||||
if (l_buffer == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_read = netlink_recv(p_socket, l_buffer, l_size);
|
||||
*p_size = l_read;
|
||||
if(l_read == -2)
|
||||
{
|
||||
uv__free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
if(l_read >= 0)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
*p_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
uv__free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return l_buffer;
|
||||
}
|
||||
|
||||
l_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
|
||||
{
|
||||
NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
|
||||
if (l_item == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_item->m_next = NULL;
|
||||
l_item->m_data = p_data;
|
||||
l_item->m_size = p_size;
|
||||
return l_item;
|
||||
}
|
||||
|
||||
static void freeResultList(NetlinkList *p_list)
|
||||
{
|
||||
NetlinkList *l_cur;
|
||||
while(p_list)
|
||||
{
|
||||
l_cur = p_list;
|
||||
p_list = p_list->m_next;
|
||||
uv__free(l_cur->m_data);
|
||||
uv__free(l_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *getResultList(int p_socket, int p_request)
|
||||
{
|
||||
int l_size;
|
||||
int l_done;
|
||||
NetlinkList *l_list;
|
||||
NetlinkList *l_end;
|
||||
|
||||
if(netlink_send(p_socket, p_request) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_list = NULL;
|
||||
l_end = NULL;
|
||||
|
||||
l_done = 0;
|
||||
while(!l_done)
|
||||
{
|
||||
NetlinkList *l_item;
|
||||
|
||||
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
|
||||
/* Error */
|
||||
if(!l_hdr)
|
||||
{
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l_item = newListItem(l_hdr, l_size);
|
||||
if (!l_item)
|
||||
{
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
if(!l_list)
|
||||
{
|
||||
l_list = l_item;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_end->m_next = l_item;
|
||||
}
|
||||
l_end = l_item;
|
||||
}
|
||||
return l_list;
|
||||
}
|
||||
|
||||
static size_t maxSize(size_t a, size_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_PACKET:
|
||||
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
|
||||
default:
|
||||
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_PACKET:
|
||||
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
|
||||
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
|
||||
break;
|
||||
default:
|
||||
memcpy(p_dest->sa_data, p_data, p_size);
|
||||
break;
|
||||
}
|
||||
p_dest->sa_family = p_family;
|
||||
}
|
||||
|
||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
|
||||
{
|
||||
if(!*p_resultList)
|
||||
{
|
||||
*p_resultList = p_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ifaddrs *l_cur = *p_resultList;
|
||||
while(l_cur->ifa_next)
|
||||
{
|
||||
l_cur = l_cur->ifa_next;
|
||||
}
|
||||
l_cur->ifa_next = p_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifaddrs *l_entry;
|
||||
|
||||
char *l_index;
|
||||
char *l_name;
|
||||
char *l_addr;
|
||||
char *l_data;
|
||||
|
||||
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
size_t l_dataSize = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
struct rtattr *l_rta;
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
l_dataSize += NLMSG_ALIGN(l_rtaSize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
|
||||
if (l_entry == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = "";
|
||||
|
||||
l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
l_name = l_index + sizeof(int);
|
||||
l_addr = l_name + l_nameSize;
|
||||
l_data = l_addr + l_addrSize;
|
||||
|
||||
/* Save the interface index so we can look it up when handling the
|
||||
* addresses.
|
||||
*/
|
||||
memcpy(l_index, &l_info->ifi_index, sizeof(int));
|
||||
|
||||
l_entry->ifa_flags = l_info->ifi_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
|
||||
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
|
||||
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
|
||||
if(l_rta->rta_type == IFLA_ADDRESS)
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFLA_IFNAME:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
memcpy(l_data, l_rtaData, l_rtaDataSize);
|
||||
l_entry->ifa_data = l_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
|
||||
{
|
||||
int l_num = 0;
|
||||
struct ifaddrs *l_cur = *p_links;
|
||||
while(l_cur && l_num < p_numLinks)
|
||||
{
|
||||
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
|
||||
int l_index;
|
||||
memcpy(&l_index, l_indexPtr, sizeof(int));
|
||||
if(l_index == p_index)
|
||||
{
|
||||
return l_cur;
|
||||
}
|
||||
|
||||
l_cur = l_cur->ifa_next;
|
||||
++l_num;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
|
||||
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
|
||||
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
|
||||
int l_addedNetmask = 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
struct rtattr *l_rta;
|
||||
struct ifaddrs *l_entry;
|
||||
|
||||
char *l_name;
|
||||
char *l_addr;
|
||||
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
if(l_info->ifa_family == AF_PACKET)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{
|
||||
/* Make room for netmask */
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
|
||||
if (l_entry == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
|
||||
|
||||
l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
l_addr = l_name + l_nameSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifa_flags;
|
||||
if(l_interface)
|
||||
{
|
||||
l_entry->ifa_flags |= l_interface->ifa_flags;
|
||||
}
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_BROADCAST:
|
||||
case IFA_LOCAL:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
|
||||
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
if(l_info->ifa_family == AF_INET6)
|
||||
{
|
||||
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
|
||||
{
|
||||
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apparently in a point-to-point network IFA_ADDRESS contains
|
||||
* the dest address and IFA_LOCAL contains the local address
|
||||
*/
|
||||
if(l_rta->rta_type == IFA_ADDRESS)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
}
|
||||
else if(l_rta->rta_type == IFA_LOCAL)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
{
|
||||
l_entry->ifa_dstaddr = l_entry->ifa_addr;
|
||||
}
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFA_LABEL:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
|
||||
{
|
||||
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
|
||||
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
|
||||
char l_mask[16] = {0};
|
||||
unsigned i;
|
||||
for(i=0; i<(l_prefix/8); ++i)
|
||||
{
|
||||
l_mask[i] = 0xff;
|
||||
}
|
||||
if(l_prefix % 8)
|
||||
{
|
||||
l_mask[i] = 0xff << (8 - (l_prefix % 8));
|
||||
}
|
||||
|
||||
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
|
||||
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
|
||||
{
|
||||
|
||||
int l_numLinks = 0;
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
if(interpretLink(l_hdr, p_resultList) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
++l_numLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_numLinks;
|
||||
}
|
||||
|
||||
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int l_socket;
|
||||
int l_result;
|
||||
int l_numLinks;
|
||||
NetlinkList *l_linkResults;
|
||||
NetlinkList *l_addrResults;
|
||||
|
||||
if(!ifap)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
*ifap = NULL;
|
||||
|
||||
l_socket = netlink_socket();
|
||||
if(l_socket < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_linkResults = getResultList(l_socket, RTM_GETLINK);
|
||||
if(!l_linkResults)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_addrResults = getResultList(l_socket, RTM_GETADDR);
|
||||
if(!l_addrResults)
|
||||
{
|
||||
close(l_socket);
|
||||
freeResultList(l_linkResults);
|
||||
return -1;
|
||||
}
|
||||
|
||||
l_result = 0;
|
||||
l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
|
||||
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
|
||||
{
|
||||
l_result = -1;
|
||||
}
|
||||
|
||||
freeResultList(l_linkResults);
|
||||
freeResultList(l_addrResults);
|
||||
close(l_socket);
|
||||
return l_result;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
struct ifaddrs *l_cur;
|
||||
while(ifa)
|
||||
{
|
||||
l_cur = ifa;
|
||||
ifa = ifa->ifa_next;
|
||||
uv__free(l_cur);
|
||||
}
|
||||
}
|
||||
290
Utilities/cmlibuv/src/unix/async.c
Normal file
290
Utilities/cmlibuv/src/unix/async.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* This file contains both the uv__async internal infrastructure and the
|
||||
* user-facing uv_async_t functions.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "atomic-ops.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* snprintf() */
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void uv__async_event(uv_loop_t* loop,
|
||||
struct uv__async* w,
|
||||
unsigned int nevents);
|
||||
static int uv__async_eventfd(void);
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
int err;
|
||||
|
||||
err = uv__async_start(loop, &loop->async_watcher, uv__async_event);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
|
||||
handle->async_cb = async_cb;
|
||||
handle->pending = 0;
|
||||
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_async_send(uv_async_t* handle) {
|
||||
/* Do a cheap read first. */
|
||||
if (ACCESS_ONCE(int, handle->pending) != 0)
|
||||
return 0;
|
||||
|
||||
if (cmpxchgi(&handle->pending, 0, 1) == 0)
|
||||
uv__async_send(&handle->loop->async_watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__async_close(uv_async_t* handle) {
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
static void uv__async_event(uv_loop_t* loop,
|
||||
struct uv__async* w,
|
||||
unsigned int nevents) {
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
uv_async_t* h;
|
||||
|
||||
QUEUE_MOVE(&loop->async_handles, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_async_t, queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
|
||||
if (cmpxchgi(&h->pending, 1, 0) == 0)
|
||||
continue;
|
||||
|
||||
if (h->async_cb == NULL)
|
||||
continue;
|
||||
h->async_cb(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
struct uv__async* wa;
|
||||
char buf[1024];
|
||||
unsigned n;
|
||||
ssize_t r;
|
||||
|
||||
n = 0;
|
||||
for (;;) {
|
||||
r = read(w->fd, buf, sizeof(buf));
|
||||
|
||||
if (r > 0)
|
||||
n += r;
|
||||
|
||||
if (r == sizeof(buf))
|
||||
continue;
|
||||
|
||||
if (r != -1)
|
||||
break;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
wa = container_of(w, struct uv__async, io_watcher);
|
||||
|
||||
#if defined(__linux__)
|
||||
if (wa->wfd == -1) {
|
||||
uint64_t val;
|
||||
assert(n == sizeof(val));
|
||||
memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */
|
||||
wa->cb(loop, wa, val);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
wa->cb(loop, wa, n);
|
||||
}
|
||||
|
||||
|
||||
void uv__async_send(struct uv__async* wa) {
|
||||
const void* buf;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
int r;
|
||||
|
||||
buf = "";
|
||||
len = 1;
|
||||
fd = wa->wfd;
|
||||
|
||||
#if defined(__linux__)
|
||||
if (fd == -1) {
|
||||
static const uint64_t val = 1;
|
||||
buf = &val;
|
||||
len = sizeof(val);
|
||||
fd = wa->io_watcher.fd; /* eventfd */
|
||||
}
|
||||
#endif
|
||||
|
||||
do
|
||||
r = write(fd, buf, len);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == len)
|
||||
return;
|
||||
|
||||
if (r == -1)
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return;
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv__async_init(struct uv__async* wa) {
|
||||
wa->io_watcher.fd = -1;
|
||||
wa->wfd = -1;
|
||||
}
|
||||
|
||||
|
||||
int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
|
||||
int pipefd[2];
|
||||
int err;
|
||||
|
||||
if (wa->io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__async_eventfd();
|
||||
if (err >= 0) {
|
||||
pipefd[0] = err;
|
||||
pipefd[1] = -1;
|
||||
}
|
||||
else if (err == -ENOSYS) {
|
||||
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
|
||||
#if defined(__linux__)
|
||||
/* Save a file descriptor by opening one of the pipe descriptors as
|
||||
* read/write through the procfs. That file descriptor can then
|
||||
* function as both ends of the pipe.
|
||||
*/
|
||||
if (err == 0) {
|
||||
char buf[32];
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
|
||||
fd = uv__open_cloexec(buf, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
uv__close(pipefd[0]);
|
||||
uv__close(pipefd[1]);
|
||||
pipefd[0] = fd;
|
||||
pipefd[1] = fd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
|
||||
uv__io_start(loop, &wa->io_watcher, POLLIN);
|
||||
wa->wfd = pipefd[1];
|
||||
wa->cb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
|
||||
if (wa->io_watcher.fd == -1)
|
||||
return;
|
||||
|
||||
if (wa->wfd != -1) {
|
||||
if (wa->wfd != wa->io_watcher.fd)
|
||||
uv__close(wa->wfd);
|
||||
wa->wfd = -1;
|
||||
}
|
||||
|
||||
uv__io_stop(loop, &wa->io_watcher, POLLIN);
|
||||
uv__close(wa->io_watcher.fd);
|
||||
wa->io_watcher.fd = -1;
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_eventfd() {
|
||||
#if defined(__linux__)
|
||||
static int no_eventfd2;
|
||||
static int no_eventfd;
|
||||
int fd;
|
||||
|
||||
if (no_eventfd2)
|
||||
goto skip_eventfd2;
|
||||
|
||||
fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
no_eventfd2 = 1;
|
||||
|
||||
skip_eventfd2:
|
||||
|
||||
if (no_eventfd)
|
||||
goto skip_eventfd;
|
||||
|
||||
fd = uv__eventfd(0);
|
||||
if (fd != -1) {
|
||||
uv__cloexec(fd, 1);
|
||||
uv__nonblock(fd, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
no_eventfd = 1;
|
||||
|
||||
skip_eventfd:
|
||||
|
||||
#endif
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
88
Utilities/cmlibuv/src/unix/atomic-ops.h
Normal file
88
Utilities/cmlibuv/src/unix/atomic-ops.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_ATOMIC_OPS_H_
|
||||
#define UV_ATOMIC_OPS_H_
|
||||
|
||||
#include "internal.h" /* UV_UNUSED */
|
||||
|
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
#include <atomic.h>
|
||||
#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
|
||||
#endif
|
||||
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
|
||||
UV_UNUSED(static void cpu_relax(void));
|
||||
|
||||
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
|
||||
* issue full memory barriers.
|
||||
*/
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
int out;
|
||||
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
||||
: "=a" (out), "+m" (*(volatile int*) ptr)
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && defined(__xlC__)
|
||||
const int out = (*(volatile int*) ptr);
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
return out;
|
||||
#elif defined(__MVS__)
|
||||
return __plo_CS(ptr, (unsigned int*) ptr,
|
||||
oldval, (unsigned int*) &newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
long out;
|
||||
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
||||
: "=a" (out), "+m" (*(volatile long*) ptr)
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && defined(__xlC__)
|
||||
const long out = (*(volatile int*) ptr);
|
||||
# if defined(__64BIT__)
|
||||
__compare_and_swaplp(ptr, &oldval, newval);
|
||||
# else
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
# endif /* if defined(__64BIT__) */
|
||||
return out;
|
||||
#elif defined (__MVS__)
|
||||
# ifdef _LP64
|
||||
return __plo_CSGR(ptr, (unsigned long long*) ptr,
|
||||
oldval, (unsigned long long*) &newval);
|
||||
# else
|
||||
return __plo_CS(ptr, (unsigned int*) ptr,
|
||||
oldval, (unsigned int*) &newval);
|
||||
# endif
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
UV_UNUSED(static void cpu_relax(void)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* UV_ATOMIC_OPS_H_ */
|
||||
1238
Utilities/cmlibuv/src/unix/core.c
Normal file
1238
Utilities/cmlibuv/src/unix/core.c
Normal file
File diff suppressed because it is too large
Load Diff
206
Utilities/cmlibuv/src/unix/darwin-proctitle.c
Normal file
206
Utilities/cmlibuv/src/unix/darwin-proctitle.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
int (*dynamic_pthread_setname_np)(const char* name);
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int err;
|
||||
|
||||
/* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
|
||||
*(void **)(&dynamic_pthread_setname_np) =
|
||||
dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||
|
||||
if (dynamic_pthread_setname_np == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = dynamic_pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__set_process_title(const char* title) {
|
||||
#if TARGET_OS_IPHONE
|
||||
return uv__pthread_setname_np(title);
|
||||
#else
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
void* application_services_handle;
|
||||
void* core_foundation_handle;
|
||||
CFBundleRef launch_services_bundle;
|
||||
CFStringRef* display_name_key;
|
||||
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
CFBundleRef hi_services_bundle;
|
||||
OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
CFTypeRef asn;
|
||||
int err;
|
||||
|
||||
err = -ENOENT;
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
core_foundation_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreFoundation.framework/"
|
||||
"Versions/A/CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
|
||||
if (application_services_handle == NULL || core_foundation_handle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pCFStringCreateWithCString) =
|
||||
dlsym(core_foundation_handle, "CFStringCreateWithCString");
|
||||
*(void **)(&pCFBundleGetBundleWithIdentifier) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
|
||||
*(void **)(&pCFBundleGetDataPointerForName) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
|
||||
*(void **)(&pCFBundleGetFunctionPointerForName) =
|
||||
dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
|
||||
|
||||
if (pCFStringCreateWithCString == NULL ||
|
||||
pCFBundleGetBundleWithIdentifier == NULL ||
|
||||
pCFBundleGetDataPointerForName == NULL ||
|
||||
pCFBundleGetFunctionPointerForName == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
if (launch_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSGetCurrentApplicationASN) =
|
||||
pCFBundleGetFunctionPointerForName(launch_services_bundle,
|
||||
S("_LSGetCurrentApplicationASN"));
|
||||
|
||||
if (pLSGetCurrentApplicationASN == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSSetApplicationInformationItem) =
|
||||
pCFBundleGetFunctionPointerForName(launch_services_bundle,
|
||||
S("_LSSetApplicationInformationItem"));
|
||||
|
||||
if (pLSSetApplicationInformationItem == NULL)
|
||||
goto out;
|
||||
|
||||
display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
|
||||
S("_kLSDisplayNameKey"));
|
||||
|
||||
if (display_name_key == NULL || *display_name_key == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetInfoDictionary");
|
||||
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetMainBundle");
|
||||
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
|
||||
goto out;
|
||||
|
||||
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
|
||||
hi_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
|
||||
err = -ENOENT;
|
||||
if (hi_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
|
||||
hi_services_bundle,
|
||||
S("SetApplicationIsDaemon"));
|
||||
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSApplicationCheckIn"));
|
||||
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
if (pSetApplicationIsDaemon == NULL ||
|
||||
pLSApplicationCheckIn == NULL ||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pSetApplicationIsDaemon(1) != noErr)
|
||||
goto out;
|
||||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
|
||||
/* Check into process manager?! */
|
||||
pLSApplicationCheckIn(-2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
|
||||
err = -EINVAL;
|
||||
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
|
||||
asn,
|
||||
*display_name_key,
|
||||
S(title),
|
||||
NULL) != noErr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
}
|
||||
335
Utilities/cmlibuv/src/unix/darwin.c
Normal file
335
Utilities/cmlibuv/src/unix/darwin.c
Normal file
@@ -0,0 +1,335 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
loop->cf_state = NULL;
|
||||
|
||||
if (uv__kqueue_init(loop))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
uv__fsevents_loop_delete(loop);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
static mach_timebase_info_data_t info;
|
||||
|
||||
if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
|
||||
ACCESS_ONCE(uint32_t, info.denom) == 0) &&
|
||||
mach_timebase_info(&info) != KERN_SUCCESS)
|
||||
abort();
|
||||
|
||||
return mach_absolute_time() * info.numer / info.denom;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
char exepath[PATH_MAX + 1];
|
||||
uint32_t exepath_size;
|
||||
size_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
exepath_size = sizeof(exepath);
|
||||
if (_NSGetExecutablePath(exepath, &exepath_size))
|
||||
return -EIO;
|
||||
|
||||
if (realpath(exepath, abspath) != abspath)
|
||||
return -errno;
|
||||
|
||||
abspath_size = strlen(abspath);
|
||||
if (abspath_size == 0)
|
||||
return -EIO;
|
||||
|
||||
*size -= 1;
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
vm_statistics_data_t info;
|
||||
mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
|
||||
|
||||
if (host_statistics(mach_host_self(), HOST_VM_INFO,
|
||||
(host_info_t)&info, &count) != KERN_SUCCESS) {
|
||||
return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
|
||||
}
|
||||
|
||||
return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_MEMSIZE};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
mach_msg_type_number_t count;
|
||||
task_basic_info_data_t info;
|
||||
kern_return_t err;
|
||||
|
||||
count = TASK_BASIC_INFO_COUNT;
|
||||
err = task_info(mach_task_self(),
|
||||
TASK_BASIC_INFO,
|
||||
(task_info_t) &info,
|
||||
&count);
|
||||
(void) &err;
|
||||
/* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
|
||||
* KERN_SUCCESS implies a libuv bug.
|
||||
*/
|
||||
assert(err == KERN_SUCCESS);
|
||||
*rss = info.resident_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
now = time(NULL);
|
||||
*uptime = now - info.tv_sec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks);
|
||||
char model[512];
|
||||
uint64_t cpuspeed;
|
||||
size_t size;
|
||||
unsigned int i;
|
||||
natural_t numcpus;
|
||||
mach_msg_type_number_t msg_type;
|
||||
processor_cpu_load_info_data_t *info;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
|
||||
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
|
||||
(processor_info_array_t*)&info,
|
||||
&msg_type) != KERN_SUCCESS) {
|
||||
return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
|
||||
}
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*count = numcpus;
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
|
||||
cpu_info->cpu_times.irq = 0;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed/1000000;
|
||||
}
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs *addrs, *ent;
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
struct sockaddr_dl *sa_addr;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family == AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* On Mac OS X getifaddrs returns information related to Mac Addresses for
|
||||
* various devices, such as firewire, etc. These are not relevant here.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
80
Utilities/cmlibuv/src/unix/dl.c
Normal file
80
Utilities/cmlibuv/src/unix/dl.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib);
|
||||
|
||||
|
||||
int uv_dlopen(const char* filename, uv_lib_t* lib) {
|
||||
dlerror(); /* Reset error status. */
|
||||
lib->errmsg = NULL;
|
||||
lib->handle = dlopen(filename, RTLD_LAZY);
|
||||
return lib->handle ? 0 : uv__dlerror(lib);
|
||||
}
|
||||
|
||||
|
||||
void uv_dlclose(uv_lib_t* lib) {
|
||||
uv__free(lib->errmsg);
|
||||
lib->errmsg = NULL;
|
||||
|
||||
if (lib->handle) {
|
||||
/* Ignore errors. No good way to signal them without leaking memory. */
|
||||
dlclose(lib->handle);
|
||||
lib->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
|
||||
dlerror(); /* Reset error status. */
|
||||
*ptr = dlsym(lib->handle, name);
|
||||
return uv__dlerror(lib);
|
||||
}
|
||||
|
||||
|
||||
const char* uv_dlerror(const uv_lib_t* lib) {
|
||||
return lib->errmsg ? lib->errmsg : "no error";
|
||||
}
|
||||
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib) {
|
||||
const char* errmsg;
|
||||
|
||||
uv__free(lib->errmsg);
|
||||
|
||||
errmsg = dlerror();
|
||||
|
||||
if (errmsg) {
|
||||
lib->errmsg = uv__strdup(errmsg);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
lib->errmsg = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
460
Utilities/cmlibuv/src/unix/freebsd.c
Normal file
460
Utilities/cmlibuv/src/unix/freebsd.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <kvm.h>
|
||||
#include <paths.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm_param.h> /* VM_LOADAVG */
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
#include <fcntl.h>
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
#ifndef CPUSTATES
|
||||
# define CPUSTATES 5U
|
||||
#endif
|
||||
#ifndef CP_USER
|
||||
# define CP_USER 0
|
||||
# define CP_NICE 1
|
||||
# define CP_SYS 2
|
||||
# define CP_IDLE 3
|
||||
# define CP_INTR 4
|
||||
#endif
|
||||
|
||||
static char *process_title;
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __DragonFly__
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
ssize_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
|
||||
if (abspath_size < 0)
|
||||
return -errno;
|
||||
|
||||
assert(abspath_size > 0);
|
||||
*size -= 1;
|
||||
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[PATH_MAX * 2 + 1];
|
||||
int mib[4];
|
||||
size_t abspath_size;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
|
||||
abspath_size = sizeof abspath;
|
||||
if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
assert(abspath_size > 0);
|
||||
abspath_size -= 1;
|
||||
*size -= 1;
|
||||
|
||||
if (*size > abspath_size)
|
||||
*size = abspath_size;
|
||||
|
||||
memcpy(buffer, abspath, *size);
|
||||
buffer[*size] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
int freecount;
|
||||
size_t size = sizeof(freecount);
|
||||
|
||||
if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
unsigned long info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM};
|
||||
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int oid[4];
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = uv__strdup(title);
|
||||
|
||||
oid[0] = CTL_KERN;
|
||||
oid[1] = KERN_PROC;
|
||||
oid[2] = KERN_PROC_ARGS;
|
||||
oid[3] = getpid();
|
||||
|
||||
sysctl(oid,
|
||||
ARRAY_SIZE(oid),
|
||||
NULL,
|
||||
NULL,
|
||||
process_title,
|
||||
strlen(process_title) + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
kvm_t *kd = NULL;
|
||||
struct kinfo_proc *kinfo = NULL;
|
||||
pid_t pid;
|
||||
int nprocs;
|
||||
size_t page_size = getpagesize();
|
||||
|
||||
pid = getpid();
|
||||
|
||||
kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
|
||||
if (kd == NULL) goto error;
|
||||
|
||||
kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
|
||||
if (kinfo == NULL) goto error;
|
||||
|
||||
#ifdef __DragonFly__
|
||||
*rss = kinfo->kp_vm_rssize * page_size;
|
||||
#else
|
||||
*rss = kinfo->ki_rssize * page_size;
|
||||
#endif
|
||||
|
||||
kvm_close(kd);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (kd) kvm_close(kd);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
int r;
|
||||
struct timespec sp;
|
||||
r = clock_gettime(CLOCK_MONOTONIC, &sp);
|
||||
if (r)
|
||||
return -errno;
|
||||
|
||||
*uptime = sp.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
|
||||
cur = 0;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
const char* maxcpus_key;
|
||||
const char* cptimes_key;
|
||||
char model[512];
|
||||
long* cp_times;
|
||||
int numcpus;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
/* This is not quite correct but DragonFlyBSD doesn't seem to have anything
|
||||
* comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
|
||||
* not per CPU). At least this stops uv_cpu_info() from failing completely.
|
||||
*/
|
||||
maxcpus_key = "hw.ncpu";
|
||||
cptimes_key = "kern.cp_time";
|
||||
#else
|
||||
maxcpus_key = "kern.smp.maxcpus";
|
||||
cptimes_key = "kern.cp_times";
|
||||
#endif
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname("hw.model", &model, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
size = sizeof(numcpus);
|
||||
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos))
|
||||
return -ENOMEM;
|
||||
|
||||
*count = numcpus;
|
||||
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
|
||||
* ncpu.
|
||||
*/
|
||||
size = sizeof(maxcpus);
|
||||
if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
size = maxcpus * CPUSTATES * sizeof(long);
|
||||
|
||||
cp_times = uv__malloc(size);
|
||||
if (cp_times == NULL) {
|
||||
uv__free(*cpu_infos);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
|
||||
uv__free(cp_times);
|
||||
uv__free(*cpu_infos);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed;
|
||||
|
||||
cur+=CPUSTATES;
|
||||
}
|
||||
|
||||
uv__free(cp_times);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs *addrs, *ent;
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
struct sockaddr_dl *sa_addr;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family == AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* On FreeBSD getifaddrs returns information related to the raw underlying
|
||||
* devices. We're not interested in this information yet.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
1355
Utilities/cmlibuv/src/unix/fs.c
Normal file
1355
Utilities/cmlibuv/src/unix/fs.c
Normal file
File diff suppressed because it is too large
Load Diff
904
Utilities/cmlibuv/src/unix/fsevents.c
Normal file
904
Utilities/cmlibuv/src/unix/fsevents.c
Normal file
@@ -0,0 +1,904 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
#else /* TARGET_OS_IPHONE */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <CoreFoundation/CFRunLoop.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
/* These are macros to avoid "initializer element is not constant" errors
|
||||
* with old versions of gcc.
|
||||
*/
|
||||
#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
|
||||
kFSEventStreamEventFlagItemModified | \
|
||||
kFSEventStreamEventFlagItemInodeMetaMod | \
|
||||
kFSEventStreamEventFlagItemChangeOwner | \
|
||||
kFSEventStreamEventFlagItemXattrMod)
|
||||
|
||||
#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
|
||||
kFSEventStreamEventFlagItemRemoved | \
|
||||
kFSEventStreamEventFlagItemRenamed)
|
||||
|
||||
#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
|
||||
kFSEventStreamEventFlagKernelDropped | \
|
||||
kFSEventStreamEventFlagEventIdsWrapped | \
|
||||
kFSEventStreamEventFlagHistoryDone | \
|
||||
kFSEventStreamEventFlagMount | \
|
||||
kFSEventStreamEventFlagUnmount | \
|
||||
kFSEventStreamEventFlagRootChanged)
|
||||
|
||||
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
|
||||
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
|
||||
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
|
||||
|
||||
enum uv__cf_loop_signal_type_e {
|
||||
kUVCFLoopSignalRegular,
|
||||
kUVCFLoopSignalClosing
|
||||
};
|
||||
typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
|
||||
|
||||
struct uv__cf_loop_signal_s {
|
||||
QUEUE member;
|
||||
uv_fs_event_t* handle;
|
||||
uv__cf_loop_signal_type_t type;
|
||||
};
|
||||
|
||||
struct uv__fsevents_event_s {
|
||||
QUEUE member;
|
||||
int events;
|
||||
char path[1];
|
||||
};
|
||||
|
||||
struct uv__cf_loop_state_s {
|
||||
CFRunLoopRef loop;
|
||||
CFRunLoopSourceRef signal_source;
|
||||
int fsevent_need_reschedule;
|
||||
FSEventStreamRef fsevent_stream;
|
||||
uv_sem_t fsevent_sem;
|
||||
uv_mutex_t fsevent_mutex;
|
||||
void* fsevent_handles[2];
|
||||
unsigned int fsevent_handle_count;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
static void uv__cf_loop_cb(void* arg);
|
||||
static void* uv__cf_loop_runner(void* arg);
|
||||
static int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type);
|
||||
|
||||
/* Lazy-loaded by uv__fsevents_global_init(). */
|
||||
static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
|
||||
const void**,
|
||||
CFIndex,
|
||||
const CFArrayCallBacks*);
|
||||
static void (*pCFRelease)(CFTypeRef);
|
||||
static void (*pCFRunLoopAddSource)(CFRunLoopRef,
|
||||
CFRunLoopSourceRef,
|
||||
CFStringRef);
|
||||
static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
|
||||
static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
|
||||
CFRunLoopSourceRef,
|
||||
CFStringRef);
|
||||
static void (*pCFRunLoopRun)(void);
|
||||
static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
|
||||
CFIndex,
|
||||
CFRunLoopSourceContext*);
|
||||
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
|
||||
static void (*pCFRunLoopStop)(CFRunLoopRef);
|
||||
static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
|
||||
static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
|
||||
CFAllocatorRef,
|
||||
const char*);
|
||||
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
|
||||
static CFStringRef (*pkCFRunLoopDefaultMode);
|
||||
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
|
||||
FSEventStreamCallback,
|
||||
FSEventStreamContext*,
|
||||
CFArrayRef,
|
||||
FSEventStreamEventId,
|
||||
CFTimeInterval,
|
||||
FSEventStreamCreateFlags);
|
||||
static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamRelease)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
|
||||
CFRunLoopRef,
|
||||
CFStringRef);
|
||||
static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
|
||||
static void (*pFSEventStreamStop)(FSEventStreamRef);
|
||||
|
||||
#define UV__FSEVENTS_PROCESS(handle, block) \
|
||||
do { \
|
||||
QUEUE events; \
|
||||
QUEUE* q; \
|
||||
uv__fsevents_event_t* event; \
|
||||
int err; \
|
||||
uv_mutex_lock(&(handle)->cf_mutex); \
|
||||
/* Split-off all events and empty original queue */ \
|
||||
QUEUE_MOVE(&(handle)->cf_events, &events); \
|
||||
/* Get error (if any) and zero original one */ \
|
||||
err = (handle)->cf_error; \
|
||||
(handle)->cf_error = 0; \
|
||||
uv_mutex_unlock(&(handle)->cf_mutex); \
|
||||
/* Loop through events, deallocating each after processing */ \
|
||||
while (!QUEUE_EMPTY(&events)) { \
|
||||
q = QUEUE_HEAD(&events); \
|
||||
event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
|
||||
QUEUE_REMOVE(q); \
|
||||
/* NOTE: Checking uv__is_active() is required here, because handle \
|
||||
* callback may close handle and invoking it after it will lead to \
|
||||
* incorrect behaviour */ \
|
||||
if (!uv__is_closing((handle)) && uv__is_active((handle))) \
|
||||
block \
|
||||
/* Free allocated data */ \
|
||||
uv__free(event); \
|
||||
} \
|
||||
if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
|
||||
(handle)->cb((handle), NULL, 0, err); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Runs in UV loop's thread, when there're events to report to handle */
|
||||
static void uv__fsevents_cb(uv_async_t* cb) {
|
||||
uv_fs_event_t* handle;
|
||||
|
||||
handle = cb->data;
|
||||
|
||||
UV__FSEVENTS_PROCESS(handle, {
|
||||
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, pushed event into handle's event list */
|
||||
static void uv__fsevents_push_event(uv_fs_event_t* handle,
|
||||
QUEUE* events,
|
||||
int err) {
|
||||
assert(events != NULL || err != 0);
|
||||
uv_mutex_lock(&handle->cf_mutex);
|
||||
|
||||
/* Concatenate two queues */
|
||||
if (events != NULL)
|
||||
QUEUE_ADD(&handle->cf_events, events);
|
||||
|
||||
/* Propagate error */
|
||||
if (err != 0)
|
||||
handle->cf_error = err;
|
||||
uv_mutex_unlock(&handle->cf_mutex);
|
||||
|
||||
uv_async_send(handle->cf_cb);
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're events in FSEventStream */
|
||||
static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
void* info,
|
||||
size_t numEvents,
|
||||
void* eventPaths,
|
||||
const FSEventStreamEventFlags eventFlags[],
|
||||
const FSEventStreamEventId eventIds[]) {
|
||||
size_t i;
|
||||
int len;
|
||||
char** paths;
|
||||
char* path;
|
||||
char* pos;
|
||||
uv_fs_event_t* handle;
|
||||
QUEUE* q;
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
uv__fsevents_event_t* event;
|
||||
QUEUE head;
|
||||
|
||||
loop = info;
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
paths = eventPaths;
|
||||
|
||||
/* For each handle */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
QUEUE_INIT(&head);
|
||||
|
||||
/* Process and filter out events */
|
||||
for (i = 0; i < numEvents; i++) {
|
||||
/* Ignore system events */
|
||||
if (eventFlags[i] & kFSEventsSystem)
|
||||
continue;
|
||||
|
||||
path = paths[i];
|
||||
len = strlen(path);
|
||||
|
||||
/* Filter out paths that are outside handle's request */
|
||||
if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
continue;
|
||||
|
||||
if (handle->realpath_len > 1 || *handle->realpath != '/') {
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Skip forward slash */
|
||||
if (*path != '\0') {
|
||||
path++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len == 0)
|
||||
continue;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
/* Do not emit events from subdirectories (without option set) */
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
|
||||
pos = strchr(path + 1, '/');
|
||||
if (pos != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
path = "";
|
||||
len = 0;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
event = uv__malloc(sizeof(*event) + len);
|
||||
if (event == NULL)
|
||||
break;
|
||||
|
||||
memset(event, 0, sizeof(*event));
|
||||
memcpy(event->path, path, len + 1);
|
||||
|
||||
if ((eventFlags[i] & kFSEventsModified) != 0 &&
|
||||
(eventFlags[i] & kFSEventsRenamed) == 0)
|
||||
event->events = UV_CHANGE;
|
||||
else
|
||||
event->events = UV_RENAME;
|
||||
|
||||
QUEUE_INSERT_TAIL(&head, &event->member);
|
||||
}
|
||||
|
||||
if (!QUEUE_EMPTY(&head))
|
||||
uv__fsevents_push_event(handle, &head, 0);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread */
|
||||
static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
|
||||
uv__cf_loop_state_t* state;
|
||||
FSEventStreamContext ctx;
|
||||
FSEventStreamRef ref;
|
||||
CFAbsoluteTime latency;
|
||||
FSEventStreamCreateFlags flags;
|
||||
|
||||
/* Initialize context */
|
||||
ctx.version = 0;
|
||||
ctx.info = loop;
|
||||
ctx.retain = NULL;
|
||||
ctx.release = NULL;
|
||||
ctx.copyDescription = NULL;
|
||||
|
||||
latency = 0.05;
|
||||
|
||||
/* Explanation of selected flags:
|
||||
* 1. NoDefer - without this flag, events that are happening continuously
|
||||
* (i.e. each event is happening after time interval less than `latency`,
|
||||
* counted from previous event), will be deferred and passed to callback
|
||||
* once they'll either fill whole OS buffer, or when this continuous stream
|
||||
* will stop (i.e. there'll be delay between events, bigger than
|
||||
* `latency`).
|
||||
* Specifying this flag will invoke callback after `latency` time passed
|
||||
* since event.
|
||||
* 2. FileEvents - fire callback for file changes too (by default it is firing
|
||||
* it only for directory changes).
|
||||
*/
|
||||
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
|
||||
|
||||
/*
|
||||
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
|
||||
* but in reality one dir might have last StreamEventId less than, the other,
|
||||
* that is being watched now. Which will cause FSEventStream API to report
|
||||
* changes to files from the past.
|
||||
*/
|
||||
ref = pFSEventStreamCreate(NULL,
|
||||
&uv__fsevents_event_cb,
|
||||
&ctx,
|
||||
paths,
|
||||
kFSEventStreamEventIdSinceNow,
|
||||
latency,
|
||||
flags);
|
||||
assert(ref != NULL);
|
||||
|
||||
state = loop->cf_state;
|
||||
pFSEventStreamScheduleWithRunLoop(ref,
|
||||
state->loop,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
if (!pFSEventStreamStart(ref)) {
|
||||
pFSEventStreamInvalidate(ref);
|
||||
pFSEventStreamRelease(ref);
|
||||
return -EMFILE;
|
||||
}
|
||||
|
||||
state->fsevent_stream = ref;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread */
|
||||
static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
state = loop->cf_state;
|
||||
|
||||
if (state->fsevent_stream == NULL)
|
||||
return;
|
||||
|
||||
/* Flush all accumulated events */
|
||||
pFSEventStreamFlushSync(state->fsevent_stream);
|
||||
|
||||
/* Stop emitting events */
|
||||
pFSEventStreamStop(state->fsevent_stream);
|
||||
|
||||
/* Release stream */
|
||||
pFSEventStreamInvalidate(state->fsevent_stream);
|
||||
pFSEventStreamRelease(state->fsevent_stream);
|
||||
state->fsevent_stream = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, when there're new fsevent handles to add to stream */
|
||||
static void uv__fsevents_reschedule(uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
uv_fs_event_t* curr;
|
||||
CFArrayRef cf_paths;
|
||||
CFStringRef* paths;
|
||||
unsigned int i;
|
||||
int err;
|
||||
unsigned int path_count;
|
||||
|
||||
state = handle->loop->cf_state;
|
||||
paths = NULL;
|
||||
cf_paths = NULL;
|
||||
err = 0;
|
||||
/* NOTE: `i` is used in deallocation loop below */
|
||||
i = 0;
|
||||
|
||||
/* Optimization to prevent O(n^2) time spent when starting to watch
|
||||
* many files simultaneously
|
||||
*/
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
if (state->fsevent_need_reschedule == 0) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
state->fsevent_need_reschedule = 0;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Destroy previous FSEventStream */
|
||||
uv__fsevents_destroy_stream(handle->loop);
|
||||
|
||||
/* Any failure below will be a memory failure */
|
||||
err = -ENOMEM;
|
||||
|
||||
/* Create list of all watched paths */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
path_count = state->fsevent_handle_count;
|
||||
if (path_count != 0) {
|
||||
paths = uv__malloc(sizeof(*paths) * path_count);
|
||||
if (paths == NULL) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
|
||||
q = &state->fsevent_handles;
|
||||
for (; i < path_count; i++) {
|
||||
q = QUEUE_NEXT(q);
|
||||
assert(q != &state->fsevent_handles);
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
|
||||
assert(curr->realpath != NULL);
|
||||
paths[i] =
|
||||
pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
|
||||
if (paths[i] == NULL) {
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
goto final;
|
||||
}
|
||||
}
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
err = 0;
|
||||
|
||||
if (path_count != 0) {
|
||||
/* Create new FSEventStream */
|
||||
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
|
||||
if (cf_paths == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto final;
|
||||
}
|
||||
err = uv__fsevents_create_stream(handle->loop, cf_paths);
|
||||
}
|
||||
|
||||
final:
|
||||
/* Deallocate all paths in case of failure */
|
||||
if (err != 0) {
|
||||
if (cf_paths == NULL) {
|
||||
while (i != 0)
|
||||
pCFRelease(paths[--i]);
|
||||
uv__free(paths);
|
||||
} else {
|
||||
/* CFArray takes ownership of both strings and original C-array */
|
||||
pCFRelease(cf_paths);
|
||||
}
|
||||
|
||||
/* Broadcast error to all handles */
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_FOREACH(q, &state->fsevent_handles) {
|
||||
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
|
||||
uv__fsevents_push_event(curr, NULL, err);
|
||||
}
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main thread will block until the removal of handle from the list,
|
||||
* we must tell it when we're ready.
|
||||
*
|
||||
* NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
|
||||
*/
|
||||
if (type == kUVCFLoopSignalClosing)
|
||||
uv_sem_post(&state->fsevent_sem);
|
||||
}
|
||||
|
||||
|
||||
static int uv__fsevents_global_init(void) {
|
||||
static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void* core_foundation_handle;
|
||||
static void* core_services_handle;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
pthread_mutex_lock(&global_init_mutex);
|
||||
if (core_foundation_handle != NULL)
|
||||
goto out;
|
||||
|
||||
/* The libraries are never unloaded because we currently don't have a good
|
||||
* mechanism for keeping a reference count. It's unlikely to be an issue
|
||||
* but if it ever becomes one, we can turn the dynamic library handles into
|
||||
* per-event loop properties and have the dynamic linker keep track for us.
|
||||
*/
|
||||
err = -ENOSYS;
|
||||
core_foundation_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreFoundation.framework/"
|
||||
"Versions/A/CoreFoundation",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
if (core_foundation_handle == NULL)
|
||||
goto out;
|
||||
|
||||
core_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"CoreServices.framework/"
|
||||
"Versions/A/CoreServices",
|
||||
RTLD_LAZY | RTLD_LOCAL);
|
||||
if (core_services_handle == NULL)
|
||||
goto out;
|
||||
|
||||
err = -ENOENT;
|
||||
#define V(handle, symbol) \
|
||||
do { \
|
||||
*(void **)(&p ## symbol) = dlsym((handle), #symbol); \
|
||||
if (p ## symbol == NULL) \
|
||||
goto out; \
|
||||
} \
|
||||
while (0)
|
||||
V(core_foundation_handle, CFArrayCreate);
|
||||
V(core_foundation_handle, CFRelease);
|
||||
V(core_foundation_handle, CFRunLoopAddSource);
|
||||
V(core_foundation_handle, CFRunLoopGetCurrent);
|
||||
V(core_foundation_handle, CFRunLoopRemoveSource);
|
||||
V(core_foundation_handle, CFRunLoopRun);
|
||||
V(core_foundation_handle, CFRunLoopSourceCreate);
|
||||
V(core_foundation_handle, CFRunLoopSourceSignal);
|
||||
V(core_foundation_handle, CFRunLoopStop);
|
||||
V(core_foundation_handle, CFRunLoopWakeUp);
|
||||
V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
|
||||
V(core_foundation_handle, CFStringGetSystemEncoding);
|
||||
V(core_foundation_handle, kCFRunLoopDefaultMode);
|
||||
V(core_services_handle, FSEventStreamCreate);
|
||||
V(core_services_handle, FSEventStreamFlushSync);
|
||||
V(core_services_handle, FSEventStreamInvalidate);
|
||||
V(core_services_handle, FSEventStreamRelease);
|
||||
V(core_services_handle, FSEventStreamScheduleWithRunLoop);
|
||||
V(core_services_handle, FSEventStreamStart);
|
||||
V(core_services_handle, FSEventStreamStop);
|
||||
#undef V
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
if (err && core_services_handle != NULL) {
|
||||
dlclose(core_services_handle);
|
||||
core_services_handle = NULL;
|
||||
}
|
||||
|
||||
if (err && core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_init_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop */
|
||||
static int uv__fsevents_loop_init(uv_loop_t* loop) {
|
||||
CFRunLoopSourceContext ctx;
|
||||
uv__cf_loop_state_t* state;
|
||||
pthread_attr_t attr_storage;
|
||||
pthread_attr_t* attr;
|
||||
int err;
|
||||
|
||||
if (loop->cf_state != NULL)
|
||||
return 0;
|
||||
|
||||
err = uv__fsevents_global_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
state = uv__calloc(1, sizeof(*state));
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
err = uv_mutex_init(&loop->cf_mutex);
|
||||
if (err)
|
||||
goto fail_mutex_init;
|
||||
|
||||
err = uv_sem_init(&loop->cf_sem, 0);
|
||||
if (err)
|
||||
goto fail_sem_init;
|
||||
|
||||
QUEUE_INIT(&loop->cf_signals);
|
||||
|
||||
err = uv_sem_init(&state->fsevent_sem, 0);
|
||||
if (err)
|
||||
goto fail_fsevent_sem_init;
|
||||
|
||||
err = uv_mutex_init(&state->fsevent_mutex);
|
||||
if (err)
|
||||
goto fail_fsevent_mutex_init;
|
||||
|
||||
QUEUE_INIT(&state->fsevent_handles);
|
||||
state->fsevent_need_reschedule = 0;
|
||||
state->fsevent_handle_count = 0;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.info = loop;
|
||||
ctx.perform = uv__cf_loop_cb;
|
||||
state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
|
||||
if (state->signal_source == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto fail_signal_source_create;
|
||||
}
|
||||
|
||||
/* In the unlikely event that pthread_attr_init() fails, create the thread
|
||||
* with the default stack size. We'll use a little more address space but
|
||||
* that in itself is not a fatal error.
|
||||
*/
|
||||
attr = &attr_storage;
|
||||
if (pthread_attr_init(attr))
|
||||
attr = NULL;
|
||||
|
||||
if (attr != NULL)
|
||||
if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
|
||||
abort();
|
||||
|
||||
loop->cf_state = state;
|
||||
|
||||
/* uv_thread_t is an alias for pthread_t. */
|
||||
err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
if (err)
|
||||
goto fail_thread_create;
|
||||
|
||||
/* Synchronize threads */
|
||||
uv_sem_wait(&loop->cf_sem);
|
||||
return 0;
|
||||
|
||||
fail_thread_create:
|
||||
loop->cf_state = NULL;
|
||||
|
||||
fail_signal_source_create:
|
||||
uv_mutex_destroy(&state->fsevent_mutex);
|
||||
|
||||
fail_fsevent_mutex_init:
|
||||
uv_sem_destroy(&state->fsevent_sem);
|
||||
|
||||
fail_fsevent_sem_init:
|
||||
uv_sem_destroy(&loop->cf_sem);
|
||||
|
||||
fail_sem_init:
|
||||
uv_mutex_destroy(&loop->cf_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv__free(state);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop */
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop) {
|
||||
uv__cf_loop_signal_t* s;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* q;
|
||||
|
||||
if (loop->cf_state == NULL)
|
||||
return;
|
||||
|
||||
if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
|
||||
abort();
|
||||
|
||||
uv_thread_join(&loop->cf_thread);
|
||||
uv_sem_destroy(&loop->cf_sem);
|
||||
uv_mutex_destroy(&loop->cf_mutex);
|
||||
|
||||
/* Free any remaining data */
|
||||
while (!QUEUE_EMPTY(&loop->cf_signals)) {
|
||||
q = QUEUE_HEAD(&loop->cf_signals);
|
||||
s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
|
||||
QUEUE_REMOVE(q);
|
||||
uv__free(s);
|
||||
}
|
||||
|
||||
/* Destroy state */
|
||||
state = loop->cf_state;
|
||||
uv_sem_destroy(&state->fsevent_sem);
|
||||
uv_mutex_destroy(&state->fsevent_mutex);
|
||||
pCFRelease(state->signal_source);
|
||||
uv__free(state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread. This is the CF loop's body */
|
||||
static void* uv__cf_loop_runner(void* arg) {
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
loop = arg;
|
||||
state = loop->cf_state;
|
||||
state->loop = pCFRunLoopGetCurrent();
|
||||
|
||||
pCFRunLoopAddSource(state->loop,
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
uv_sem_post(&loop->cf_sem);
|
||||
|
||||
pCFRunLoopRun();
|
||||
pCFRunLoopRemoveSource(state->loop,
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
|
||||
static void uv__cf_loop_cb(void* arg) {
|
||||
uv_loop_t* loop;
|
||||
uv__cf_loop_state_t* state;
|
||||
QUEUE* item;
|
||||
QUEUE split_head;
|
||||
uv__cf_loop_signal_t* s;
|
||||
|
||||
loop = arg;
|
||||
state = loop->cf_state;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_MOVE(&loop->cf_signals, &split_head);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
while (!QUEUE_EMPTY(&split_head)) {
|
||||
item = QUEUE_HEAD(&split_head);
|
||||
QUEUE_REMOVE(item);
|
||||
|
||||
s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
|
||||
|
||||
/* This was a termination signal */
|
||||
if (s->handle == NULL)
|
||||
pCFRunLoopStop(state->loop);
|
||||
else
|
||||
uv__fsevents_reschedule(s->handle, s->type);
|
||||
|
||||
uv__free(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to notify CF thread */
|
||||
int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle,
|
||||
uv__cf_loop_signal_type_t type) {
|
||||
uv__cf_loop_signal_t* item;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
item = uv__malloc(sizeof(*item));
|
||||
if (item == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
item->handle = handle;
|
||||
item->type = type;
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
pCFRunLoopSourceSignal(state->signal_source);
|
||||
pCFRunLoopWakeUp(state->loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to initialize handle */
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
err = uv__fsevents_loop_init(handle->loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Get absolute path to file */
|
||||
handle->realpath = realpath(handle->path, NULL);
|
||||
if (handle->realpath == NULL)
|
||||
return -errno;
|
||||
handle->realpath_len = strlen(handle->realpath);
|
||||
|
||||
/* Initialize event queue */
|
||||
QUEUE_INIT(&handle->cf_events);
|
||||
handle->cf_error = 0;
|
||||
|
||||
/*
|
||||
* Events will occur in other thread.
|
||||
* Initialize callback for getting them back into event loop's thread
|
||||
*/
|
||||
handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
|
||||
if (handle->cf_cb == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto fail_cf_cb_malloc;
|
||||
}
|
||||
|
||||
handle->cf_cb->data = handle;
|
||||
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
|
||||
handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
|
||||
uv_unref((uv_handle_t*) handle->cf_cb);
|
||||
|
||||
err = uv_mutex_init(&handle->cf_mutex);
|
||||
if (err)
|
||||
goto fail_cf_mutex_init;
|
||||
|
||||
/* Insert handle into the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
|
||||
state->fsevent_handle_count++;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
|
||||
if (err)
|
||||
goto fail_loop_signal;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_loop_signal:
|
||||
uv_mutex_destroy(&handle->cf_mutex);
|
||||
|
||||
fail_cf_mutex_init:
|
||||
uv__free(handle->cf_cb);
|
||||
handle->cf_cb = NULL;
|
||||
|
||||
fail_cf_cb_malloc:
|
||||
uv__free(handle->realpath);
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Runs in UV loop to de-initialize handle */
|
||||
int uv__fsevents_close(uv_fs_event_t* handle) {
|
||||
int err;
|
||||
uv__cf_loop_state_t* state;
|
||||
|
||||
if (handle->cf_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Remove handle from the list */
|
||||
state = handle->loop->cf_state;
|
||||
uv_mutex_lock(&state->fsevent_mutex);
|
||||
QUEUE_REMOVE(&handle->cf_member);
|
||||
state->fsevent_handle_count--;
|
||||
state->fsevent_need_reschedule = 1;
|
||||
uv_mutex_unlock(&state->fsevent_mutex);
|
||||
|
||||
/* Reschedule FSEventStream */
|
||||
assert(handle != NULL);
|
||||
err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
/* Wait for deinitialization */
|
||||
uv_sem_wait(&state->fsevent_sem);
|
||||
|
||||
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
|
||||
handle->cf_cb = NULL;
|
||||
|
||||
/* Free data in queue */
|
||||
UV__FSEVENTS_PROCESS(handle, {
|
||||
/* NOP */
|
||||
});
|
||||
|
||||
uv_mutex_destroy(&handle->cf_mutex);
|
||||
uv__free(handle->realpath);
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
202
Utilities/cmlibuv/src/unix/getaddrinfo.c
Normal file
202
Utilities/cmlibuv/src/unix/getaddrinfo.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
|
||||
* include any headers.
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* EAI_* constants. */
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
switch (sys_err) {
|
||||
case 0: return 0;
|
||||
#if defined(EAI_ADDRFAMILY)
|
||||
case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
|
||||
#endif
|
||||
#if defined(EAI_AGAIN)
|
||||
case EAI_AGAIN: return UV_EAI_AGAIN;
|
||||
#endif
|
||||
#if defined(EAI_BADFLAGS)
|
||||
case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
|
||||
#endif
|
||||
#if defined(EAI_BADHINTS)
|
||||
case EAI_BADHINTS: return UV_EAI_BADHINTS;
|
||||
#endif
|
||||
#if defined(EAI_CANCELED)
|
||||
case EAI_CANCELED: return UV_EAI_CANCELED;
|
||||
#endif
|
||||
#if defined(EAI_FAIL)
|
||||
case EAI_FAIL: return UV_EAI_FAIL;
|
||||
#endif
|
||||
#if defined(EAI_FAMILY)
|
||||
case EAI_FAMILY: return UV_EAI_FAMILY;
|
||||
#endif
|
||||
#if defined(EAI_MEMORY)
|
||||
case EAI_MEMORY: return UV_EAI_MEMORY;
|
||||
#endif
|
||||
#if defined(EAI_NODATA)
|
||||
case EAI_NODATA: return UV_EAI_NODATA;
|
||||
#endif
|
||||
#if defined(EAI_NONAME)
|
||||
# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
|
||||
case EAI_NONAME: return UV_EAI_NONAME;
|
||||
# endif
|
||||
#endif
|
||||
#if defined(EAI_OVERFLOW)
|
||||
case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
|
||||
#endif
|
||||
#if defined(EAI_PROTOCOL)
|
||||
case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
|
||||
#endif
|
||||
#if defined(EAI_SERVICE)
|
||||
case EAI_SERVICE: return UV_EAI_SERVICE;
|
||||
#endif
|
||||
#if defined(EAI_SOCKTYPE)
|
||||
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
|
||||
#endif
|
||||
#if defined(EAI_SYSTEM)
|
||||
case EAI_SYSTEM: return -errno;
|
||||
#endif
|
||||
}
|
||||
assert(!"unknown EAI_* error code");
|
||||
abort();
|
||||
return 0; /* Pacify compiler. */
|
||||
}
|
||||
|
||||
|
||||
static void uv__getaddrinfo_work(struct uv__work* w) {
|
||||
uv_getaddrinfo_t* req;
|
||||
int err;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
|
||||
req->retcode = uv__getaddrinfo_translate_error(err);
|
||||
}
|
||||
|
||||
|
||||
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
|
||||
/* See initialization in uv_getaddrinfo(). */
|
||||
if (req->hints)
|
||||
uv__free(req->hints);
|
||||
else if (req->service)
|
||||
uv__free(req->service);
|
||||
else if (req->hostname)
|
||||
uv__free(req->hostname);
|
||||
else
|
||||
assert(0);
|
||||
|
||||
req->hints = NULL;
|
||||
req->service = NULL;
|
||||
req->hostname = NULL;
|
||||
|
||||
if (status == -ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
}
|
||||
|
||||
if (req->cb)
|
||||
req->cb(req, req->retcode, req->addrinfo);
|
||||
}
|
||||
|
||||
|
||||
int uv_getaddrinfo(uv_loop_t* loop,
|
||||
uv_getaddrinfo_t* req,
|
||||
uv_getaddrinfo_cb cb,
|
||||
const char* hostname,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
size_t hostname_len;
|
||||
size_t service_len;
|
||||
size_t hints_len;
|
||||
size_t len;
|
||||
char* buf;
|
||||
|
||||
if (req == NULL || (hostname == NULL && service == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
hostname_len = hostname ? strlen(hostname) + 1 : 0;
|
||||
service_len = service ? strlen(service) + 1 : 0;
|
||||
hints_len = hints ? sizeof(*hints) : 0;
|
||||
buf = uv__malloc(hostname_len + service_len + hints_len);
|
||||
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
uv__req_init(loop, req, UV_GETADDRINFO);
|
||||
req->loop = loop;
|
||||
req->cb = cb;
|
||||
req->addrinfo = NULL;
|
||||
req->hints = NULL;
|
||||
req->service = NULL;
|
||||
req->hostname = NULL;
|
||||
req->retcode = 0;
|
||||
|
||||
/* order matters, see uv_getaddrinfo_done() */
|
||||
len = 0;
|
||||
|
||||
if (hints) {
|
||||
req->hints = memcpy(buf + len, hints, sizeof(*hints));
|
||||
len += sizeof(*hints);
|
||||
}
|
||||
|
||||
if (service) {
|
||||
req->service = memcpy(buf + len, service, service_len);
|
||||
len += service_len;
|
||||
}
|
||||
|
||||
if (hostname)
|
||||
req->hostname = memcpy(buf + len, hostname, hostname_len);
|
||||
|
||||
if (cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getaddrinfo_work(&req->work_req);
|
||||
uv__getaddrinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_freeaddrinfo(struct addrinfo* ai) {
|
||||
if (ai)
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
120
Utilities/cmlibuv/src/unix/getnameinfo.c
Normal file
120
Utilities/cmlibuv/src/unix/getnameinfo.c
Normal file
@@ -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 "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
uv_getnameinfo_t* req;
|
||||
int err;
|
||||
socklen_t salen;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
|
||||
if (req->storage.ss_family == AF_INET)
|
||||
salen = sizeof(struct sockaddr_in);
|
||||
else if (req->storage.ss_family == AF_INET6)
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
abort();
|
||||
|
||||
err = getnameinfo((struct sockaddr*) &req->storage,
|
||||
salen,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
req->flags);
|
||||
req->retcode = uv__getaddrinfo_translate_error(err);
|
||||
}
|
||||
|
||||
static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
uv_getnameinfo_t* req;
|
||||
char* host;
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == -ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
} else if (req->retcode == 0) {
|
||||
host = req->host;
|
||||
service = req->service;
|
||||
}
|
||||
|
||||
if (req->getnameinfo_cb)
|
||||
req->getnameinfo_cb(req, req->retcode, host, service);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entry point for getnameinfo
|
||||
* return 0 if a callback will be made
|
||||
* return error code if validation fails
|
||||
*/
|
||||
int uv_getnameinfo(uv_loop_t* loop,
|
||||
uv_getnameinfo_t* req,
|
||||
uv_getnameinfo_cb getnameinfo_cb,
|
||||
const struct sockaddr* addr,
|
||||
int flags) {
|
||||
if (req == NULL || addr == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
|
||||
|
||||
req->getnameinfo_cb = getnameinfo_cb;
|
||||
req->flags = flags;
|
||||
req->type = UV_GETNAMEINFO;
|
||||
req->loop = loop;
|
||||
req->retcode = 0;
|
||||
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getnameinfo_work(&req->work_req);
|
||||
uv__getnameinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
}
|
||||
322
Utilities/cmlibuv/src/unix/internal.h
Normal file
322
Utilities/cmlibuv/src/unix/internal.h
Normal file
@@ -0,0 +1,322 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_UNIX_INTERNAL_H_
|
||||
#define UV_UNIX_INTERNAL_H_
|
||||
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h> /* abort */
|
||||
#include <string.h> /* strrchr */
|
||||
#include <fcntl.h> /* O_CLOEXEC, may be */
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(__STRICT_ANSI__)
|
||||
# define inline __inline
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "linux-syscalls.h"
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined(__sun)
|
||||
# include <sys/port.h>
|
||||
# include <port.h>
|
||||
#endif /* __sun */
|
||||
|
||||
#if defined(_AIX)
|
||||
# define reqevents events
|
||||
# define rtnevents revents
|
||||
# include <sys/poll.h>
|
||||
#else
|
||||
# include <poll.h>
|
||||
#endif /* _AIX */
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
# ifdef pthread_sigmask
|
||||
# undef pthread_sigmask
|
||||
# endif
|
||||
# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
|
||||
#endif
|
||||
|
||||
#define ACCESS_ONCE(type, var) \
|
||||
(*(volatile type*) &(var))
|
||||
|
||||
#define ROUND_UP(a, b) \
|
||||
((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
|
||||
|
||||
#define UNREACHABLE() \
|
||||
do { \
|
||||
assert(0 && "unreachable code"); \
|
||||
abort(); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SAVE_ERRNO(block) \
|
||||
do { \
|
||||
int _saved_errno = errno; \
|
||||
do { block; } while (0); \
|
||||
errno = _saved_errno; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
|
||||
* define __GNUC__. They are here to convey to you, dear reader, that these
|
||||
* macros are enabled when compiling with clang or icc.
|
||||
*/
|
||||
#if defined(__clang__) || \
|
||||
defined(__GNUC__) || \
|
||||
defined(__INTEL_COMPILER) || \
|
||||
defined(__SUNPRO_C)
|
||||
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
|
||||
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
|
||||
#else
|
||||
# define UV_DESTRUCTOR(declaration) declaration
|
||||
# define UV_UNUSED(declaration) declaration
|
||||
#endif
|
||||
|
||||
/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */
|
||||
#ifdef POLLRDHUP
|
||||
# define UV__POLLRDHUP POLLRDHUP
|
||||
#else
|
||||
# define UV__POLLRDHUP 0x2000
|
||||
#endif
|
||||
|
||||
#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
|
||||
/*
|
||||
* It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
|
||||
* Try using fixed value const and give up, if it doesn't work
|
||||
*/
|
||||
# define O_CLOEXEC 0x00100000
|
||||
#endif
|
||||
|
||||
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
|
||||
/* handle flags */
|
||||
enum {
|
||||
UV_CLOSING = 0x01, /* uv_close() called but not finished. */
|
||||
UV_CLOSED = 0x02, /* close(2) finished. */
|
||||
UV_STREAM_READING = 0x04, /* uv_read_start() called. */
|
||||
UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
|
||||
UV_STREAM_SHUT = 0x10, /* Write side closed. */
|
||||
UV_STREAM_READABLE = 0x20, /* The stream is readable */
|
||||
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
|
||||
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
|
||||
UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
|
||||
UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
|
||||
UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
|
||||
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
|
||||
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
|
||||
UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
|
||||
UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */
|
||||
UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */
|
||||
};
|
||||
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 1
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
|
||||
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
|
||||
} uv_clocktype_t;
|
||||
|
||||
struct uv__stream_queued_fds_s {
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
int fds[1];
|
||||
};
|
||||
|
||||
|
||||
#if defined(_AIX) || \
|
||||
defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__linux__)
|
||||
#define uv__cloexec uv__cloexec_ioctl
|
||||
#define uv__nonblock uv__nonblock_ioctl
|
||||
#else
|
||||
#define uv__cloexec uv__cloexec_fcntl
|
||||
#define uv__nonblock uv__nonblock_fcntl
|
||||
#endif
|
||||
|
||||
/* core */
|
||||
int uv__cloexec_ioctl(int fd, int set);
|
||||
int uv__cloexec_fcntl(int fd, int set);
|
||||
int uv__nonblock_ioctl(int fd, int set);
|
||||
int uv__nonblock_fcntl(int fd, int set);
|
||||
int uv__close(int fd);
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__dup(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
|
||||
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
|
||||
void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
void uv__io_close(uv_loop_t* loop, uv__io_t* w);
|
||||
void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
|
||||
int uv__io_active(const uv__io_t* w, unsigned int events);
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd);
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
|
||||
|
||||
/* async */
|
||||
void uv__async_send(struct uv__async* wa);
|
||||
void uv__async_init(struct uv__async* wa);
|
||||
int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
|
||||
void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
|
||||
|
||||
/* loop */
|
||||
void uv__run_idle(uv_loop_t* loop);
|
||||
void uv__run_check(uv_loop_t* loop);
|
||||
void uv__run_prepare(uv_loop_t* loop);
|
||||
|
||||
/* stream */
|
||||
void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
|
||||
uv_handle_type type);
|
||||
int uv__stream_open(uv_stream_t*, int fd, int flags);
|
||||
void uv__stream_destroy(uv_stream_t* stream);
|
||||
#if defined(__APPLE__)
|
||||
int uv__stream_try_select(uv_stream_t* stream, int* fd);
|
||||
#endif /* defined(__APPLE__) */
|
||||
void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
int uv__accept(int sockfd);
|
||||
int uv__dup2_cloexec(int oldfd, int newfd);
|
||||
int uv__open_cloexec(const char* path, int flags);
|
||||
|
||||
/* tcp */
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
|
||||
int uv__tcp_nodelay(int fd, int on);
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay);
|
||||
|
||||
/* pipe */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
/* timer */
|
||||
void uv__run_timers(uv_loop_t* loop);
|
||||
int uv__next_timeout(const uv_loop_t* loop);
|
||||
|
||||
/* signal */
|
||||
void uv__signal_close(uv_signal_t* handle);
|
||||
void uv__signal_global_once_init(void);
|
||||
void uv__signal_loop_cleanup(uv_loop_t* loop);
|
||||
|
||||
/* platform specific */
|
||||
uint64_t uv__hrtime(uv_clocktype_t type);
|
||||
int uv__kqueue_init(uv_loop_t* loop);
|
||||
int uv__platform_loop_init(uv_loop_t* loop);
|
||||
void uv__platform_loop_delete(uv_loop_t* loop);
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
|
||||
|
||||
/* various */
|
||||
void uv__async_close(uv_async_t* handle);
|
||||
void uv__check_close(uv_check_t* handle);
|
||||
void uv__fs_event_close(uv_fs_event_t* handle);
|
||||
void uv__idle_close(uv_idle_t* handle);
|
||||
void uv__pipe_close(uv_pipe_t* handle);
|
||||
void uv__poll_close(uv_poll_t* handle);
|
||||
void uv__prepare_close(uv_prepare_t* handle);
|
||||
void uv__process_close(uv_process_t* handle);
|
||||
void uv__stream_close(uv_stream_t* handle);
|
||||
void uv__tcp_close(uv_tcp_t* handle);
|
||||
void uv__timer_close(uv_timer_t* handle);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
uv_handle_type uv__handle_type(int fd);
|
||||
FILE* uv__open_file(const char* path);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
int uv___stream_fd(const uv_stream_t* handle);
|
||||
#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
|
||||
#else
|
||||
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#ifdef UV__O_NONBLOCK
|
||||
# define UV__F_NONBLOCK UV__O_NONBLOCK
|
||||
#else
|
||||
# define UV__F_NONBLOCK 1
|
||||
#endif
|
||||
|
||||
int uv__make_socketpair(int fds[2], int flags);
|
||||
int uv__make_pipe(int fds[2], int flags);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle);
|
||||
int uv__fsevents_close(uv_fs_event_t* handle);
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop);
|
||||
|
||||
/* OSX < 10.7 has no file events, polyfill them */
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
|
||||
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
|
||||
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
|
||||
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
|
||||
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
|
||||
static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
|
||||
static const int kFSEventStreamEventFlagItemModified = 0x00001000;
|
||||
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
|
||||
static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
|
||||
static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
|
||||
static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
|
||||
static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
|
||||
static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
|
||||
|
||||
#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
|
||||
uv_req_t* req,
|
||||
uv_req_type type)) {
|
||||
req->type = type;
|
||||
uv__req_register(loop, req);
|
||||
}
|
||||
#define uv__req_init(loop, req, type) \
|
||||
uv__req_init((loop), (uv_req_t*)(req), (type))
|
||||
|
||||
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
/* Use a fast time source if available. We only need millisecond precision.
|
||||
*/
|
||||
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
|
||||
}
|
||||
|
||||
UV_UNUSED(static char* uv__basename_r(const char* path)) {
|
||||
char* s;
|
||||
|
||||
s = strrchr(path, '/');
|
||||
if (s == NULL)
|
||||
return (char*) path;
|
||||
|
||||
return s + 1;
|
||||
}
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
463
Utilities/cmlibuv/src/unix/kqueue.c
Normal file
463
Utilities/cmlibuv/src/unix/kqueue.c
Normal file
@@ -0,0 +1,463 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
|
||||
|
||||
|
||||
int uv__kqueue_init(uv_loop_t* loop) {
|
||||
loop->backend_fd = kqueue();
|
||||
if (loop->backend_fd == -1)
|
||||
return -errno;
|
||||
|
||||
uv__cloexec(loop->backend_fd, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent ev;
|
||||
int rc;
|
||||
|
||||
rc = 0;
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
rc = -errno;
|
||||
|
||||
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
|
||||
if (rc == 0)
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct kevent events[1024];
|
||||
struct kevent* ev;
|
||||
struct timespec spec;
|
||||
unsigned int nevents;
|
||||
unsigned int revents;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
int have_signals;
|
||||
int filter;
|
||||
int fflags;
|
||||
int count;
|
||||
int nfds;
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
nevents = 0;
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
|
||||
filter = EVFILT_READ;
|
||||
fflags = 0;
|
||||
op = EV_ADD;
|
||||
|
||||
if (w->cb == uv__fs_event) {
|
||||
filter = EVFILT_VNODE;
|
||||
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
|
||||
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
|
||||
op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
|
||||
}
|
||||
|
||||
EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
|
||||
|
||||
if (++nevents == ARRAY_SIZE(events)) {
|
||||
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
|
||||
abort();
|
||||
nevents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
|
||||
EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
|
||||
|
||||
if (++nevents == ARRAY_SIZE(events)) {
|
||||
if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
|
||||
abort();
|
||||
nevents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
pset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
pset = &set;
|
||||
sigemptyset(pset);
|
||||
sigaddset(pset, SIGPROF);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
|
||||
for (;; nevents = 0) {
|
||||
if (timeout != -1) {
|
||||
spec.tv_sec = timeout / 1000;
|
||||
spec.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_BLOCK, pset, NULL);
|
||||
|
||||
nfds = kevent(loop->backend_fd,
|
||||
events,
|
||||
nevents,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout == -1 ? NULL : &spec);
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||
* operating system didn't reschedule our process while in the syscall.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
/* Interrupted by a signal. Update timeout and poll again. */
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = (void*) events;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
ev = events + i;
|
||||
fd = ev->ident;
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
w = loop->watchers[fd];
|
||||
|
||||
if (w == NULL) {
|
||||
/* File descriptor that we've stopped watching, disarm it. */
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != EBADF && errno != ENOENT)
|
||||
abort();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->filter == EVFILT_VNODE) {
|
||||
assert(w->events == POLLIN);
|
||||
assert(w->pevents == POLLIN);
|
||||
w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
|
||||
nevents++;
|
||||
continue;
|
||||
}
|
||||
|
||||
revents = 0;
|
||||
|
||||
if (ev->filter == EVFILT_READ) {
|
||||
if (w->pevents & POLLIN) {
|
||||
revents |= POLLIN;
|
||||
w->rcount = ev->data;
|
||||
} else {
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->filter == EVFILT_WRITE) {
|
||||
if (w->pevents & POLLOUT) {
|
||||
revents |= POLLOUT;
|
||||
w->wcount = ev->data;
|
||||
} else {
|
||||
/* TODO batch up */
|
||||
struct kevent events[1];
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
|
||||
if (errno != ENOENT)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->flags & EV_ERROR)
|
||||
revents |= POLLERR;
|
||||
|
||||
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
|
||||
revents |= UV__POLLRDHUP;
|
||||
|
||||
if (revents == 0)
|
||||
continue;
|
||||
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher)
|
||||
have_signals = 1;
|
||||
else
|
||||
w->cb(loop, w, revents);
|
||||
|
||||
nevents++;
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
if (nevents != 0) {
|
||||
if (nfds == ARRAY_SIZE(events) && --count != 0) {
|
||||
/* Poll for more events but don't block this time. */
|
||||
timeout = 0;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
update_timeout:
|
||||
assert(timeout > 0);
|
||||
|
||||
diff = loop->time - base;
|
||||
if (diff >= (uint64_t) timeout)
|
||||
return;
|
||||
|
||||
timeout -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct kevent* events;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
|
||||
events = (struct kevent*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events == NULL)
|
||||
return;
|
||||
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].ident == fd)
|
||||
events[i].ident = -1;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
|
||||
uv_fs_event_t* handle;
|
||||
struct kevent ev;
|
||||
int events;
|
||||
const char* path;
|
||||
#if defined(F_GETPATH)
|
||||
/* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
|
||||
char pathbuf[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
handle = container_of(w, uv_fs_event_t, event_watcher);
|
||||
|
||||
if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
|
||||
events = UV_CHANGE;
|
||||
else
|
||||
events = UV_RENAME;
|
||||
|
||||
path = NULL;
|
||||
#if defined(F_GETPATH)
|
||||
/* Also works when the file has been unlinked from the file system. Passing
|
||||
* in the path when the file has been deleted is arguably a little strange
|
||||
* but it's consistent with what the inotify backend does.
|
||||
*/
|
||||
if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
|
||||
path = uv__basename_r(pathbuf);
|
||||
#endif
|
||||
handle->cb(handle, path, events, 0);
|
||||
|
||||
if (handle->event_watcher.fd == -1)
|
||||
return;
|
||||
|
||||
/* Watcher operates in one-shot mode, re-arm it. */
|
||||
fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
|
||||
| NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
|
||||
|
||||
EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
|
||||
|
||||
if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
#if defined(__APPLE__)
|
||||
struct stat statbuf;
|
||||
#endif /* defined(__APPLE__) */
|
||||
int fd;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
handle->path = uv__strdup(path);
|
||||
handle->cb = cb;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
handle->cf_flags = flags;
|
||||
|
||||
if (fstat(fd, &statbuf))
|
||||
goto fallback;
|
||||
/* FSEvents works only with directories */
|
||||
if (!(statbuf.st_mode & S_IFDIR))
|
||||
goto fallback;
|
||||
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close(fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
|
||||
return uv__fsevents_init(handle);
|
||||
|
||||
fallback:
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (uv__fsevents_close(handle))
|
||||
#endif /* defined(__APPLE__) */
|
||||
{
|
||||
uv__io_close(handle->loop, &handle->event_watcher);
|
||||
}
|
||||
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
/* When FSEvents is used, we don't use the event_watcher's fd under certain
|
||||
* confitions. (see uv_fs_event_start) */
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
985
Utilities/cmlibuv/src/unix/linux-core.c
Normal file
985
Utilities/cmlibuv/src/unix/linux-core.c
Normal file
@@ -0,0 +1,985 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
|
||||
* EPOLL* counterparts. We use the POLL* variants in this file because that
|
||||
* is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#define HAVE_IFADDRS_H 1
|
||||
|
||||
#ifdef __UCLIBC__
|
||||
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
|
||||
# undef HAVE_IFADDRS_H
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
# if defined(__ANDROID__)
|
||||
# include "android-ifaddrs.h"
|
||||
# else
|
||||
# include <ifaddrs.h>
|
||||
# endif
|
||||
# include <sys/socket.h>
|
||||
# include <net/ethernet.h>
|
||||
# include <netpacket/packet.h>
|
||||
#endif /* HAVE_IFADDRS_H */
|
||||
|
||||
/* Available from 2.6.32 onwards. */
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
# define CLOCK_MONOTONIC_COARSE 6
|
||||
#endif
|
||||
|
||||
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
|
||||
* include that file because it conflicts with <time.h>. We'll just have to
|
||||
* define it ourselves.
|
||||
*/
|
||||
#ifndef CLOCK_BOOTTIME
|
||||
# define CLOCK_BOOTTIME 7
|
||||
#endif
|
||||
|
||||
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
|
||||
static int read_times(FILE* statfile_fp,
|
||||
unsigned int numcpus,
|
||||
uv_cpu_info_t* ci);
|
||||
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
|
||||
static unsigned long read_cpufreq(unsigned int cpunum);
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int fd;
|
||||
|
||||
fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the EPOLL_CLOEXEC flag.
|
||||
*/
|
||||
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
|
||||
fd = uv__epoll_create(256);
|
||||
|
||||
if (fd != -1)
|
||||
uv__cloexec(fd, 1);
|
||||
}
|
||||
|
||||
loop->backend_fd = fd;
|
||||
loop->inotify_fd = -1;
|
||||
loop->inotify_watchers = NULL;
|
||||
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
if (loop->inotify_fd == -1) return;
|
||||
uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
|
||||
uv__close(loop->inotify_fd);
|
||||
loop->inotify_fd = -1;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event* events;
|
||||
struct uv__epoll_event dummy;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
|
||||
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events != NULL)
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].data == fd)
|
||||
events[i].data = -1;
|
||||
|
||||
/* Remove the file descriptor from the epoll.
|
||||
* This avoids a problem where the same file description remains open
|
||||
* in another process, causing repeated junk epoll events.
|
||||
*
|
||||
* We pass in a dummy epoll_event, to work around a bug in old kernels.
|
||||
*/
|
||||
if (loop->backend_fd >= 0) {
|
||||
/* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
|
||||
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
|
||||
*/
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event e;
|
||||
int rc;
|
||||
|
||||
e.events = POLLIN;
|
||||
e.data = -1;
|
||||
|
||||
rc = 0;
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
|
||||
if (errno != EEXIST)
|
||||
rc = -errno;
|
||||
|
||||
if (rc == 0)
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
/* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
|
||||
* effectively infinite on 32 bits architectures. To avoid blocking
|
||||
* indefinitely, we cap the timeout and poll again if necessary.
|
||||
*
|
||||
* Note that "30 minutes" is a simplification because it depends on
|
||||
* the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
|
||||
* that being the largest value I have seen in the wild (and only once.)
|
||||
*/
|
||||
static const int max_safe_timeout = 1789569;
|
||||
static int no_epoll_pwait;
|
||||
static int no_epoll_wait;
|
||||
struct uv__epoll_event events[1024];
|
||||
struct uv__epoll_event* pe;
|
||||
struct uv__epoll_event e;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
uint64_t sigmask;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
int count;
|
||||
int nfds;
|
||||
int fd;
|
||||
int op;
|
||||
int i;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
assert(w->fd >= 0);
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
e.events = w->pevents;
|
||||
e.data = w->fd;
|
||||
|
||||
if (w->events == 0)
|
||||
op = UV__EPOLL_CTL_ADD;
|
||||
else
|
||||
op = UV__EPOLL_CTL_MOD;
|
||||
|
||||
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
|
||||
* events, skip the syscall and squelch the events after epoll_wait().
|
||||
*/
|
||||
if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
|
||||
if (errno != EEXIST)
|
||||
abort();
|
||||
|
||||
assert(op == UV__EPOLL_CTL_ADD);
|
||||
|
||||
/* We've reactivated a file descriptor that's been watched before. */
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
sigmask = 0;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
sigmask |= 1 << (SIGPROF - 1);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
real_timeout = timeout;
|
||||
|
||||
for (;;) {
|
||||
/* See the comment for max_safe_timeout for an explanation of why
|
||||
* this is necessary. Executive summary: kernel bug workaround.
|
||||
*/
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||
abort();
|
||||
|
||||
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
|
||||
nfds = uv__epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
sigmask);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_pwait = 1;
|
||||
} else {
|
||||
nfds = uv__epoll_wait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_wait = 1;
|
||||
}
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
|
||||
abort();
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||
* operating system didn't reschedule our process while in the syscall.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* We may have been inside the system call for longer than |timeout|
|
||||
* milliseconds so we need to update the timestamp to avoid drift.
|
||||
*/
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
|
||||
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
/* Interrupted by a signal. Update timeout and poll again. */
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = (void*) events;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert((unsigned) fd < loop->nwatchers);
|
||||
|
||||
w = loop->watchers[fd];
|
||||
|
||||
if (w == NULL) {
|
||||
/* File descriptor that we've stopped watching, disarm it.
|
||||
*
|
||||
* Ignore all errors because we may be racing with another thread
|
||||
* when the file descriptor is closed.
|
||||
*/
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Give users only events they're interested in. Prevents spurious
|
||||
* callbacks when previous callback invocation in this loop has stopped
|
||||
* the current watcher. Also, filters out events that users has not
|
||||
* requested us to watch.
|
||||
*/
|
||||
pe->events &= w->pevents | POLLERR | POLLHUP;
|
||||
|
||||
/* Work around an epoll quirk where it sometimes reports just the
|
||||
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
|
||||
* move forward, we merge in the read/write events that the watcher
|
||||
* is interested in; uv__read() and uv__write() will then deal with
|
||||
* the error or hangup in the usual fashion.
|
||||
*
|
||||
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
|
||||
* reads the available data, calls uv_read_stop(), then sometime later
|
||||
* calls uv_read_start() again. By then, libuv has forgotten about the
|
||||
* hangup and the kernel won't report EPOLLIN again because there's
|
||||
* nothing left to read. If anything, libuv is to blame here. The
|
||||
* current hack is just a quick bandaid; to properly fix it, libuv
|
||||
* needs to remember the error/hangup event. We should get that for
|
||||
* free when we switch over to edge-triggered I/O.
|
||||
*/
|
||||
if (pe->events == POLLERR || pe->events == POLLHUP)
|
||||
pe->events |= w->pevents & (POLLIN | POLLOUT);
|
||||
|
||||
if (pe->events != 0) {
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher)
|
||||
have_signals = 1;
|
||||
else
|
||||
w->cb(loop, w, pe->events);
|
||||
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
if (nevents != 0) {
|
||||
if (nfds == ARRAY_SIZE(events) && --count != 0) {
|
||||
/* Poll for more events but don't block this time. */
|
||||
timeout = 0;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
update_timeout:
|
||||
assert(timeout > 0);
|
||||
|
||||
real_timeout -= (loop->time - base);
|
||||
if (real_timeout <= 0)
|
||||
return;
|
||||
|
||||
timeout = real_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
static clock_t fast_clock_id = -1;
|
||||
struct timespec t;
|
||||
clock_t clock_id;
|
||||
|
||||
/* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
|
||||
* millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
|
||||
* serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
|
||||
* decide to make a costly system call.
|
||||
*/
|
||||
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
|
||||
* when it has microsecond granularity or better (unlikely).
|
||||
*/
|
||||
if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
|
||||
if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
|
||||
t.tv_nsec <= 1 * 1000 * 1000) {
|
||||
fast_clock_id = CLOCK_MONOTONIC_COARSE;
|
||||
} else {
|
||||
fast_clock_id = CLOCK_MONOTONIC;
|
||||
}
|
||||
}
|
||||
|
||||
clock_id = CLOCK_MONOTONIC;
|
||||
if (type == UV_CLOCK_FAST)
|
||||
clock_id = fast_clock_id;
|
||||
|
||||
if (clock_gettime(clock_id, &t))
|
||||
return 0; /* Not really possible. */
|
||||
|
||||
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) < 0) return;
|
||||
|
||||
avg[0] = (double) info.loads[0] / 65536.0;
|
||||
avg[1] = (double) info.loads[1] / 65536.0;
|
||||
avg[2] = (double) info.loads[2] / 65536.0;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
ssize_t n;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
n = *size - 1;
|
||||
if (n > 0)
|
||||
n = readlink("/proc/self/exe", buffer, n);
|
||||
|
||||
if (n == -1)
|
||||
return -errno;
|
||||
|
||||
buffer[n] = '\0';
|
||||
*size = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
char buf[1024];
|
||||
const char* s;
|
||||
ssize_t n;
|
||||
long val;
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
do
|
||||
fd = open("/proc/self/stat", O_RDONLY);
|
||||
while (fd == -1 && errno == EINTR);
|
||||
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
do
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
uv__close(fd);
|
||||
if (n == -1)
|
||||
return -errno;
|
||||
buf[n] = '\0';
|
||||
|
||||
s = strchr(buf, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
s += 1;
|
||||
if (*s != '(')
|
||||
goto err;
|
||||
|
||||
s = strchr(s, ')');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 1; i <= 22; i++) {
|
||||
s = strchr(s + 1, ' ');
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = strtol(s, NULL, 10);
|
||||
if (errno != 0)
|
||||
goto err;
|
||||
if (val < 0)
|
||||
goto err;
|
||||
|
||||
*rss = val * getpagesize();
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
static volatile int no_clock_boottime;
|
||||
struct timespec now;
|
||||
int r;
|
||||
|
||||
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
|
||||
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
|
||||
* is suspended.
|
||||
*/
|
||||
if (no_clock_boottime) {
|
||||
retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
}
|
||||
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
|
||||
no_clock_boottime = 1;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (r)
|
||||
return -errno;
|
||||
|
||||
*uptime = now.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
|
||||
unsigned int num;
|
||||
char buf[1024];
|
||||
|
||||
if (!fgets(buf, sizeof(buf), statfile_fp))
|
||||
return -EIO;
|
||||
|
||||
num = 0;
|
||||
while (fgets(buf, sizeof(buf), statfile_fp)) {
|
||||
if (strncmp(buf, "cpu", 3))
|
||||
break;
|
||||
num++;
|
||||
}
|
||||
|
||||
if (num == 0)
|
||||
return -EIO;
|
||||
|
||||
*numcpus = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int numcpus;
|
||||
uv_cpu_info_t* ci;
|
||||
int err;
|
||||
FILE* statfile_fp;
|
||||
|
||||
*cpu_infos = NULL;
|
||||
*count = 0;
|
||||
|
||||
statfile_fp = uv__open_file("/proc/stat");
|
||||
if (statfile_fp == NULL)
|
||||
return -errno;
|
||||
|
||||
err = uv__cpu_num(statfile_fp, &numcpus);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = -ENOMEM;
|
||||
ci = uv__calloc(numcpus, sizeof(*ci));
|
||||
if (ci == NULL)
|
||||
goto out;
|
||||
|
||||
err = read_models(numcpus, ci);
|
||||
if (err == 0)
|
||||
err = read_times(statfile_fp, numcpus, ci);
|
||||
|
||||
if (err) {
|
||||
uv_free_cpu_info(ci, numcpus);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
|
||||
* We don't check for errors here. Worst case, the field is left zero.
|
||||
*/
|
||||
if (ci[0].speed == 0)
|
||||
read_speeds(numcpus, ci);
|
||||
|
||||
*cpu_infos = ci;
|
||||
*count = numcpus;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
|
||||
if (fclose(statfile_fp))
|
||||
if (errno != EINTR && errno != EINPROGRESS)
|
||||
abort();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
unsigned int num;
|
||||
|
||||
for (num = 0; num < numcpus; num++)
|
||||
ci[num].speed = read_cpufreq(num) / 1000;
|
||||
}
|
||||
|
||||
|
||||
/* Also reads the CPU frequency on x86. The other architectures only have
|
||||
* a BogoMIPS field, which may not be very accurate.
|
||||
*
|
||||
* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
|
||||
*/
|
||||
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
static const char model_marker[] = "model name\t: ";
|
||||
static const char speed_marker[] = "cpu MHz\t\t: ";
|
||||
const char* inferred_model;
|
||||
unsigned int model_idx;
|
||||
unsigned int speed_idx;
|
||||
char buf[1024];
|
||||
char* model;
|
||||
FILE* fp;
|
||||
|
||||
/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
|
||||
(void) &model_marker;
|
||||
(void) &speed_marker;
|
||||
(void) &speed_idx;
|
||||
(void) &model;
|
||||
(void) &buf;
|
||||
(void) &fp;
|
||||
|
||||
model_idx = 0;
|
||||
speed_idx = 0;
|
||||
|
||||
#if defined(__arm__) || \
|
||||
defined(__i386__) || \
|
||||
defined(__mips__) || \
|
||||
defined(__x86_64__)
|
||||
fp = uv__open_file("/proc/cpuinfo");
|
||||
if (fp == NULL)
|
||||
return -errno;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp)) {
|
||||
if (model_idx < numcpus) {
|
||||
if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
|
||||
model = buf + sizeof(model_marker) - 1;
|
||||
model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
|
||||
if (model == NULL) {
|
||||
fclose(fp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ci[model_idx++].model = model;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#if defined(__arm__) || defined(__mips__)
|
||||
if (model_idx < numcpus) {
|
||||
#if defined(__arm__)
|
||||
/* Fallback for pre-3.8 kernels. */
|
||||
static const char model_marker[] = "Processor\t: ";
|
||||
#else /* defined(__mips__) */
|
||||
static const char model_marker[] = "cpu model\t\t: ";
|
||||
#endif
|
||||
if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
|
||||
model = buf + sizeof(model_marker) - 1;
|
||||
model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
|
||||
if (model == NULL) {
|
||||
fclose(fp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ci[model_idx++].model = model;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else /* !__arm__ && !__mips__ */
|
||||
if (speed_idx < numcpus) {
|
||||
if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
|
||||
ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif /* __arm__ || __mips__ */
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
|
||||
|
||||
/* Now we want to make sure that all the models contain *something* because
|
||||
* it's not safe to leave them as null. Copy the last entry unless there
|
||||
* isn't one, in that case we simply put "unknown" into everything.
|
||||
*/
|
||||
inferred_model = "unknown";
|
||||
if (model_idx > 0)
|
||||
inferred_model = ci[model_idx - 1].model;
|
||||
|
||||
while (model_idx < numcpus) {
|
||||
model = uv__strndup(inferred_model, strlen(inferred_model));
|
||||
if (model == NULL)
|
||||
return -ENOMEM;
|
||||
ci[model_idx++].model = model;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int read_times(FILE* statfile_fp,
|
||||
unsigned int numcpus,
|
||||
uv_cpu_info_t* ci) {
|
||||
unsigned long clock_ticks;
|
||||
struct uv_cpu_times_s ts;
|
||||
unsigned long user;
|
||||
unsigned long nice;
|
||||
unsigned long sys;
|
||||
unsigned long idle;
|
||||
unsigned long dummy;
|
||||
unsigned long irq;
|
||||
unsigned int num;
|
||||
unsigned int len;
|
||||
char buf[1024];
|
||||
|
||||
clock_ticks = sysconf(_SC_CLK_TCK);
|
||||
assert(clock_ticks != (unsigned long) -1);
|
||||
assert(clock_ticks != 0);
|
||||
|
||||
rewind(statfile_fp);
|
||||
|
||||
if (!fgets(buf, sizeof(buf), statfile_fp))
|
||||
abort();
|
||||
|
||||
num = 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), statfile_fp)) {
|
||||
if (num >= numcpus)
|
||||
break;
|
||||
|
||||
if (strncmp(buf, "cpu", 3))
|
||||
break;
|
||||
|
||||
/* skip "cpu<num> " marker */
|
||||
{
|
||||
unsigned int n;
|
||||
int r = sscanf(buf, "cpu%u ", &n);
|
||||
assert(r == 1);
|
||||
(void) r; /* silence build warning */
|
||||
for (len = sizeof("cpu0"); n /= 10; len++);
|
||||
}
|
||||
|
||||
/* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
|
||||
* guest, guest_nice but we're only interested in the first four + irq.
|
||||
*
|
||||
* Don't use %*s to skip fields or %ll to read straight into the uint64_t
|
||||
* fields, they're not allowed in C89 mode.
|
||||
*/
|
||||
if (6 != sscanf(buf + len,
|
||||
"%lu %lu %lu %lu %lu %lu",
|
||||
&user,
|
||||
&nice,
|
||||
&sys,
|
||||
&idle,
|
||||
&dummy,
|
||||
&irq))
|
||||
abort();
|
||||
|
||||
ts.user = clock_ticks * user;
|
||||
ts.nice = clock_ticks * nice;
|
||||
ts.sys = clock_ticks * sys;
|
||||
ts.idle = clock_ticks * idle;
|
||||
ts.irq = clock_ticks * irq;
|
||||
ci[num++].cpu_times = ts;
|
||||
}
|
||||
assert(num == numcpus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long read_cpufreq(unsigned int cpunum) {
|
||||
unsigned long val;
|
||||
char buf[1024];
|
||||
FILE* fp;
|
||||
|
||||
snprintf(buf,
|
||||
sizeof(buf),
|
||||
"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
|
||||
cpunum);
|
||||
|
||||
fp = uv__open_file(buf);
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
if (fscanf(fp, "%lu", &val) != 1)
|
||||
val = 0;
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
#ifndef HAVE_IFADDRS_H
|
||||
return -ENOSYS;
|
||||
#else
|
||||
struct ifaddrs *addrs, *ent;
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
struct sockaddr_ll *sll;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family == PF_PACKET)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0)
|
||||
return 0;
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* On Linux getifaddrs returns information related to the raw underlying
|
||||
* devices. We're not interested in this information yet.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == PF_PACKET)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != PF_PACKET)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sll = (struct sockaddr_ll*)ent->ifa_addr;
|
||||
memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
||||
void uv__set_process_title(const char* title) {
|
||||
#if defined(PR_SET_NAME)
|
||||
prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
|
||||
#endif
|
||||
}
|
||||
285
Utilities/cmlibuv/src/unix/linux-inotify.c
Normal file
285
Utilities/cmlibuv/src/unix/linux-inotify.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct watcher_list {
|
||||
RB_ENTRY(watcher_list) entry;
|
||||
QUEUE watchers;
|
||||
int iterating;
|
||||
char* path;
|
||||
int wd;
|
||||
};
|
||||
|
||||
struct watcher_root {
|
||||
struct watcher_list* rbh_root;
|
||||
};
|
||||
#define CAST(p) ((struct watcher_root*)(p))
|
||||
|
||||
|
||||
static int compare_watchers(const struct watcher_list* a,
|
||||
const struct watcher_list* b) {
|
||||
if (a->wd < b->wd) return -1;
|
||||
if (a->wd > b->wd) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
|
||||
|
||||
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int revents);
|
||||
|
||||
|
||||
static int new_inotify_fd(void) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
fd = uv__inotify_init();
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(fd, 1);
|
||||
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static int init_inotify(uv_loop_t* loop) {
|
||||
int err;
|
||||
|
||||
if (loop->inotify_fd != -1)
|
||||
return 0;
|
||||
|
||||
err = new_inotify_fd();
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
loop->inotify_fd = err;
|
||||
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
|
||||
uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
|
||||
struct watcher_list w;
|
||||
w.wd = wd;
|
||||
return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
|
||||
}
|
||||
|
||||
static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
/* if the watcher_list->watchers is being iterated over, we can't free it. */
|
||||
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
|
||||
/* No watchers left for this path. Clean up. */
|
||||
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
|
||||
uv__inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
uv__free(w);
|
||||
}
|
||||
}
|
||||
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* dummy,
|
||||
unsigned int events) {
|
||||
const struct uv__inotify_event* e;
|
||||
struct watcher_list* w;
|
||||
uv_fs_event_t* h;
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
const char* path;
|
||||
ssize_t size;
|
||||
const char *p;
|
||||
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
|
||||
char buf[4096];
|
||||
|
||||
while (1) {
|
||||
do
|
||||
size = read(loop->inotify_fd, buf, sizeof(buf));
|
||||
while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1) {
|
||||
assert(errno == EAGAIN || errno == EWOULDBLOCK);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
|
||||
|
||||
/* Now we have one or more inotify_event structs. */
|
||||
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
|
||||
e = (const struct uv__inotify_event*)p;
|
||||
|
||||
events = 0;
|
||||
if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
events |= UV_CHANGE;
|
||||
if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
events |= UV_RENAME;
|
||||
|
||||
w = find_watcher(loop, e->wd);
|
||||
if (w == NULL)
|
||||
continue; /* Stale event, no watchers left. */
|
||||
|
||||
/* inotify does not return the filename when monitoring a single file
|
||||
* for modifications. Repurpose the filename for API compatibility.
|
||||
* I'm not convinced this is a good thing, maybe it should go.
|
||||
*/
|
||||
path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
|
||||
|
||||
/* We're about to iterate over the queue and call user's callbacks.
|
||||
* What can go wrong?
|
||||
* A callback could call uv_fs_event_stop()
|
||||
* and the queue can change under our feet.
|
||||
* So, we use QUEUE_MOVE() trick to safely iterate over the queue.
|
||||
* And we don't free the watcher_list until we're done iterating.
|
||||
*
|
||||
* First,
|
||||
* tell uv_fs_event_stop() (that could be called from a user's callback)
|
||||
* not to free watcher_list.
|
||||
*/
|
||||
w->iterating = 1;
|
||||
QUEUE_MOVE(&w->watchers, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_fs_event_t, watchers);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&w->watchers, q);
|
||||
|
||||
h->cb(h, path, events, 0);
|
||||
}
|
||||
/* done iterating, time to (maybe) free empty watcher_list */
|
||||
w->iterating = 0;
|
||||
maybe_free_watcher_list(w, loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
struct watcher_list* w;
|
||||
int events;
|
||||
int err;
|
||||
int wd;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return -EINVAL;
|
||||
|
||||
err = init_inotify(handle->loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
events = UV__IN_ATTRIB
|
||||
| UV__IN_CREATE
|
||||
| UV__IN_MODIFY
|
||||
| UV__IN_DELETE
|
||||
| UV__IN_DELETE_SELF
|
||||
| UV__IN_MOVE_SELF
|
||||
| UV__IN_MOVED_FROM
|
||||
| UV__IN_MOVED_TO;
|
||||
|
||||
wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
if (wd == -1)
|
||||
return -errno;
|
||||
|
||||
w = find_watcher(handle->loop, wd);
|
||||
if (w)
|
||||
goto no_insert;
|
||||
|
||||
w = uv__malloc(sizeof(*w) + strlen(path) + 1);
|
||||
if (w == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
w->wd = wd;
|
||||
w->path = strcpy((char*)(w + 1), path);
|
||||
QUEUE_INIT(&w->watchers);
|
||||
w->iterating = 0;
|
||||
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
|
||||
|
||||
no_insert:
|
||||
uv__handle_start(handle);
|
||||
QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
|
||||
handle->path = w->path;
|
||||
handle->cb = cb;
|
||||
handle->wd = wd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
struct watcher_list* w;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
w = find_watcher(handle->loop, handle->wd);
|
||||
assert(w != NULL);
|
||||
|
||||
handle->wd = -1;
|
||||
handle->path = NULL;
|
||||
uv__handle_stop(handle);
|
||||
QUEUE_REMOVE(&handle->watchers);
|
||||
|
||||
maybe_free_watcher_list(w, handle->loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
471
Utilities/cmlibuv/src/unix/linux-syscalls.c
Normal file
471
Utilities/cmlibuv/src/unix/linux-syscalls.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "linux-syscalls.h"
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# define MSAN_ACTIVE 1
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
# ifndef __NR_socketcall
|
||||
# define __NR_socketcall 102
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)
|
||||
# if defined(__thumb__) || defined(__ARM_EABI__)
|
||||
# define UV_SYSCALL_BASE 0
|
||||
# else
|
||||
# define UV_SYSCALL_BASE 0x900000
|
||||
# endif
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifndef __NR_accept4
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_accept4 288
|
||||
# elif defined(__i386__)
|
||||
/* Nothing. Handled through socketcall(). */
|
||||
# elif defined(__arm__)
|
||||
# define __NR_accept4 (UV_SYSCALL_BASE + 366)
|
||||
# endif
|
||||
#endif /* __NR_accept4 */
|
||||
|
||||
#ifndef __NR_eventfd
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd 284
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd 323
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd (UV_SYSCALL_BASE + 351)
|
||||
# endif
|
||||
#endif /* __NR_eventfd */
|
||||
|
||||
#ifndef __NR_eventfd2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd2 290
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd2 328
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
|
||||
# endif
|
||||
#endif /* __NR_eventfd2 */
|
||||
|
||||
#ifndef __NR_epoll_create
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create 213
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create 254
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create */
|
||||
|
||||
#ifndef __NR_epoll_create1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create1 291
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create1 329
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create1 */
|
||||
|
||||
#ifndef __NR_epoll_ctl
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_ctl 233 /* used to be 214 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_ctl 255
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
|
||||
# endif
|
||||
#endif /* __NR_epoll_ctl */
|
||||
|
||||
#ifndef __NR_epoll_wait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_wait 232 /* used to be 215 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_wait 256
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
|
||||
# endif
|
||||
#endif /* __NR_epoll_wait */
|
||||
|
||||
#ifndef __NR_epoll_pwait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_pwait 281
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_pwait 319
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
|
||||
# endif
|
||||
#endif /* __NR_epoll_pwait */
|
||||
|
||||
#ifndef __NR_inotify_init
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init 253
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init 291
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init */
|
||||
|
||||
#ifndef __NR_inotify_init1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init1 294
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init1 332
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init1 */
|
||||
|
||||
#ifndef __NR_inotify_add_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_add_watch 254
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_add_watch 292
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
|
||||
# endif
|
||||
#endif /* __NR_inotify_add_watch */
|
||||
|
||||
#ifndef __NR_inotify_rm_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_rm_watch 255
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_rm_watch 293
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
|
||||
# endif
|
||||
#endif /* __NR_inotify_rm_watch */
|
||||
|
||||
#ifndef __NR_pipe2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_pipe2 293
|
||||
# elif defined(__i386__)
|
||||
# define __NR_pipe2 331
|
||||
# elif defined(__arm__)
|
||||
# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
|
||||
# endif
|
||||
#endif /* __NR_pipe2 */
|
||||
|
||||
#ifndef __NR_recvmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_recvmmsg 299
|
||||
# elif defined(__i386__)
|
||||
# define __NR_recvmmsg 337
|
||||
# elif defined(__arm__)
|
||||
# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
|
||||
# endif
|
||||
#endif /* __NR_recvmsg */
|
||||
|
||||
#ifndef __NR_sendmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_sendmmsg 307
|
||||
# elif defined(__i386__)
|
||||
# define __NR_sendmmsg 345
|
||||
# elif defined(__arm__)
|
||||
# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
|
||||
# endif
|
||||
#endif /* __NR_sendmmsg */
|
||||
|
||||
#ifndef __NR_utimensat
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_utimensat 280
|
||||
# elif defined(__i386__)
|
||||
# define __NR_utimensat 320
|
||||
# elif defined(__arm__)
|
||||
# define __NR_utimensat (UV_SYSCALL_BASE + 348)
|
||||
# endif
|
||||
#endif /* __NR_utimensat */
|
||||
|
||||
#ifndef __NR_preadv
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_preadv 295
|
||||
# elif defined(__i386__)
|
||||
# define __NR_preadv 333
|
||||
# elif defined(__arm__)
|
||||
# define __NR_preadv (UV_SYSCALL_BASE + 361)
|
||||
# endif
|
||||
#endif /* __NR_preadv */
|
||||
|
||||
#ifndef __NR_pwritev
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_pwritev 296
|
||||
# elif defined(__i386__)
|
||||
# define __NR_pwritev 334
|
||||
# elif defined(__arm__)
|
||||
# define __NR_pwritev (UV_SYSCALL_BASE + 362)
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
#ifndef __NR_dup3
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_dup3 292
|
||||
# elif defined(__i386__)
|
||||
# define __NR_dup3 330
|
||||
# elif defined(__arm__)
|
||||
# define __NR_dup3 (UV_SYSCALL_BASE + 358)
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
|
||||
#if defined(__i386__)
|
||||
unsigned long args[4];
|
||||
int r;
|
||||
|
||||
args[0] = (unsigned long) fd;
|
||||
args[1] = (unsigned long) addr;
|
||||
args[2] = (unsigned long) addrlen;
|
||||
args[3] = (unsigned long) flags;
|
||||
|
||||
r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
|
||||
|
||||
/* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
|
||||
* a bad flags argument. Try to distinguish between the two cases.
|
||||
*/
|
||||
if (r == -1)
|
||||
if (errno == EINVAL)
|
||||
if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
|
||||
errno = ENOSYS;
|
||||
|
||||
return r;
|
||||
#elif defined(__NR_accept4)
|
||||
return syscall(__NR_accept4, fd, addr, addrlen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__eventfd(unsigned int count) {
|
||||
#if defined(__NR_eventfd)
|
||||
return syscall(__NR_eventfd, count);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__eventfd2(unsigned int count, int flags) {
|
||||
#if defined(__NR_eventfd2)
|
||||
return syscall(__NR_eventfd2, count, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create(int size) {
|
||||
#if defined(__NR_epoll_create)
|
||||
return syscall(__NR_epoll_create, size);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create1(int flags) {
|
||||
#if defined(__NR_epoll_create1)
|
||||
return syscall(__NR_epoll_create1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
|
||||
#if defined(__NR_epoll_ctl)
|
||||
return syscall(__NR_epoll_ctl, epfd, op, fd, events);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout) {
|
||||
#if defined(__NR_epoll_wait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask) {
|
||||
#if defined(__NR_epoll_pwait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_pwait,
|
||||
epfd,
|
||||
events,
|
||||
nevents,
|
||||
timeout,
|
||||
&sigmask,
|
||||
sizeof(sigmask));
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init(void) {
|
||||
#if defined(__NR_inotify_init)
|
||||
return syscall(__NR_inotify_init);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init1(int flags) {
|
||||
#if defined(__NR_inotify_init1)
|
||||
return syscall(__NR_inotify_init1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
|
||||
#if defined(__NR_inotify_add_watch)
|
||||
return syscall(__NR_inotify_add_watch, fd, path, mask);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd) {
|
||||
#if defined(__NR_inotify_rm_watch)
|
||||
return syscall(__NR_inotify_rm_watch, fd, wd);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__pipe2(int pipefd[2], int flags) {
|
||||
#if defined(__NR_pipe2)
|
||||
int result;
|
||||
result = syscall(__NR_pipe2, pipefd, flags);
|
||||
#if MSAN_ACTIVE
|
||||
if (!result)
|
||||
__msan_unpoison(pipefd, sizeof(int[2]));
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags) {
|
||||
#if defined(__NR_sendmmsg)
|
||||
return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout) {
|
||||
#if defined(__NR_recvmmsg)
|
||||
return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags)
|
||||
{
|
||||
#if defined(__NR_utimensat)
|
||||
return syscall(__NR_utimensat, dirfd, path, times, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_preadv)
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_pwritev)
|
||||
return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__dup3(int oldfd, int newfd, int flags) {
|
||||
#if defined(__NR_dup3)
|
||||
return syscall(__NR_dup3, oldfd, newfd, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
151
Utilities/cmlibuv/src/unix/linux-syscalls.h
Normal file
151
Utilities/cmlibuv/src/unix/linux-syscalls.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_LINUX_SYSCALL_H_
|
||||
#define UV_LINUX_SYSCALL_H_
|
||||
|
||||
#undef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_CLOEXEC 0x400000
|
||||
#else
|
||||
# define UV__O_CLOEXEC 0x80000
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_NONBLOCK 0x4
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_NONBLOCK O_NONBLOCK
|
||||
#elif defined(__mips__)
|
||||
# define UV__O_NONBLOCK 0x80
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_NONBLOCK 0x4000
|
||||
#else
|
||||
# define UV__O_NONBLOCK 0x800
|
||||
#endif
|
||||
|
||||
#define UV__EFD_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EFD_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__IN_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__IN_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
|
||||
#if defined(SOCK_NONBLOCK)
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
#else
|
||||
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/* epoll flags */
|
||||
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EPOLL_CTL_ADD 1
|
||||
#define UV__EPOLL_CTL_DEL 2
|
||||
#define UV__EPOLL_CTL_MOD 3
|
||||
|
||||
/* inotify flags */
|
||||
#define UV__IN_ACCESS 0x001
|
||||
#define UV__IN_MODIFY 0x002
|
||||
#define UV__IN_ATTRIB 0x004
|
||||
#define UV__IN_CLOSE_WRITE 0x008
|
||||
#define UV__IN_CLOSE_NOWRITE 0x010
|
||||
#define UV__IN_OPEN 0x020
|
||||
#define UV__IN_MOVED_FROM 0x040
|
||||
#define UV__IN_MOVED_TO 0x080
|
||||
#define UV__IN_CREATE 0x100
|
||||
#define UV__IN_DELETE 0x200
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
#if defined(__x86_64__)
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
uint32_t mask;
|
||||
uint32_t cookie;
|
||||
uint32_t len;
|
||||
/* char name[0]; */
|
||||
};
|
||||
|
||||
struct uv__mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
|
||||
int uv__eventfd(unsigned int count);
|
||||
int uv__epoll_create(int size);
|
||||
int uv__epoll_create1(int flags);
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout);
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask);
|
||||
int uv__eventfd2(unsigned int count, int flags);
|
||||
int uv__inotify_init(void);
|
||||
int uv__inotify_init1(int flags);
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd);
|
||||
int uv__pipe2(int pipefd[2], int flags);
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout);
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags);
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags);
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
int uv__dup3(int oldfd, int newfd, int flags);
|
||||
|
||||
#endif /* UV_LINUX_SYSCALL_H_ */
|
||||
68
Utilities/cmlibuv/src/unix/loop-watcher.c
Normal file
68
Utilities/cmlibuv/src/unix/loop-watcher.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define UV_LOOP_WATCHER_DEFINE(name, type) \
|
||||
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
|
||||
handle->name##_cb = NULL; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
|
||||
if (uv__is_active(handle)) return 0; \
|
||||
if (cb == NULL) return -EINVAL; \
|
||||
QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
|
||||
handle->name##_cb = cb; \
|
||||
uv__handle_start(handle); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int uv_##name##_stop(uv_##name##_t* handle) { \
|
||||
if (!uv__is_active(handle)) return 0; \
|
||||
QUEUE_REMOVE(&handle->queue); \
|
||||
uv__handle_stop(handle); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
void uv__run_##name(uv_loop_t* loop) { \
|
||||
uv_##name##_t* h; \
|
||||
QUEUE queue; \
|
||||
QUEUE* q; \
|
||||
QUEUE_MOVE(&loop->name##_handles, &queue); \
|
||||
while (!QUEUE_EMPTY(&queue)) { \
|
||||
q = QUEUE_HEAD(&queue); \
|
||||
h = QUEUE_DATA(q, uv_##name##_t, queue); \
|
||||
QUEUE_REMOVE(q); \
|
||||
QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
|
||||
h->name##_cb(h); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void uv__##name##_close(uv_##name##_t* handle) { \
|
||||
uv_##name##_stop(handle); \
|
||||
}
|
||||
|
||||
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
|
||||
UV_LOOP_WATCHER_DEFINE(check, CHECK)
|
||||
UV_LOOP_WATCHER_DEFINE(idle, IDLE)
|
||||
159
Utilities/cmlibuv/src/unix/loop.c
Normal file
159
Utilities/cmlibuv/src/unix/loop.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "internal.h"
|
||||
#include "heap-inl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
void* saved_data;
|
||||
int err;
|
||||
|
||||
uv__signal_global_once_init();
|
||||
|
||||
saved_data = loop->data;
|
||||
memset(loop, 0, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
|
||||
heap_init((struct heap*) &loop->timer_heap);
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->active_reqs);
|
||||
QUEUE_INIT(&loop->idle_handles);
|
||||
QUEUE_INIT(&loop->async_handles);
|
||||
QUEUE_INIT(&loop->check_handles);
|
||||
QUEUE_INIT(&loop->prepare_handles);
|
||||
QUEUE_INIT(&loop->handle_queue);
|
||||
|
||||
loop->nfds = 0;
|
||||
loop->watchers = NULL;
|
||||
loop->nwatchers = 0;
|
||||
QUEUE_INIT(&loop->pending_queue);
|
||||
QUEUE_INIT(&loop->watcher_queue);
|
||||
|
||||
loop->closing_handles = NULL;
|
||||
uv__update_time(loop);
|
||||
uv__async_init(&loop->async_watcher);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
loop->signal_pipefd[1] = -1;
|
||||
loop->backend_fd = -1;
|
||||
loop->emfile_fd = -1;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
loop->stop_flag = 0;
|
||||
|
||||
err = uv__platform_loop_init(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv_signal_init(loop, &loop->child_watcher);
|
||||
if (err)
|
||||
goto fail_signal_init;
|
||||
|
||||
uv__handle_unref(&loop->child_watcher);
|
||||
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
|
||||
QUEUE_INIT(&loop->process_handles);
|
||||
|
||||
err = uv_rwlock_init(&loop->cloexec_lock);
|
||||
if (err)
|
||||
goto fail_rwlock_init;
|
||||
|
||||
err = uv_mutex_init(&loop->wq_mutex);
|
||||
if (err)
|
||||
goto fail_mutex_init;
|
||||
|
||||
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv_rwlock_destroy(&loop->cloexec_lock);
|
||||
|
||||
fail_rwlock_init:
|
||||
uv__signal_loop_cleanup(loop);
|
||||
|
||||
fail_signal_init:
|
||||
uv__platform_loop_delete(loop);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
uv__signal_loop_cleanup(loop);
|
||||
uv__platform_loop_delete(loop);
|
||||
uv__async_stop(loop, &loop->async_watcher);
|
||||
|
||||
if (loop->emfile_fd != -1) {
|
||||
uv__close(loop->emfile_fd);
|
||||
loop->emfile_fd = -1;
|
||||
}
|
||||
|
||||
if (loop->backend_fd != -1) {
|
||||
uv__close(loop->backend_fd);
|
||||
loop->backend_fd = -1;
|
||||
}
|
||||
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(!uv__has_active_reqs(loop));
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
/*
|
||||
* Note that all thread pool stuff is finished at this point and
|
||||
* it is safe to just destroy rw lock
|
||||
*/
|
||||
uv_rwlock_destroy(&loop->cloexec_lock);
|
||||
|
||||
#if 0
|
||||
assert(QUEUE_EMPTY(&loop->pending_queue));
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
assert(loop->nfds == 0);
|
||||
#endif
|
||||
|
||||
uv__free(loop->watchers);
|
||||
loop->watchers = NULL;
|
||||
loop->nwatchers = 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
|
||||
if (option != UV_LOOP_BLOCK_SIGNAL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
if (va_arg(ap, int) != SIGPROF)
|
||||
return UV_EINVAL;
|
||||
|
||||
loop->flags |= UV_LOOP_BLOCK_SIGPROF;
|
||||
return 0;
|
||||
}
|
||||
380
Utilities/cmlibuv/src/unix/netbsd.c
Normal file
380
Utilities/cmlibuv/src/unix/netbsd.c
Normal file
@@ -0,0 +1,380 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <kvm.h>
|
||||
#include <paths.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
static char *process_title;
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int mib[4];
|
||||
size_t cb;
|
||||
pid_t mypid;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mypid = getpid();
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = mypid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
|
||||
cb = *size;
|
||||
if (sysctl(mib, 4, buffer, &cb, NULL, 0))
|
||||
return -errno;
|
||||
*size = strlen(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct uvmexp info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
#if defined(HW_PHYSMEM64)
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
#else
|
||||
unsigned int info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM};
|
||||
#endif
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
if (process_title) uv__free(process_title);
|
||||
|
||||
process_title = uv__strdup(title);
|
||||
setproctitle("%s", title);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
kvm_t *kd = NULL;
|
||||
struct kinfo_proc2 *kinfo = NULL;
|
||||
pid_t pid;
|
||||
int nprocs;
|
||||
int max_size = sizeof(struct kinfo_proc2);
|
||||
int page_size;
|
||||
|
||||
page_size = getpagesize();
|
||||
pid = getpid();
|
||||
|
||||
kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
|
||||
|
||||
if (kd == NULL) goto error;
|
||||
|
||||
kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
|
||||
if (kinfo == NULL) goto error;
|
||||
|
||||
*rss = kinfo->p_vm_rssize * page_size;
|
||||
|
||||
kvm_close(kd);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (kd) kvm_close(kd);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
*uptime = (double)(now - info.tv_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
|
||||
unsigned int multiplier = ((uint64_t)1000L / ticks);
|
||||
unsigned int cur = 0;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
u_int64_t* cp_times;
|
||||
char model[512];
|
||||
u_int64_t cpuspeed;
|
||||
int numcpus;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
|
||||
sysctlbyname("hw.model", &model, &size, NULL, 0)) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
size = sizeof(numcpus);
|
||||
if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
|
||||
return -errno;
|
||||
*count = numcpus;
|
||||
|
||||
/* Only i386 and amd64 have machdep.tsc_freq */
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
|
||||
cpuspeed = 0;
|
||||
|
||||
size = numcpus * CPUSTATES * sizeof(*cp_times);
|
||||
cp_times = uv__malloc(size);
|
||||
if (cp_times == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
uv__free(cp_times);
|
||||
uv__free(*cpu_infos);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
|
||||
cur += CPUSTATES;
|
||||
}
|
||||
uv__free(cp_times);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs *addrs, *ent;
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
struct sockaddr_dl *sa_addr;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != PF_INET)) {
|
||||
continue;
|
||||
}
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr->sa_family != PF_INET)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
396
Utilities/cmlibuv/src/unix/openbsd.c
Normal file
396
Utilities/cmlibuv/src/unix/openbsd.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <paths.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
|
||||
static char *process_title;
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
avg[2] = (double) info.ldavg[2] / info.fscale;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int mib[4];
|
||||
char **argsbuf = NULL;
|
||||
char **argsbuf_tmp;
|
||||
size_t argsbuf_size = 100U;
|
||||
size_t exepath_size;
|
||||
pid_t mypid;
|
||||
int err;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mypid = getpid();
|
||||
for (;;) {
|
||||
err = -ENOMEM;
|
||||
argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
|
||||
if (argsbuf_tmp == NULL)
|
||||
goto out;
|
||||
argsbuf = argsbuf_tmp;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = mypid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
break;
|
||||
}
|
||||
if (errno != ENOMEM) {
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
argsbuf_size *= 2U;
|
||||
}
|
||||
|
||||
if (argsbuf[0] == NULL) {
|
||||
err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
*size -= 1;
|
||||
exepath_size = strlen(argsbuf[0]);
|
||||
if (*size > exepath_size)
|
||||
*size = exepath_size;
|
||||
|
||||
memcpy(buffer, argsbuf[0], *size);
|
||||
buffer[*size] = '\0';
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
uv__free(argsbuf);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct uvmexp info;
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
uint64_t info;
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
return (uint64_t) info;
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
uv__free(process_title);
|
||||
process_title = uv__strdup(title);
|
||||
setproctitle(title);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size = getpagesize();
|
||||
size_t size = sizeof(struct kinfo_proc);
|
||||
int mib[6];
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
mib[4] = sizeof(struct kinfo_proc);
|
||||
mib[5] = 1;
|
||||
|
||||
if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
|
||||
return -errno;
|
||||
|
||||
*rss = kinfo.p_vm_rssize * page_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
time_t now;
|
||||
struct timeval info;
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
*uptime = (double)(now - info.tv_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
|
||||
multiplier = ((uint64_t)1000L / ticks), cpuspeed;
|
||||
uint64_t info[CPUSTATES];
|
||||
char model[512];
|
||||
int numcpus = 1;
|
||||
int which[] = {CTL_HW,HW_MODEL,0};
|
||||
size_t size;
|
||||
int i;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctl(which, 2, &model, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
which[1] = HW_NCPU;
|
||||
size = sizeof(numcpus);
|
||||
if (sysctl(which, 2, &numcpus, &size, NULL, 0))
|
||||
return -errno;
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos))
|
||||
return -ENOMEM;
|
||||
|
||||
*count = numcpus;
|
||||
|
||||
which[1] = HW_CPUSPEED;
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
size = sizeof(info);
|
||||
which[0] = CTL_KERN;
|
||||
which[1] = KERN_CPTIME2;
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
which[2] = i;
|
||||
size = sizeof(info);
|
||||
if (sysctl(which, 3, &info, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
|
||||
cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
|
||||
cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
|
||||
cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
|
||||
cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
|
||||
|
||||
cpu_info->model = uv__strdup(model);
|
||||
cpu_info->speed = cpuspeed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
struct ifaddrs *addrs, *ent;
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
struct sockaddr_dl *sa_addr;
|
||||
|
||||
if (getifaddrs(&addrs) != 0)
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != PF_INET)) {
|
||||
continue;
|
||||
}
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr->sa_family != PF_INET)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family != AF_LINK)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
42
Utilities/cmlibuv/src/unix/os390.c
Normal file
42
Utilities/cmlibuv/src/unix/os390.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct pollfd p[1];
|
||||
int rv;
|
||||
|
||||
p[0].fd = fd;
|
||||
p[0].events = POLLIN;
|
||||
|
||||
do
|
||||
rv = poll(p, 1, 0);
|
||||
while (rv == -1 && errno == EINTR);
|
||||
|
||||
if (rv == -1)
|
||||
abort();
|
||||
|
||||
if (p[0].revents & POLLNVAL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
298
Utilities/cmlibuv/src/unix/pipe.c
Normal file
298
Utilities/cmlibuv/src/unix/pipe.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
||||
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
|
||||
handle->shutdown_req = NULL;
|
||||
handle->connect_req = NULL;
|
||||
handle->pipe_fname = NULL;
|
||||
handle->ipc = ipc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
struct sockaddr_un saddr;
|
||||
const char* pipe_fname;
|
||||
int sockfd;
|
||||
int err;
|
||||
|
||||
pipe_fname = NULL;
|
||||
sockfd = -1;
|
||||
|
||||
/* Already bound? */
|
||||
if (uv__stream_fd(handle) >= 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make a copy of the file name, it outlives this function's scope. */
|
||||
pipe_fname = uv__strdup(name);
|
||||
if (pipe_fname == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* We've got a copy, don't touch the original any more. */
|
||||
name = NULL;
|
||||
|
||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
goto err_socket;
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||
err = -errno;
|
||||
/* Convert ENOENT to EACCES for compatibility with Windows. */
|
||||
if (err == -ENOENT)
|
||||
err = -EACCES;
|
||||
goto err_bind;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
|
||||
handle->io_watcher.fd = sockfd;
|
||||
return 0;
|
||||
|
||||
err_bind:
|
||||
uv__close(sockfd);
|
||||
|
||||
err_socket:
|
||||
uv__free((void*)pipe_fname);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
if (uv__stream_fd(handle) == -1)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
/* On zOS, backlog=0 has undefined behaviour */
|
||||
if (backlog == 0)
|
||||
backlog = 1;
|
||||
else if (backlog < 0)
|
||||
backlog = SOMAXCONN;
|
||||
#endif
|
||||
|
||||
if (listen(uv__stream_fd(handle), backlog))
|
||||
return -errno;
|
||||
|
||||
handle->connection_cb = cb;
|
||||
handle->io_watcher.cb = uv__server_io;
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__pipe_close(uv_pipe_t* handle) {
|
||||
if (handle->pipe_fname) {
|
||||
/*
|
||||
* Unlink the file system entity before closing the file descriptor.
|
||||
* Doing it the other way around introduces a race where our process
|
||||
* unlinks a socket with the same name that's just been created by
|
||||
* another thread or process.
|
||||
*/
|
||||
unlink(handle->pipe_fname);
|
||||
uv__free((void*)handle->pipe_fname);
|
||||
handle->pipe_fname = NULL;
|
||||
}
|
||||
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
int err;
|
||||
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
err = uv__stream_try_select((uv_stream_t*) handle, &fd);
|
||||
if (err)
|
||||
return err;
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_connect(uv_connect_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const char* name,
|
||||
uv_connect_cb cb) {
|
||||
struct sockaddr_un saddr;
|
||||
int new_sock;
|
||||
int err;
|
||||
int r;
|
||||
|
||||
new_sock = (uv__stream_fd(handle) == -1);
|
||||
|
||||
if (new_sock) {
|
||||
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
handle->io_watcher.fd = err;
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
do {
|
||||
r = connect(uv__stream_fd(handle),
|
||||
(struct sockaddr*)&saddr, sizeof saddr);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1 && errno != EINPROGRESS) {
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
if (new_sock) {
|
||||
err = uv__stream_open((uv_stream_t*)handle,
|
||||
uv__stream_fd(handle),
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT);
|
||||
|
||||
out:
|
||||
handle->delayed_error = err;
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*)handle;
|
||||
req->cb = cb;
|
||||
QUEUE_INIT(&req->queue);
|
||||
|
||||
/* Force callback to run on next tick in case of error. */
|
||||
if (err)
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
}
|
||||
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
|
||||
|
||||
static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
uv__peersockfunc func,
|
||||
char* buffer,
|
||||
size_t* size) {
|
||||
struct sockaddr_un sa;
|
||||
socklen_t addrlen;
|
||||
int err;
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
memset(&sa, 0, addrlen);
|
||||
err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
|
||||
if (err < 0) {
|
||||
*size = 0;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (sa.sun_path[0] == 0)
|
||||
/* Linux abstract namespace */
|
||||
addrlen -= offsetof(struct sockaddr_un, sun_path);
|
||||
else
|
||||
#endif
|
||||
addrlen = strlen(sa.sun_path);
|
||||
|
||||
|
||||
if (addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, sa.sun_path, addrlen);
|
||||
*size = addrlen;
|
||||
|
||||
/* only null-terminate if it's not an abstract socket */
|
||||
if (buffer[0] != '\0')
|
||||
buffer[addrlen] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||
return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
||||
return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_pending_count(uv_pipe_t* handle) {
|
||||
uv__stream_queued_fds_t* queued_fds;
|
||||
|
||||
if (!handle->ipc)
|
||||
return 0;
|
||||
|
||||
if (handle->accepted_fd == -1)
|
||||
return 0;
|
||||
|
||||
if (handle->queued_fds == NULL)
|
||||
return 1;
|
||||
|
||||
queued_fds = handle->queued_fds;
|
||||
return queued_fds->offset + 1;
|
||||
}
|
||||
|
||||
|
||||
uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
||||
if (!handle->ipc)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (handle->accepted_fd == -1)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
else
|
||||
return uv__handle_type(handle->accepted_fd);
|
||||
}
|
||||
130
Utilities/cmlibuv/src/unix/poll.c
Normal file
130
Utilities/cmlibuv/src/unix/poll.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
uv_poll_t* handle;
|
||||
int pevents;
|
||||
|
||||
handle = container_of(w, uv_poll_t, io_watcher);
|
||||
|
||||
if (events & POLLERR) {
|
||||
uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
|
||||
uv__handle_stop(handle);
|
||||
handle->poll_cb(handle, -EBADF, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pevents = 0;
|
||||
if (events & POLLIN)
|
||||
pevents |= UV_READABLE;
|
||||
if (events & POLLOUT)
|
||||
pevents |= UV_WRITABLE;
|
||||
if (events & UV__POLLRDHUP)
|
||||
pevents |= UV_DISCONNECT;
|
||||
|
||||
handle->poll_cb(handle, 0, pevents);
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
int err;
|
||||
|
||||
err = uv__io_check_fd(loop, fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
|
||||
* Workaround for e.g. kqueue fds not supporting ioctls.
|
||||
*/
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err == -ENOTTY)
|
||||
if (uv__nonblock == uv__nonblock_ioctl)
|
||||
err = uv__nonblock_fcntl(fd, 1);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
|
||||
uv__io_init(&handle->io_watcher, uv__poll_io, fd);
|
||||
handle->poll_cb = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_os_sock_t socket) {
|
||||
return uv_poll_init(loop, handle, socket);
|
||||
}
|
||||
|
||||
|
||||
static void uv__poll_stop(uv_poll_t* handle) {
|
||||
uv__io_stop(handle->loop,
|
||||
&handle->io_watcher,
|
||||
POLLIN | POLLOUT | UV__POLLRDHUP);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_stop(uv_poll_t* handle) {
|
||||
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
|
||||
uv__poll_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
|
||||
int events;
|
||||
|
||||
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
|
||||
|
||||
uv__poll_stop(handle);
|
||||
|
||||
if (pevents == 0)
|
||||
return 0;
|
||||
|
||||
events = 0;
|
||||
if (pevents & UV_READABLE)
|
||||
events |= POLLIN;
|
||||
if (pevents & UV_WRITABLE)
|
||||
events |= POLLOUT;
|
||||
if (pevents & UV_DISCONNECT)
|
||||
events |= UV__POLLRDHUP;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, events);
|
||||
uv__handle_start(handle);
|
||||
handle->poll_cb = poll_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__poll_close(uv_poll_t* handle) {
|
||||
uv__poll_stop(handle);
|
||||
}
|
||||
563
Utilities/cmlibuv/src/unix/process.c
Normal file
563
Utilities/cmlibuv/src/unix/process.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
# include <grp.h>
|
||||
#endif
|
||||
|
||||
|
||||
static void uv__chld(uv_signal_t* handle, int signum) {
|
||||
uv_process_t* process;
|
||||
uv_loop_t* loop;
|
||||
int exit_status;
|
||||
int term_signal;
|
||||
int status;
|
||||
pid_t pid;
|
||||
QUEUE pending;
|
||||
QUEUE* q;
|
||||
QUEUE* h;
|
||||
|
||||
assert(signum == SIGCHLD);
|
||||
|
||||
QUEUE_INIT(&pending);
|
||||
loop = handle->loop;
|
||||
|
||||
h = &loop->process_handles;
|
||||
q = QUEUE_HEAD(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
|
||||
do
|
||||
pid = waitpid(process->pid, &status, WNOHANG);
|
||||
while (pid == -1 && errno == EINTR);
|
||||
|
||||
if (pid == 0)
|
||||
continue;
|
||||
|
||||
if (pid == -1) {
|
||||
if (errno != ECHILD)
|
||||
abort();
|
||||
continue;
|
||||
}
|
||||
|
||||
process->status = status;
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INSERT_TAIL(&pending, &process->queue);
|
||||
}
|
||||
|
||||
h = &pending;
|
||||
q = QUEUE_HEAD(h);
|
||||
while (q != h) {
|
||||
process = QUEUE_DATA(q, uv_process_t, queue);
|
||||
q = QUEUE_NEXT(q);
|
||||
|
||||
QUEUE_REMOVE(&process->queue);
|
||||
QUEUE_INIT(&process->queue);
|
||||
uv__handle_stop(process);
|
||||
|
||||
if (process->exit_cb == NULL)
|
||||
continue;
|
||||
|
||||
exit_status = 0;
|
||||
if (WIFEXITED(process->status))
|
||||
exit_status = WEXITSTATUS(process->status);
|
||||
|
||||
term_signal = 0;
|
||||
if (WIFSIGNALED(process->status))
|
||||
term_signal = WTERMSIG(process->status);
|
||||
|
||||
process->exit_cb(process, exit_status, term_signal);
|
||||
}
|
||||
assert(QUEUE_EMPTY(&pending));
|
||||
}
|
||||
|
||||
|
||||
int uv__make_socketpair(int fds[2], int flags) {
|
||||
#if defined(__linux__)
|
||||
static int no_cloexec;
|
||||
|
||||
if (no_cloexec)
|
||||
goto skip;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
|
||||
return 0;
|
||||
|
||||
/* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
|
||||
* Anything else is a genuine error.
|
||||
*/
|
||||
if (errno != EINVAL)
|
||||
return -errno;
|
||||
|
||||
no_cloexec = 1;
|
||||
|
||||
skip:
|
||||
#endif
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
|
||||
return -errno;
|
||||
|
||||
uv__cloexec(fds[0], 1);
|
||||
uv__cloexec(fds[1], 1);
|
||||
|
||||
if (flags & UV__F_NONBLOCK) {
|
||||
uv__nonblock(fds[0], 1);
|
||||
uv__nonblock(fds[1], 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__make_pipe(int fds[2], int flags) {
|
||||
#if defined(__linux__)
|
||||
static int no_pipe2;
|
||||
|
||||
if (no_pipe2)
|
||||
goto skip;
|
||||
|
||||
if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
|
||||
return 0;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return -errno;
|
||||
|
||||
no_pipe2 = 1;
|
||||
|
||||
skip:
|
||||
#endif
|
||||
|
||||
if (pipe(fds))
|
||||
return -errno;
|
||||
|
||||
uv__cloexec(fds[0], 1);
|
||||
uv__cloexec(fds[1], 1);
|
||||
|
||||
if (flags & UV__F_NONBLOCK) {
|
||||
uv__nonblock(fds[0], 1);
|
||||
uv__nonblock(fds[1], 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Used for initializing stdio streams like options.stdin_stream. Returns
|
||||
* zero on success. See also the cleanup section in uv_spawn().
|
||||
*/
|
||||
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||
int mask;
|
||||
int fd;
|
||||
|
||||
mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
|
||||
|
||||
switch (container->flags & mask) {
|
||||
case UV_IGNORE:
|
||||
return 0;
|
||||
|
||||
case UV_CREATE_PIPE:
|
||||
assert(container->data.stream != NULL);
|
||||
if (container->data.stream->type != UV_NAMED_PIPE)
|
||||
return -EINVAL;
|
||||
else
|
||||
return uv__make_socketpair(fds, 0);
|
||||
|
||||
case UV_INHERIT_FD:
|
||||
case UV_INHERIT_STREAM:
|
||||
if (container->flags & UV_INHERIT_FD)
|
||||
fd = container->data.fd;
|
||||
else
|
||||
fd = uv__stream_fd(container->data.stream);
|
||||
|
||||
if (fd == -1)
|
||||
return -EINVAL;
|
||||
|
||||
fds[1] = fd;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert(0 && "Unexpected flags");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__process_open_stream(uv_stdio_container_t* container,
|
||||
int pipefds[2],
|
||||
int writable) {
|
||||
int flags;
|
||||
int err;
|
||||
|
||||
if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
|
||||
return 0;
|
||||
|
||||
err = uv__close(pipefds[1]);
|
||||
if (err != 0)
|
||||
abort();
|
||||
|
||||
pipefds[1] = -1;
|
||||
uv__nonblock(pipefds[0], 1);
|
||||
|
||||
if (container->data.stream->type == UV_NAMED_PIPE &&
|
||||
((uv_pipe_t*)container->data.stream)->ipc)
|
||||
flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
|
||||
else if (writable)
|
||||
flags = UV_STREAM_WRITABLE;
|
||||
else
|
||||
flags = UV_STREAM_READABLE;
|
||||
|
||||
return uv__stream_open(container->data.stream, pipefds[0], flags);
|
||||
}
|
||||
|
||||
|
||||
static void uv__process_close_stream(uv_stdio_container_t* container) {
|
||||
if (!(container->flags & UV_CREATE_PIPE)) return;
|
||||
uv__stream_close((uv_stream_t*)container->data.stream);
|
||||
}
|
||||
|
||||
|
||||
static void uv__write_int(int fd, int val) {
|
||||
ssize_t n;
|
||||
|
||||
do
|
||||
n = write(fd, &val, sizeof(val));
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1 && errno == EPIPE)
|
||||
return; /* parent process has quit */
|
||||
|
||||
assert(n == sizeof(val));
|
||||
}
|
||||
|
||||
|
||||
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
||||
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
|
||||
* avoided. Since this isn't called on those targets, the function
|
||||
* doesn't even need to be defined for them.
|
||||
*/
|
||||
static void uv__process_child_init(const uv_process_options_t* options,
|
||||
int stdio_count,
|
||||
int (*pipes)[2],
|
||||
int error_fd) {
|
||||
int close_fd;
|
||||
int use_fd;
|
||||
int fd;
|
||||
|
||||
if (options->flags & UV_PROCESS_DETACHED)
|
||||
setsid();
|
||||
|
||||
/* First duplicate low numbered fds, since it's not safe to duplicate them,
|
||||
* they could get replaced. Example: swapping stdout and stderr; without
|
||||
* this fd 2 (stderr) would be duplicated into fd 1, thus making both
|
||||
* stdout and stderr go to the same fd, which was not the intention. */
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
use_fd = pipes[fd][1];
|
||||
if (use_fd < 0 || use_fd >= fd)
|
||||
continue;
|
||||
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
|
||||
if (pipes[fd][1] == -1) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
close_fd = pipes[fd][0];
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd < 0) {
|
||||
if (fd >= 3)
|
||||
continue;
|
||||
else {
|
||||
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
|
||||
* set
|
||||
*/
|
||||
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
|
||||
close_fd = use_fd;
|
||||
|
||||
if (use_fd == -1) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == use_fd)
|
||||
uv__cloexec(use_fd, 0);
|
||||
else
|
||||
fd = dup2(use_fd, fd);
|
||||
|
||||
if (fd == -1) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (fd <= 2)
|
||||
uv__nonblock(fd, 0);
|
||||
|
||||
if (close_fd >= stdio_count)
|
||||
uv__close(close_fd);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < stdio_count; fd++) {
|
||||
use_fd = pipes[fd][1];
|
||||
|
||||
if (use_fd >= stdio_count)
|
||||
uv__close(use_fd);
|
||||
}
|
||||
|
||||
if (options->cwd != NULL && chdir(options->cwd)) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
|
||||
/* When dropping privileges from root, the `setgroups` call will
|
||||
* remove any extraneous groups. If we don't call this, then
|
||||
* even though our uid has dropped, we may still have groups
|
||||
* that enable us to do super-user things. This will fail if we
|
||||
* aren't root, so don't bother checking the return value, this
|
||||
* is just done as an optimistic privilege dropping function.
|
||||
*/
|
||||
SAVE_ERRNO(setgroups(0, NULL));
|
||||
}
|
||||
|
||||
if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
if (options->env != NULL) {
|
||||
environ = options->env;
|
||||
}
|
||||
|
||||
execvp(options->file, options->args);
|
||||
uv__write_int(error_fd, -errno);
|
||||
_exit(127);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int uv_spawn(uv_loop_t* loop,
|
||||
uv_process_t* process,
|
||||
const uv_process_options_t* options) {
|
||||
#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
|
||||
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
|
||||
return -ENOSYS;
|
||||
#else
|
||||
int signal_pipe[2] = { -1, -1 };
|
||||
int (*pipes)[2];
|
||||
int stdio_count;
|
||||
ssize_t r;
|
||||
pid_t pid;
|
||||
int err;
|
||||
int exec_errorno;
|
||||
int i;
|
||||
int status;
|
||||
|
||||
assert(options->file != NULL);
|
||||
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
QUEUE_INIT(&process->queue);
|
||||
|
||||
stdio_count = options->stdio_count;
|
||||
if (stdio_count < 3)
|
||||
stdio_count = 3;
|
||||
|
||||
err = -ENOMEM;
|
||||
pipes = uv__malloc(stdio_count * sizeof(*pipes));
|
||||
if (pipes == NULL)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < stdio_count; i++) {
|
||||
pipes[i][0] = -1;
|
||||
pipes[i][1] = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
err = uv__process_init_stdio(options->stdio + i, pipes[i]);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This pipe is used by the parent to wait until
|
||||
* the child has called `execve()`. We need this
|
||||
* to avoid the following race condition:
|
||||
*
|
||||
* if ((pid = fork()) > 0) {
|
||||
* kill(pid, SIGTERM);
|
||||
* }
|
||||
* else if (pid == 0) {
|
||||
* execve("/bin/cat", argp, envp);
|
||||
* }
|
||||
*
|
||||
* The parent sends a signal immediately after forking.
|
||||
* Since the child may not have called `execve()` yet,
|
||||
* there is no telling what process receives the signal,
|
||||
* our fork or /bin/cat.
|
||||
*
|
||||
* To avoid ambiguity, we create a pipe with both ends
|
||||
* marked close-on-exec. Then, after the call to `fork()`,
|
||||
* the parent polls the read end until it EOFs or errors with EPIPE.
|
||||
*/
|
||||
err = uv__make_pipe(signal_pipe, 0);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
|
||||
|
||||
/* Acquire write lock to prevent opening new fds in worker threads */
|
||||
uv_rwlock_wrlock(&loop->cloexec_lock);
|
||||
pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
err = -errno;
|
||||
uv_rwlock_wrunlock(&loop->cloexec_lock);
|
||||
uv__close(signal_pipe[0]);
|
||||
uv__close(signal_pipe[1]);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Release lock in parent process */
|
||||
uv_rwlock_wrunlock(&loop->cloexec_lock);
|
||||
uv__close(signal_pipe[1]);
|
||||
|
||||
process->status = 0;
|
||||
exec_errorno = 0;
|
||||
do
|
||||
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == 0)
|
||||
; /* okay, EOF */
|
||||
else if (r == sizeof(exec_errorno)) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, read errorno */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else if (r == -1 && errno == EPIPE) {
|
||||
do
|
||||
err = waitpid(pid, &status, 0); /* okay, got EPIPE */
|
||||
while (err == -1 && errno == EINTR);
|
||||
assert(err == pid);
|
||||
} else
|
||||
abort();
|
||||
|
||||
uv__close_nocheckstdio(signal_pipe[0]);
|
||||
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
|
||||
if (err == 0)
|
||||
continue;
|
||||
|
||||
while (i--)
|
||||
uv__process_close_stream(options->stdio + i);
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Only activate this handle if exec() happened successfully */
|
||||
if (exec_errorno == 0) {
|
||||
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
|
||||
uv__handle_start(process);
|
||||
}
|
||||
|
||||
process->pid = pid;
|
||||
process->exit_cb = options->exit_cb;
|
||||
|
||||
uv__free(pipes);
|
||||
return exec_errorno;
|
||||
|
||||
error:
|
||||
if (pipes != NULL) {
|
||||
for (i = 0; i < stdio_count; i++) {
|
||||
if (i < options->stdio_count)
|
||||
if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
|
||||
continue;
|
||||
if (pipes[i][0] != -1)
|
||||
uv__close_nocheckstdio(pipes[i][0]);
|
||||
if (pipes[i][1] != -1)
|
||||
uv__close_nocheckstdio(pipes[i][1]);
|
||||
}
|
||||
uv__free(pipes);
|
||||
}
|
||||
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv_process_kill(uv_process_t* process, int signum) {
|
||||
return uv_kill(process->pid, signum);
|
||||
}
|
||||
|
||||
|
||||
int uv_kill(int pid, int signum) {
|
||||
if (kill(pid, signum))
|
||||
return -errno;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__process_close(uv_process_t* handle) {
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
if (QUEUE_EMPTY(&handle->loop->process_handles))
|
||||
uv_signal_stop(&handle->loop->child_watcher);
|
||||
}
|
||||
105
Utilities/cmlibuv/src/unix/proctitle.c
Normal file
105
Utilities/cmlibuv/src/unix/proctitle.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void uv__set_process_title(const char* title);
|
||||
|
||||
static void* args_mem;
|
||||
|
||||
static struct {
|
||||
char* str;
|
||||
size_t len;
|
||||
} process_title;
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
char** new_argv;
|
||||
size_t size;
|
||||
char* s;
|
||||
int i;
|
||||
|
||||
if (argc <= 0)
|
||||
return argv;
|
||||
|
||||
/* Calculate how much memory we need for the argv strings. */
|
||||
size = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
size += strlen(argv[i]) + 1;
|
||||
|
||||
process_title.str = argv[0];
|
||||
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
|
||||
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
|
||||
|
||||
/* Add space for the argv pointers. */
|
||||
size += (argc + 1) * sizeof(char*);
|
||||
|
||||
new_argv = uv__malloc(size);
|
||||
if (new_argv == NULL)
|
||||
return argv;
|
||||
args_mem = new_argv;
|
||||
|
||||
/* Copy over the strings and set up the pointer table. */
|
||||
s = (char*) &new_argv[argc + 1];
|
||||
for (i = 0; i < argc; i++) {
|
||||
size = strlen(argv[i]) + 1;
|
||||
memcpy(s, argv[i], size);
|
||||
new_argv[i] = s;
|
||||
s += size;
|
||||
}
|
||||
new_argv[i] = NULL;
|
||||
|
||||
return new_argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
if (process_title.len == 0)
|
||||
return 0;
|
||||
|
||||
/* No need to terminate, byte after is always '\0'. */
|
||||
strncpy(process_title.str, title, process_title.len);
|
||||
uv__set_process_title(title);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
else if (size <= process_title.len)
|
||||
return -ENOBUFS;
|
||||
|
||||
memcpy(buffer, process_title.str, process_title.len + 1);
|
||||
buffer[process_title.len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void free_args_mem(void)) {
|
||||
uv__free(args_mem); /* Keep valgrind happy. */
|
||||
args_mem = NULL;
|
||||
}
|
||||
120
Utilities/cmlibuv/src/unix/pthread-barrier.c
Normal file
120
Utilities/cmlibuv/src/unix/pthread-barrier.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "uv-common.h"
|
||||
#include "pthread-barrier.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* TODO: support barrier_attr */
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || count == 0)
|
||||
return EINVAL;
|
||||
|
||||
if (barrier_attr != NULL)
|
||||
return ENOTSUP;
|
||||
|
||||
b = uv__malloc(sizeof(*b));
|
||||
if (b == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
b->in = 0;
|
||||
b->out = 0;
|
||||
b->threshold = count;
|
||||
|
||||
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
|
||||
goto error2;
|
||||
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
|
||||
goto error;
|
||||
|
||||
barrier->b = b;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
error2:
|
||||
uv__free(b);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
|
||||
b = barrier->b;
|
||||
/* Lock the mutex*/
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
|
||||
/* Increment the count. If this is the first thread to reach the threshold,
|
||||
wake up waiters, unlock the mutex, then return
|
||||
PTHREAD_BARRIER_SERIAL_THREAD. */
|
||||
if (++b->in == b->threshold) {
|
||||
b->in = 0;
|
||||
b->out = b->threshold - 1;
|
||||
assert(pthread_cond_signal(&b->cond) == 0);
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
/* Otherwise, wait for other threads until in is set to 0,
|
||||
then return 0 to indicate this is not the first thread. */
|
||||
do {
|
||||
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
|
||||
break;
|
||||
} while (b->in != 0);
|
||||
|
||||
/* mark thread exit */
|
||||
b->out--;
|
||||
pthread_cond_signal(&b->cond);
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pthread_barrier_destroy(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
|
||||
b = barrier->b;
|
||||
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
|
||||
if (b->in > 0 || b->out > 0)
|
||||
rc = EBUSY;
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pthread_cond_destroy(&b->cond);
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
uv__free(barrier->b);
|
||||
barrier->b = NULL;
|
||||
return 0;
|
||||
}
|
||||
56
Utilities/cmlibuv/src/unix/pthread-fixes.c
Normal file
56
Utilities/cmlibuv/src/unix/pthread-fixes.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright (c) 2013, Sony Mobile Communications AB
|
||||
* Copyright (c) 2012, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Android versions < 4.1 have a broken pthread_sigmask. */
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
|
||||
static int workaround;
|
||||
int err;
|
||||
|
||||
if (workaround) {
|
||||
return sigprocmask(how, set, oset);
|
||||
} else {
|
||||
err = pthread_sigmask(how, set, oset);
|
||||
if (err) {
|
||||
if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
|
||||
workaround = 1;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
467
Utilities/cmlibuv/src/unix/signal.c
Normal file
467
Utilities/cmlibuv/src/unix/signal.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uv_signal_t* handle;
|
||||
int signum;
|
||||
} uv__signal_msg_t;
|
||||
|
||||
RB_HEAD(uv__signal_tree_s, uv_signal_s);
|
||||
|
||||
|
||||
static int uv__signal_unlock(void);
|
||||
static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
|
||||
static void uv__signal_stop(uv_signal_t* handle);
|
||||
|
||||
|
||||
static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
|
||||
static struct uv__signal_tree_s uv__signal_tree =
|
||||
RB_INITIALIZER(uv__signal_tree);
|
||||
static int uv__signal_lock_pipefd[2];
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(uv__signal_tree_s,
|
||||
uv_signal_s, tree_entry,
|
||||
uv__signal_compare)
|
||||
|
||||
|
||||
static void uv__signal_global_init(void) {
|
||||
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
|
||||
abort();
|
||||
|
||||
if (uv__signal_unlock())
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_global_once_init(void) {
|
||||
pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int uv__signal_lock(void) {
|
||||
int r;
|
||||
char data;
|
||||
|
||||
do {
|
||||
r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
return (r < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_unlock(void) {
|
||||
int r;
|
||||
char data = 42;
|
||||
|
||||
do {
|
||||
r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
|
||||
} while (r < 0 && errno == EINTR);
|
||||
|
||||
return (r < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
|
||||
sigset_t new_mask;
|
||||
|
||||
if (sigfillset(&new_mask))
|
||||
abort();
|
||||
|
||||
if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
|
||||
abort();
|
||||
|
||||
if (uv__signal_lock())
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
|
||||
if (uv__signal_unlock())
|
||||
abort();
|
||||
|
||||
if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static uv_signal_t* uv__signal_first_handle(int signum) {
|
||||
/* This function must be called with the signal lock held. */
|
||||
uv_signal_t lookup;
|
||||
uv_signal_t* handle;
|
||||
|
||||
lookup.signum = signum;
|
||||
lookup.loop = NULL;
|
||||
|
||||
handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
|
||||
|
||||
if (handle != NULL && handle->signum == signum)
|
||||
return handle;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_handler(int signum) {
|
||||
uv__signal_msg_t msg;
|
||||
uv_signal_t* handle;
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
memset(&msg, 0, sizeof msg);
|
||||
|
||||
if (uv__signal_lock()) {
|
||||
errno = saved_errno;
|
||||
return;
|
||||
}
|
||||
|
||||
for (handle = uv__signal_first_handle(signum);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
|
||||
int r;
|
||||
|
||||
msg.signum = signum;
|
||||
msg.handle = handle;
|
||||
|
||||
/* write() should be atomic for small data chunks, so the entire message
|
||||
* should be written at once. In theory the pipe could become full, in
|
||||
* which case the user is out of luck.
|
||||
*/
|
||||
do {
|
||||
r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
assert(r == sizeof msg ||
|
||||
(r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
|
||||
|
||||
if (r != -1)
|
||||
handle->caught_signals++;
|
||||
}
|
||||
|
||||
uv__signal_unlock();
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register_handler(int signum) {
|
||||
/* When this function is called, the signal lock must be held. */
|
||||
struct sigaction sa;
|
||||
|
||||
/* XXX use a separate signal stack? */
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (sigfillset(&sa.sa_mask))
|
||||
abort();
|
||||
sa.sa_handler = uv__signal_handler;
|
||||
|
||||
/* XXX save old action so we can restore it later on? */
|
||||
if (sigaction(signum, &sa, NULL))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister_handler(int signum) {
|
||||
/* When this function is called, the signal lock must be held. */
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = SIG_DFL;
|
||||
|
||||
/* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
|
||||
* signal implies that it was successfully registered earlier, so EINVAL
|
||||
* should never happen.
|
||||
*/
|
||||
if (sigaction(signum, &sa, NULL))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_loop_once_init(uv_loop_t* loop) {
|
||||
int err;
|
||||
|
||||
/* Return if already initialized. */
|
||||
if (loop->signal_pipefd[0] != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__io_init(&loop->signal_io_watcher,
|
||||
uv__signal_event,
|
||||
loop->signal_pipefd[0]);
|
||||
uv__io_start(loop, &loop->signal_io_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_loop_cleanup(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
|
||||
/* Stop all the signal watchers that are still attached to this loop. This
|
||||
* ensures that the (shared) signal tree doesn't contain any invalid entries
|
||||
* entries, and that signal handlers are removed when appropriate.
|
||||
* It's safe to use QUEUE_FOREACH here because the handles and the handle
|
||||
* queue are not modified by uv__signal_stop().
|
||||
*/
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
|
||||
if (handle->type == UV_SIGNAL)
|
||||
uv__signal_stop((uv_signal_t*) handle);
|
||||
}
|
||||
|
||||
if (loop->signal_pipefd[0] != -1) {
|
||||
uv__close(loop->signal_pipefd[0]);
|
||||
loop->signal_pipefd[0] = -1;
|
||||
}
|
||||
|
||||
if (loop->signal_pipefd[1] != -1) {
|
||||
uv__close(loop->signal_pipefd[1]);
|
||||
loop->signal_pipefd[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
int err;
|
||||
|
||||
err = uv__signal_loop_once_init(loop);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
|
||||
handle->signum = 0;
|
||||
handle->caught_signals = 0;
|
||||
handle->dispatched_signals = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_close(uv_signal_t* handle) {
|
||||
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If there are any caught signals "trapped" in the signal pipe, we can't
|
||||
* call the close callback yet. Otherwise, add the handle to the finish_close
|
||||
* queue.
|
||||
*/
|
||||
if (handle->caught_signals == handle->dispatched_signals) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
|
||||
sigset_t saved_sigmask;
|
||||
int err;
|
||||
|
||||
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
|
||||
|
||||
/* If the user supplies signum == 0, then return an error already. If the
|
||||
* signum is otherwise invalid then uv__signal_register will find out
|
||||
* eventually.
|
||||
*/
|
||||
if (signum == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Short circuit: if the signal watcher is already watching {signum} don't
|
||||
* go through the process of deregistering and registering the handler.
|
||||
* Additionally, this avoids pending signals getting lost in the small time
|
||||
* time frame that handle->signum == 0.
|
||||
*/
|
||||
if (signum == handle->signum) {
|
||||
handle->signal_cb = signal_cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the signal handler was already active, stop it first. */
|
||||
if (handle->signum != 0) {
|
||||
uv__signal_stop(handle);
|
||||
}
|
||||
|
||||
uv__signal_block_and_lock(&saved_sigmask);
|
||||
|
||||
/* If at this point there are no active signal watchers for this signum (in
|
||||
* any of the loops), it's time to try and register a handler for it here.
|
||||
*/
|
||||
if (uv__signal_first_handle(signum) == NULL) {
|
||||
err = uv__signal_register_handler(signum);
|
||||
if (err) {
|
||||
/* Registering the signal handler failed. Must be an invalid signal. */
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
handle->signum = signum;
|
||||
RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
|
||||
handle->signal_cb = signal_cb;
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_event(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int events) {
|
||||
uv__signal_msg_t* msg;
|
||||
uv_signal_t* handle;
|
||||
char buf[sizeof(uv__signal_msg_t) * 32];
|
||||
size_t bytes, end, i;
|
||||
int r;
|
||||
|
||||
bytes = 0;
|
||||
end = 0;
|
||||
|
||||
do {
|
||||
r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
|
||||
|
||||
if (r == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
/* If there are bytes in the buffer already (which really is extremely
|
||||
* unlikely if possible at all) we can't exit the function here. We'll
|
||||
* spin until more bytes are read instead.
|
||||
*/
|
||||
if (bytes > 0)
|
||||
continue;
|
||||
|
||||
/* Otherwise, there was nothing there. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Other errors really should never happen. */
|
||||
if (r == -1)
|
||||
abort();
|
||||
|
||||
bytes += r;
|
||||
|
||||
/* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
|
||||
end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
|
||||
|
||||
for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
|
||||
msg = (uv__signal_msg_t*) (buf + i);
|
||||
handle = msg->handle;
|
||||
|
||||
if (msg->signum == handle->signum) {
|
||||
assert(!(handle->flags & UV_CLOSING));
|
||||
handle->signal_cb(handle, handle->signum);
|
||||
}
|
||||
|
||||
handle->dispatched_signals++;
|
||||
|
||||
/* If uv_close was called while there were caught signals that were not
|
||||
* yet dispatched, the uv__finish_close was deferred. Make close pending
|
||||
* now if this has happened.
|
||||
*/
|
||||
if ((handle->flags & UV_CLOSING) &&
|
||||
(handle->caught_signals == handle->dispatched_signals)) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
bytes -= end;
|
||||
|
||||
/* If there are any "partial" messages left, move them to the start of the
|
||||
* the buffer, and spin. This should not happen.
|
||||
*/
|
||||
if (bytes) {
|
||||
memmove(buf, buf + end, bytes);
|
||||
continue;
|
||||
}
|
||||
} while (end == sizeof buf);
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
/* Compare signums first so all watchers with the same signnum end up
|
||||
* adjacent.
|
||||
*/
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Sort by loop pointer, so we can easily look up the first item after
|
||||
* { .signum = x, .loop = NULL }.
|
||||
*/
|
||||
if (w1->loop < w2->loop) return -1;
|
||||
if (w1->loop > w2->loop) return 1;
|
||||
|
||||
if (w1 < w2) return -1;
|
||||
if (w1 > w2) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_stop(uv_signal_t* handle) {
|
||||
assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
|
||||
uv__signal_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_stop(uv_signal_t* handle) {
|
||||
uv_signal_t* removed_handle;
|
||||
sigset_t saved_sigmask;
|
||||
|
||||
/* If the watcher wasn't started, this is a no-op. */
|
||||
if (handle->signum == 0)
|
||||
return;
|
||||
|
||||
uv__signal_block_and_lock(&saved_sigmask);
|
||||
|
||||
removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
assert(removed_handle == handle);
|
||||
(void) removed_handle;
|
||||
|
||||
/* Check if there are other active signal watchers observing this signal. If
|
||||
* not, unregister the signal handler.
|
||||
*/
|
||||
if (uv__signal_first_handle(handle->signum) == NULL)
|
||||
uv__signal_unregister_handler(handle->signum);
|
||||
|
||||
uv__signal_unlock_and_unblock(&saved_sigmask);
|
||||
|
||||
handle->signum = 0;
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
53
Utilities/cmlibuv/src/unix/spinlock.h
Normal file
53
Utilities/cmlibuv/src/unix/spinlock.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SPINLOCK_H_
|
||||
#define UV_SPINLOCK_H_
|
||||
|
||||
#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
|
||||
#include "atomic-ops.h"
|
||||
|
||||
#define UV_SPINLOCK_INITIALIZER { 0 }
|
||||
|
||||
typedef struct {
|
||||
int lock;
|
||||
} uv_spinlock_t;
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
|
||||
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
|
||||
ACCESS_ONCE(int, spinlock->lock) = 0;
|
||||
}
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
|
||||
while (!uv_spinlock_trylock(spinlock)) cpu_relax();
|
||||
}
|
||||
|
||||
UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
|
||||
ACCESS_ONCE(int, spinlock->lock) = 0;
|
||||
}
|
||||
|
||||
UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
|
||||
/* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
|
||||
* Not really critical until we have locks that are (frequently) contended
|
||||
* for by several threads.
|
||||
*/
|
||||
return 0 == cmpxchgi(&spinlock->lock, 0, 1);
|
||||
}
|
||||
|
||||
#endif /* UV_SPINLOCK_H_ */
|
||||
1638
Utilities/cmlibuv/src/unix/stream.c
Normal file
1638
Utilities/cmlibuv/src/unix/stream.c
Normal file
File diff suppressed because it is too large
Load Diff
821
Utilities/cmlibuv/src/unix/sunos.c
Normal file
821
Utilities/cmlibuv/src/unix/sunos.c
Normal file
@@ -0,0 +1,821 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef SUNOS_NO_IFADDRS
|
||||
# include <ifaddrs.h>
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <sys/loadavg.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <kstat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/port.h>
|
||||
#include <port.h>
|
||||
|
||||
#define PORT_FIRED 0x69
|
||||
#define PORT_UNUSED 0x0
|
||||
#define PORT_LOADED 0x99
|
||||
#define PORT_DELETED -1
|
||||
|
||||
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
|
||||
#define PROCFS_FILE_OFFSET_BITS_HACK 1
|
||||
#undef _FILE_OFFSET_BITS
|
||||
#else
|
||||
#define PROCFS_FILE_OFFSET_BITS_HACK 0
|
||||
#endif
|
||||
|
||||
#include <procfs.h>
|
||||
|
||||
#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
loop->fs_fd = -1;
|
||||
loop->backend_fd = -1;
|
||||
|
||||
fd = port_create();
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
loop->backend_fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
if (loop->fs_fd != -1) {
|
||||
uv__close(loop->fs_fd);
|
||||
loop->fs_fd = -1;
|
||||
}
|
||||
|
||||
if (loop->backend_fd != -1) {
|
||||
uv__close(loop->backend_fd);
|
||||
loop->backend_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct port_event* events;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
|
||||
events = (struct port_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events == NULL)
|
||||
return;
|
||||
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].portev_object == fd)
|
||||
events[i].portev_object = -1;
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
|
||||
return -errno;
|
||||
|
||||
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd))
|
||||
abort();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct port_event events[1024];
|
||||
struct port_event* pe;
|
||||
struct timespec spec;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t* pset;
|
||||
sigset_t set;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
unsigned int nfds;
|
||||
unsigned int i;
|
||||
int saved_errno;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
int count;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (loop->nfds == 0) {
|
||||
assert(QUEUE_EMPTY(&loop->watcher_queue));
|
||||
return;
|
||||
}
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q);
|
||||
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
|
||||
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
|
||||
abort();
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
pset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
pset = &set;
|
||||
sigemptyset(pset);
|
||||
sigaddset(pset, SIGPROF);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
base = loop->time;
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
|
||||
for (;;) {
|
||||
if (timeout != -1) {
|
||||
spec.tv_sec = timeout / 1000;
|
||||
spec.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
|
||||
/* Work around a kernel bug where nfds is not updated. */
|
||||
events[0].portev_source = 0;
|
||||
|
||||
nfds = 1;
|
||||
saved_errno = 0;
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_BLOCK, pset, NULL);
|
||||
|
||||
err = port_getn(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
&nfds,
|
||||
timeout == -1 ? NULL : &spec);
|
||||
|
||||
if (pset != NULL)
|
||||
pthread_sigmask(SIG_UNBLOCK, pset, NULL);
|
||||
|
||||
if (err) {
|
||||
/* Work around another kernel bug: port_getn() may return events even
|
||||
* on error.
|
||||
*/
|
||||
if (errno == EINTR || errno == ETIME)
|
||||
saved_errno = errno;
|
||||
else
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||
* operating system didn't reschedule our process while in the syscall.
|
||||
*/
|
||||
SAVE_ERRNO(uv__update_time(loop));
|
||||
|
||||
if (events[0].portev_source == 0) {
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
goto update_timeout;
|
||||
}
|
||||
|
||||
if (nfds == 0) {
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = (void*) events;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->portev_object;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert((unsigned) fd < loop->nwatchers);
|
||||
|
||||
w = loop->watchers[fd];
|
||||
|
||||
/* File descriptor that we've stopped watching, ignore. */
|
||||
if (w == NULL)
|
||||
continue;
|
||||
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher)
|
||||
have_signals = 1;
|
||||
else
|
||||
w->cb(loop, w, pe->portev_events);
|
||||
|
||||
nevents++;
|
||||
|
||||
if (w != loop->watchers[fd])
|
||||
continue; /* Disabled by callback. */
|
||||
|
||||
/* Events Ports operates in oneshot mode, rearm timer on next run. */
|
||||
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
|
||||
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
|
||||
}
|
||||
|
||||
if (have_signals != 0)
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
if (nevents != 0) {
|
||||
if (nfds == ARRAY_SIZE(events) && --count != 0) {
|
||||
/* Poll for more events but don't block this time. */
|
||||
timeout = 0;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (saved_errno == ETIME) {
|
||||
assert(timeout != -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return;
|
||||
|
||||
if (timeout == -1)
|
||||
continue;
|
||||
|
||||
update_timeout:
|
||||
assert(timeout > 0);
|
||||
|
||||
diff = loop->time - base;
|
||||
if (diff >= (uint64_t) timeout)
|
||||
return;
|
||||
|
||||
timeout -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(uv_clocktype_t type) {
|
||||
return gethrtime();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We could use a static buffer for the path manipulations that we need outside
|
||||
* of the function, but this function could be called by multiple consumers and
|
||||
* we don't want to potentially create a race condition in the use of snprintf.
|
||||
*/
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
ssize_t res;
|
||||
char buf[128];
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
|
||||
|
||||
res = *size - 1;
|
||||
if (res > 0)
|
||||
res = readlink(buf, buffer, res);
|
||||
|
||||
if (res == -1)
|
||||
return -errno;
|
||||
|
||||
buffer[res] = '\0';
|
||||
*size = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
(void) getloadavg(avg, 3);
|
||||
}
|
||||
|
||||
|
||||
#if defined(PORT_SOURCE_FILE)
|
||||
|
||||
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
|
||||
if (handle->fd == -1)
|
||||
return -EBADF;
|
||||
|
||||
if (port_associate(handle->loop->fs_fd,
|
||||
PORT_SOURCE_FILE,
|
||||
(uintptr_t) &handle->fo,
|
||||
FILE_ATTRIB | FILE_MODIFIED,
|
||||
handle) == -1) {
|
||||
return -errno;
|
||||
}
|
||||
handle->fd = PORT_LOADED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_event_read(uv_loop_t* loop,
|
||||
uv__io_t* w,
|
||||
unsigned int revents) {
|
||||
uv_fs_event_t *handle = NULL;
|
||||
timespec_t timeout;
|
||||
port_event_t pe;
|
||||
int events;
|
||||
int r;
|
||||
|
||||
(void) w;
|
||||
(void) revents;
|
||||
|
||||
do {
|
||||
uint_t n = 1;
|
||||
|
||||
/*
|
||||
* Note that our use of port_getn() here (and not port_get()) is deliberate:
|
||||
* there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
|
||||
* causes port_get() to return success instead of ETIME when there aren't
|
||||
* actually any events (!); by using port_getn() in lieu of port_get(),
|
||||
* we can at least workaround the bug by checking for zero returned events
|
||||
* and treating it as we would ETIME.
|
||||
*/
|
||||
do {
|
||||
memset(&timeout, 0, sizeof timeout);
|
||||
r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if ((r == -1 && errno == ETIME) || n == 0)
|
||||
break;
|
||||
|
||||
handle = (uv_fs_event_t*) pe.portev_user;
|
||||
assert((r == 0) && "unexpected port_get() error");
|
||||
|
||||
events = 0;
|
||||
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
|
||||
events |= UV_CHANGE;
|
||||
if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
|
||||
events |= UV_RENAME;
|
||||
assert(events != 0);
|
||||
handle->fd = PORT_FIRED;
|
||||
handle->cb(handle, NULL, events, 0);
|
||||
|
||||
if (handle->fd != PORT_DELETED) {
|
||||
r = uv__fs_event_rearm(handle);
|
||||
if (r != 0)
|
||||
handle->cb(handle, NULL, 0, r);
|
||||
}
|
||||
}
|
||||
while (handle->fd != PORT_DELETED);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int portfd;
|
||||
int first_run;
|
||||
int err;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return -EINVAL;
|
||||
|
||||
first_run = 0;
|
||||
if (handle->loop->fs_fd == -1) {
|
||||
portfd = port_create();
|
||||
if (portfd == -1)
|
||||
return -errno;
|
||||
handle->loop->fs_fd = portfd;
|
||||
first_run = 1;
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
handle->path = uv__strdup(path);
|
||||
handle->fd = PORT_UNUSED;
|
||||
handle->cb = cb;
|
||||
|
||||
memset(&handle->fo, 0, sizeof handle->fo);
|
||||
handle->fo.fo_name = handle->path;
|
||||
err = uv__fs_event_rearm(handle);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
if (first_run) {
|
||||
uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
|
||||
uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
|
||||
port_dissociate(handle->loop->fs_fd,
|
||||
PORT_SOURCE_FILE,
|
||||
(uintptr_t) &handle->fo);
|
||||
}
|
||||
|
||||
handle->fd = PORT_DELETED;
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
handle->fo.fo_name = NULL;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
|
||||
#else /* !defined(PORT_SOURCE_FILE) */
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* filename,
|
||||
unsigned int flags) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
#endif /* defined(PORT_SOURCE_FILE) */
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
if (buffer == NULL || size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
psinfo_t psinfo;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/self/psinfo", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return -errno;
|
||||
|
||||
/* FIXME(bnoordhuis) Handle EINTR. */
|
||||
err = -EINVAL;
|
||||
if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
|
||||
*rss = (size_t)psinfo.pr_rssize * 1024;
|
||||
err = 0;
|
||||
}
|
||||
uv__close(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
kstat_ctl_t *kc;
|
||||
kstat_t *ksp;
|
||||
kstat_named_t *knp;
|
||||
|
||||
long hz = sysconf(_SC_CLK_TCK);
|
||||
|
||||
kc = kstat_open();
|
||||
if (kc == NULL)
|
||||
return -EPERM;
|
||||
|
||||
ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
*uptime = -1;
|
||||
} else {
|
||||
knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
|
||||
*uptime = knp->value.ul / hz;
|
||||
}
|
||||
kstat_close(kc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
int lookup_instance;
|
||||
kstat_ctl_t *kc;
|
||||
kstat_t *ksp;
|
||||
kstat_named_t *knp;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
kc = kstat_open();
|
||||
if (kc == NULL)
|
||||
return -EPERM;
|
||||
|
||||
/* Get count of cpus */
|
||||
lookup_instance = 0;
|
||||
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
|
||||
lookup_instance++;
|
||||
}
|
||||
|
||||
*cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos)) {
|
||||
kstat_close(kc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*count = lookup_instance;
|
||||
|
||||
cpu_info = *cpu_infos;
|
||||
lookup_instance = 0;
|
||||
while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
cpu_info->speed = 0;
|
||||
cpu_info->model = NULL;
|
||||
} else {
|
||||
knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
|
||||
assert(knp->data_type == KSTAT_DATA_INT32 ||
|
||||
knp->data_type == KSTAT_DATA_INT64);
|
||||
cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
|
||||
: knp->value.i64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "brand");
|
||||
assert(knp->data_type == KSTAT_DATA_STRING);
|
||||
cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
|
||||
}
|
||||
|
||||
lookup_instance++;
|
||||
cpu_info++;
|
||||
}
|
||||
|
||||
cpu_info = *cpu_infos;
|
||||
lookup_instance = 0;
|
||||
for (;;) {
|
||||
ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
|
||||
|
||||
if (ksp == NULL)
|
||||
break;
|
||||
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
cpu_info->cpu_times.user = 0;
|
||||
cpu_info->cpu_times.nice = 0;
|
||||
cpu_info->cpu_times.sys = 0;
|
||||
cpu_info->cpu_times.idle = 0;
|
||||
cpu_info->cpu_times.irq = 0;
|
||||
} else {
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.user = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.sys = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.idle = knp->value.ui64;
|
||||
|
||||
knp = kstat_data_lookup(ksp, (char*) "intr");
|
||||
assert(knp->data_type == KSTAT_DATA_UINT64);
|
||||
cpu_info->cpu_times.irq = knp->value.ui64;
|
||||
cpu_info->cpu_times.nice = 0;
|
||||
}
|
||||
|
||||
lookup_instance++;
|
||||
cpu_info++;
|
||||
}
|
||||
|
||||
kstat_close(kc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspired By:
|
||||
* https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
|
||||
* http://www.pauliesworld.org/project/getmac.c
|
||||
*/
|
||||
static int uv__set_phys_addr(uv_interface_address_t* address,
|
||||
struct ifaddrs* ent) {
|
||||
|
||||
struct sockaddr_dl* sa_addr;
|
||||
int sockfd;
|
||||
int i;
|
||||
struct arpreq arpreq;
|
||||
|
||||
/* This appears to only work as root */
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
for (i = 0; i < sizeof(address->phys_addr); i++) {
|
||||
if (address->phys_addr[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
memset(&arpreq, 0, sizeof(arpreq));
|
||||
if (address->address.address4.sin_family == AF_INET) {
|
||||
struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
|
||||
sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
|
||||
} else if (address->address.address4.sin_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
|
||||
memcpy(sin->sin6_addr.s6_addr,
|
||||
address->address.address6.sin6_addr.s6_addr,
|
||||
sizeof(address->address.address6.sin6_addr.s6_addr));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0)
|
||||
return -errno;
|
||||
|
||||
if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
|
||||
uv__close(sockfd);
|
||||
return -errno;
|
||||
}
|
||||
memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
#ifdef SUNOS_NO_IFADDRS
|
||||
return -ENOSYS;
|
||||
#else
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
int i;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return -errno;
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
|
||||
(ent->ifa_addr == NULL) ||
|
||||
(ent->ifa_addr->sa_family == PF_PACKET)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
address = *addresses;
|
||||
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
continue;
|
||||
|
||||
if (ent->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(ent->ifa_name);
|
||||
|
||||
if (ent->ifa_addr->sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
|
||||
}
|
||||
|
||||
if (ent->ifa_netmask->sa_family == AF_INET6) {
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
|
||||
} else {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
|
||||
}
|
||||
|
||||
address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
|
||||
(ent->ifa_flags & IFF_LOOPBACK));
|
||||
|
||||
uv__set_phys_addr(address, ent);
|
||||
address++;
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
return 0;
|
||||
#endif /* SUNOS_NO_IFADDRS */
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
395
Utilities/cmlibuv/src/unix/tcp.c
Normal file
395
Utilities/cmlibuv/src/unix/tcp.c
Normal file
@@ -0,0 +1,395 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
|
||||
int sockfd;
|
||||
int err;
|
||||
|
||||
if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = uv__socket(domain, SOCK_STREAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sockfd = err;
|
||||
|
||||
err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
|
||||
if (err) {
|
||||
uv__close(sockfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
|
||||
int domain;
|
||||
|
||||
/* Use the lower 8 bits for the domain */
|
||||
domain = flags & 0xFF;
|
||||
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & ~0xFF)
|
||||
return -EINVAL;
|
||||
|
||||
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
|
||||
|
||||
/* If anything fails beyond this point we need to remove the handle from
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (domain != AF_UNSPEC) {
|
||||
int err = maybe_new_socket(tcp, domain, 0);
|
||||
if (err) {
|
||||
QUEUE_REMOVE(&tcp->handle_queue);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
int err;
|
||||
int on;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
|
||||
return -EINVAL;
|
||||
|
||||
err = maybe_new_socket(tcp,
|
||||
addr->sa_family,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
on = 1;
|
||||
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
||||
return -errno;
|
||||
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
on = (flags & UV_TCP_IPV6ONLY) != 0;
|
||||
if (setsockopt(tcp->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
IPV6_V6ONLY,
|
||||
&on,
|
||||
sizeof on) == -1) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == EOPNOTSUPP)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
errno = 0;
|
||||
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
|
||||
if (errno == EAFNOSUPPORT)
|
||||
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
|
||||
* socket created with AF_INET to an AF_INET6 address or vice versa. */
|
||||
return -EINVAL;
|
||||
return -errno;
|
||||
}
|
||||
tcp->delayed_error = -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
if (addr->sa_family == AF_INET6)
|
||||
tcp->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_connect_cb cb) {
|
||||
int err;
|
||||
int r;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
if (handle->connect_req != NULL)
|
||||
return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
|
||||
|
||||
err = maybe_new_socket(handle,
|
||||
addr->sa_family,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
handle->delayed_error = 0;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(uv__stream_fd(handle), addr, addrlen);
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
/* We not only check the return value, but also check the errno != 0.
|
||||
* Because in rare cases connect() will return -1 but the errno
|
||||
* is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
|
||||
* and actually the tcp three-way handshake is completed.
|
||||
*/
|
||||
if (r == -1 && errno != 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED)
|
||||
/* If we get a ECONNREFUSED wait until the next tick to report the
|
||||
* error. Solaris wants to report immediately--other unixes want to
|
||||
* wait.
|
||||
*/
|
||||
handle->delayed_error = -errno;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
uv__req_init(handle->loop, req, UV_CONNECT);
|
||||
req->cb = cb;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
QUEUE_INIT(&req->queue);
|
||||
handle->connect_req = req;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
|
||||
if (handle->delayed_error)
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
int err;
|
||||
|
||||
err = uv__nonblock(sock, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
sock,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
if (uv__stream_fd(handle) < 0)
|
||||
return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getsockname(uv__stream_fd(handle), name, &socklen))
|
||||
return -errno;
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
if (uv__stream_fd(handle) < 0)
|
||||
return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getpeername(uv__stream_fd(handle), name, &socklen))
|
||||
return -errno;
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
static int single_accept = -1;
|
||||
int err;
|
||||
|
||||
if (tcp->delayed_error)
|
||||
return tcp->delayed_error;
|
||||
|
||||
if (single_accept == -1) {
|
||||
const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
|
||||
single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
|
||||
}
|
||||
|
||||
if (single_accept)
|
||||
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
|
||||
err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef __MVS__
|
||||
/* on zOS the listen call does not bind automatically
|
||||
if the socket is unbound. Hence the manual binding to
|
||||
an arbitrary port is required to be done manually
|
||||
*/
|
||||
|
||||
if (!(tcp->flags & UV_HANDLE_BOUND)) {
|
||||
struct sockaddr_storage saddr;
|
||||
socklen_t slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
|
||||
if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
|
||||
return -errno;
|
||||
|
||||
if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
|
||||
return -errno;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen(tcp->io_watcher.fd, backlog))
|
||||
return -errno;
|
||||
|
||||
tcp->connection_cb = cb;
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
/* Start listening for connections. */
|
||||
tcp->io_watcher.cb = uv__server_io;
|
||||
uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_nodelay(int fd, int on) {
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
|
||||
return -errno;
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return -errno;
|
||||
#endif
|
||||
|
||||
/* Solaris/SmartOS, if you don't support keep-alive,
|
||||
* then don't advertise it in your system headers...
|
||||
*/
|
||||
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
|
||||
#if defined(TCP_KEEPALIVE) && !defined(__sun)
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
|
||||
return -errno;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
|
||||
int err;
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
err = uv__tcp_nodelay(uv__stream_fd(handle), on);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_NODELAY;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_NODELAY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
int err;
|
||||
|
||||
if (uv__stream_fd(handle) != -1) {
|
||||
err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_KEEPALIVE;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_KEEPALIVE;
|
||||
|
||||
/* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
|
||||
* uv_tcp_t with an int that's almost never used...
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
if (enable)
|
||||
handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
|
||||
else
|
||||
handle->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__tcp_close(uv_tcp_t* handle) {
|
||||
uv__stream_close((uv_stream_t*)handle);
|
||||
}
|
||||
605
Utilities/cmlibuv/src/unix/thread.c
Normal file
605
Utilities/cmlibuv/src/unix/thread.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h> /* getrlimit() */
|
||||
#include <unistd.h> /* getpagesize() */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __MVS__
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
struct thread_ctx {
|
||||
void (*entry)(void* arg);
|
||||
void* arg;
|
||||
};
|
||||
|
||||
|
||||
static void* uv__thread_start(void *arg)
|
||||
{
|
||||
struct thread_ctx *ctx_p;
|
||||
struct thread_ctx ctx;
|
||||
|
||||
ctx_p = arg;
|
||||
ctx = *ctx_p;
|
||||
uv__free(ctx_p);
|
||||
ctx.entry(ctx.arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
struct thread_ctx* ctx;
|
||||
int err;
|
||||
pthread_attr_t* attr;
|
||||
#if defined(__APPLE__)
|
||||
pthread_attr_t attr_storage;
|
||||
struct rlimit lim;
|
||||
#endif
|
||||
|
||||
ctx = uv__malloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
ctx->entry = entry;
|
||||
ctx->arg = arg;
|
||||
|
||||
/* On OSX threads other than the main thread are created with a reduced stack
|
||||
* size by default, adjust it to RLIMIT_STACK.
|
||||
*/
|
||||
#if defined(__APPLE__)
|
||||
if (getrlimit(RLIMIT_STACK, &lim))
|
||||
abort();
|
||||
|
||||
attr = &attr_storage;
|
||||
if (pthread_attr_init(attr))
|
||||
abort();
|
||||
|
||||
if (lim.rlim_cur != RLIM_INFINITY) {
|
||||
/* pthread_attr_setstacksize() expects page-aligned values. */
|
||||
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
||||
|
||||
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
|
||||
if (pthread_attr_setstacksize(attr, lim.rlim_cur))
|
||||
abort();
|
||||
}
|
||||
#else
|
||||
attr = NULL;
|
||||
#endif
|
||||
|
||||
err = pthread_create(tid, attr, uv__thread_start, ctx);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
|
||||
if (err)
|
||||
uv__free(ctx);
|
||||
|
||||
return -err;
|
||||
}
|
||||
|
||||
|
||||
uv_thread_t uv_thread_self(void) {
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
int uv_thread_join(uv_thread_t *tid) {
|
||||
return -pthread_join(*tid, NULL);
|
||||
}
|
||||
|
||||
|
||||
int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
|
||||
return pthread_equal(*t1, *t2);
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_init(uv_mutex_t* mutex) {
|
||||
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
||||
return -pthread_mutex_init(mutex, NULL);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
int err;
|
||||
|
||||
if (pthread_mutexattr_init(&attr))
|
||||
abort();
|
||||
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
|
||||
abort();
|
||||
|
||||
err = pthread_mutex_init(mutex, &attr);
|
||||
|
||||
if (pthread_mutexattr_destroy(&attr))
|
||||
abort();
|
||||
|
||||
return -err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_destroy(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_lock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_lock(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_mutex_trylock(uv_mutex_t* mutex) {
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_trylock(mutex);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_mutex_unlock(uv_mutex_t* mutex) {
|
||||
if (pthread_mutex_unlock(mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_init(uv_rwlock_t* rwlock) {
|
||||
return -pthread_rwlock_init(rwlock, NULL);
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_destroy(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_rdlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_tryrdlock(rwlock);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_wrlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_trywrlock(rwlock);
|
||||
if (err) {
|
||||
if (err != EBUSY && err != EAGAIN)
|
||||
abort();
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
|
||||
if (pthread_rwlock_unlock(rwlock))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_once(uv_once_t* guard, void (*callback)(void)) {
|
||||
if (pthread_once(guard, callback))
|
||||
abort();
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
kern_return_t err;
|
||||
|
||||
err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
|
||||
if (err == KERN_SUCCESS)
|
||||
return 0;
|
||||
if (err == KERN_INVALID_ARGUMENT)
|
||||
return -EINVAL;
|
||||
if (err == KERN_RESOURCE_SHORTAGE)
|
||||
return -ENOMEM;
|
||||
|
||||
abort();
|
||||
return -EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (semaphore_destroy(mach_task_self(), *sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
if (semaphore_signal(*sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = semaphore_wait(*sem);
|
||||
while (r == KERN_ABORTED);
|
||||
|
||||
if (r != KERN_SUCCESS)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
mach_timespec_t interval;
|
||||
kern_return_t err;
|
||||
|
||||
interval.tv_sec = 0;
|
||||
interval.tv_nsec = 0;
|
||||
|
||||
err = semaphore_timedwait(*sem, interval);
|
||||
if (err == KERN_SUCCESS)
|
||||
return 0;
|
||||
if (err == KERN_OPERATION_TIMED_OUT)
|
||||
return -EAGAIN;
|
||||
|
||||
abort();
|
||||
return -EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
#elif defined(__MVS__)
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
uv_sem_t semid;
|
||||
struct sembuf buf;
|
||||
int err;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = value;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
|
||||
if (semid == -1)
|
||||
return -errno;
|
||||
|
||||
if (-1 == semop(semid, &buf, 1)) {
|
||||
err = errno;
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
return -err;
|
||||
}
|
||||
|
||||
*sem = semid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (-1 == semctl(*sem, 0, IPC_RMID))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = 1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
if (-1 == semop(*sem, &buf, 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = 0;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status)
|
||||
abort();
|
||||
}
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
struct sembuf buf;
|
||||
int op_status;
|
||||
|
||||
buf.sem_num = 0;
|
||||
buf.sem_op = -1;
|
||||
buf.sem_flg = IPC_NOWAIT;
|
||||
|
||||
do
|
||||
op_status = semop(*sem, &buf, 1);
|
||||
while (op_status == -1 && errno == EINTR);
|
||||
|
||||
if (op_status) {
|
||||
if (errno == EAGAIN)
|
||||
return -EAGAIN;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
if (sem_init(sem, 0, value))
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_destroy(uv_sem_t* sem) {
|
||||
if (sem_destroy(sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_post(uv_sem_t* sem) {
|
||||
if (sem_post(sem))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void uv_sem_wait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = sem_wait(sem);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r)
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_sem_trywait(uv_sem_t* sem) {
|
||||
int r;
|
||||
|
||||
do
|
||||
r = sem_trywait(sem);
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r) {
|
||||
if (errno == EAGAIN)
|
||||
return -EAGAIN;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
return -pthread_cond_init(cond, NULL);
|
||||
}
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
pthread_condattr_t attr;
|
||||
int err;
|
||||
|
||||
err = pthread_condattr_init(&attr);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
|
||||
err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
if (err)
|
||||
goto error2;
|
||||
#endif
|
||||
|
||||
err = pthread_cond_init(cond, &attr);
|
||||
if (err)
|
||||
goto error2;
|
||||
|
||||
err = pthread_condattr_destroy(&attr);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_cond_destroy(cond);
|
||||
error2:
|
||||
pthread_condattr_destroy(&attr);
|
||||
return -err;
|
||||
}
|
||||
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
void uv_cond_destroy(uv_cond_t* cond) {
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/* It has been reported that destroying condition variables that have been
|
||||
* signalled but not waited on can sometimes result in application crashes.
|
||||
* See https://codereview.chromium.org/1323293005.
|
||||
*/
|
||||
pthread_mutex_t mutex;
|
||||
struct timespec ts;
|
||||
int err;
|
||||
|
||||
if (pthread_mutex_init(&mutex, NULL))
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_lock(&mutex))
|
||||
abort();
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 1;
|
||||
|
||||
err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
|
||||
if (err != 0 && err != ETIMEDOUT)
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_unlock(&mutex))
|
||||
abort();
|
||||
|
||||
if (pthread_mutex_destroy(&mutex))
|
||||
abort();
|
||||
#endif /* defined(__APPLE__) && defined(__MACH__) */
|
||||
|
||||
if (pthread_cond_destroy(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_signal(uv_cond_t* cond) {
|
||||
if (pthread_cond_signal(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_broadcast(uv_cond_t* cond) {
|
||||
if (pthread_cond_broadcast(cond))
|
||||
abort();
|
||||
}
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (pthread_cond_wait(cond, mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
int r;
|
||||
struct timespec ts;
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
|
||||
#else
|
||||
timeout += uv__hrtime(UV_CLOCK_PRECISE);
|
||||
ts.tv_sec = timeout / NANOSEC;
|
||||
ts.tv_nsec = timeout % NANOSEC;
|
||||
#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
|
||||
/*
|
||||
* The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
|
||||
* but has this alternative function instead.
|
||||
*/
|
||||
r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
|
||||
#else
|
||||
r = pthread_cond_timedwait(cond, mutex, &ts);
|
||||
#endif /* __ANDROID__ */
|
||||
#endif
|
||||
|
||||
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
if (r == ETIMEDOUT)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
abort();
|
||||
return -EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return -pthread_barrier_init(barrier, NULL, count);
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int r = pthread_barrier_wait(barrier);
|
||||
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
return r == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
|
||||
int uv_key_create(uv_key_t* key) {
|
||||
return -pthread_key_create(key, NULL);
|
||||
}
|
||||
|
||||
|
||||
void uv_key_delete(uv_key_t* key) {
|
||||
if (pthread_key_delete(*key))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
void* uv_key_get(uv_key_t* key) {
|
||||
return pthread_getspecific(*key);
|
||||
}
|
||||
|
||||
|
||||
void uv_key_set(uv_key_t* key, void* value) {
|
||||
if (pthread_setspecific(*key, value))
|
||||
abort();
|
||||
}
|
||||
172
Utilities/cmlibuv/src/unix/timer.c
Normal file
172
Utilities/cmlibuv/src/unix/timer.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "heap-inl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
static int timer_less_than(const struct heap_node* ha,
|
||||
const struct heap_node* hb) {
|
||||
const uv_timer_t* a;
|
||||
const uv_timer_t* b;
|
||||
|
||||
a = container_of(ha, uv_timer_t, heap_node);
|
||||
b = container_of(hb, uv_timer_t, heap_node);
|
||||
|
||||
if (a->timeout < b->timeout)
|
||||
return 1;
|
||||
if (b->timeout < a->timeout)
|
||||
return 0;
|
||||
|
||||
/* Compare start_id when both have the same timeout. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return 1;
|
||||
if (b->start_id < a->start_id)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
|
||||
handle->timer_cb = NULL;
|
||||
handle->repeat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_start(uv_timer_t* handle,
|
||||
uv_timer_cb cb,
|
||||
uint64_t timeout,
|
||||
uint64_t repeat) {
|
||||
uint64_t clamped_timeout;
|
||||
|
||||
if (cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
uv_timer_stop(handle);
|
||||
|
||||
clamped_timeout = handle->loop->time + timeout;
|
||||
if (clamped_timeout < timeout)
|
||||
clamped_timeout = (uint64_t) -1;
|
||||
|
||||
handle->timer_cb = cb;
|
||||
handle->timeout = clamped_timeout;
|
||||
handle->repeat = repeat;
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
heap_insert((struct heap*) &handle->loop->timer_heap,
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_stop(uv_timer_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
heap_remove((struct heap*) &handle->loop->timer_heap,
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_again(uv_timer_t* handle) {
|
||||
if (handle->timer_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (handle->repeat) {
|
||||
uv_timer_stop(handle);
|
||||
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
|
||||
handle->repeat = repeat;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
|
||||
int uv__next_timeout(const uv_loop_t* loop) {
|
||||
const struct heap_node* heap_node;
|
||||
const uv_timer_t* handle;
|
||||
uint64_t diff;
|
||||
|
||||
heap_node = heap_min((const struct heap*) &loop->timer_heap);
|
||||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
if (handle->timeout <= loop->time)
|
||||
return 0;
|
||||
|
||||
diff = handle->timeout - loop->time;
|
||||
if (diff > INT_MAX)
|
||||
diff = INT_MAX;
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
void uv__run_timers(uv_loop_t* loop) {
|
||||
struct heap_node* heap_node;
|
||||
uv_timer_t* handle;
|
||||
|
||||
for (;;) {
|
||||
heap_node = heap_min((struct heap*) &loop->timer_heap);
|
||||
if (heap_node == NULL)
|
||||
break;
|
||||
|
||||
handle = container_of(heap_node, uv_timer_t, heap_node);
|
||||
if (handle->timeout > loop->time)
|
||||
break;
|
||||
|
||||
uv_timer_stop(handle);
|
||||
uv_timer_again(handle);
|
||||
handle->timer_cb(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__timer_close(uv_timer_t* handle) {
|
||||
uv_timer_stop(handle);
|
||||
}
|
||||
336
Utilities/cmlibuv/src/unix/tty.c
Normal file
336
Utilities/cmlibuv/src/unix/tty.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__MVS__) && !defined(IMAXBEL)
|
||||
#define IMAXBEL 0
|
||||
#endif
|
||||
|
||||
static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
int dummy;
|
||||
|
||||
result = ioctl(fd, TIOCGPTN, &dummy) != 0;
|
||||
#elif defined(__APPLE__)
|
||||
char dummy[256];
|
||||
|
||||
result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
|
||||
#else
|
||||
/* Fallback to ptsname
|
||||
*/
|
||||
result = ptsname(fd) == NULL;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
uv_handle_type type;
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
int saved_flags;
|
||||
char path[256];
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
* That restriction also applies to character devices like /dev/random
|
||||
* (but obviously not /dev/tty.)
|
||||
*/
|
||||
type = uv_guess_handle(fd);
|
||||
if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
|
||||
return -EINVAL;
|
||||
|
||||
flags = 0;
|
||||
newfd = -1;
|
||||
|
||||
/* Reopen the file descriptor when it refers to a tty. This lets us put the
|
||||
* tty in non-blocking mode without affecting other processes that share it
|
||||
* with us.
|
||||
*
|
||||
* Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
|
||||
* affects fd 1 of `cat` because both file descriptors refer to the same
|
||||
* struct file in the kernel. When we reopen our fd 0, it points to a
|
||||
* different struct file, hence changing its properties doesn't affect
|
||||
* other processes.
|
||||
*/
|
||||
if (type == UV_TTY) {
|
||||
/* Reopening a pty in master mode won't work either because the reopened
|
||||
* pty will be in slave mode (*BSD) or reopening will allocate a new
|
||||
* master/slave pair (Linux). Therefore check if the fd points to a
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, O_RDWR);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
if (r < 0) {
|
||||
/* fallback to using blocking writes */
|
||||
if (!readable)
|
||||
flags |= UV_STREAM_BLOCKING;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
newfd = r;
|
||||
|
||||
r = uv__dup2_cloexec(newfd, fd);
|
||||
if (r < 0 && r != -EINVAL) {
|
||||
/* EINVAL means newfd == fd which could conceivably happen if another
|
||||
* thread called close(fd) between our calls to isatty() and open().
|
||||
* That's a rather unlikely event but let's handle it anyway.
|
||||
*/
|
||||
uv__close(newfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return -errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pacify the compiler. */
|
||||
(void) &saved_flags;
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
/* If anything fails beyond this point we need to remove the handle from
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
r = uv__stream_try_select((uv_stream_t*) tty, &fd);
|
||||
if (r) {
|
||||
int rc = r;
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
QUEUE_REMOVE(&tty->handle_queue);
|
||||
do
|
||||
r = fcntl(fd, F_SETFL, saved_flags);
|
||||
while (r == -1 && errno == EINTR);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (readable)
|
||||
flags |= UV_STREAM_READABLE;
|
||||
else
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__tty_make_raw(struct termios* tio) {
|
||||
assert(tio != NULL);
|
||||
|
||||
#if defined __sun || defined __MVS__
|
||||
/*
|
||||
* This implementation of cfmakeraw for Solaris and derivatives is taken from
|
||||
* http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
|
||||
*/
|
||||
tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
|
||||
IGNCR | ICRNL | IXON);
|
||||
tio->c_oflag &= ~OPOST;
|
||||
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tio->c_cflag &= ~(CSIZE | PARENB);
|
||||
tio->c_cflag |= CS8;
|
||||
#else
|
||||
cfmakeraw(tio);
|
||||
#endif /* #ifdef __sun */
|
||||
}
|
||||
|
||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
struct termios tmp;
|
||||
int fd;
|
||||
|
||||
if (tty->mode == (int) mode)
|
||||
return 0;
|
||||
|
||||
fd = uv__stream_fd(tty);
|
||||
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
|
||||
if (tcgetattr(fd, &tty->orig_termios))
|
||||
return -errno;
|
||||
|
||||
/* This is used for uv_tty_reset_mode() */
|
||||
uv_spinlock_lock(&termios_spinlock);
|
||||
if (orig_termios_fd == -1) {
|
||||
orig_termios = tty->orig_termios;
|
||||
orig_termios_fd = fd;
|
||||
}
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
}
|
||||
|
||||
tmp = tty->orig_termios;
|
||||
switch (mode) {
|
||||
case UV_TTY_MODE_NORMAL:
|
||||
break;
|
||||
case UV_TTY_MODE_RAW:
|
||||
tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
tmp.c_oflag |= (ONLCR);
|
||||
tmp.c_cflag |= (CS8);
|
||||
tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
||||
tmp.c_cc[VMIN] = 1;
|
||||
tmp.c_cc[VTIME] = 0;
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
uv__tty_make_raw(&tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Apply changes after draining */
|
||||
if (tcsetattr(fd, TCSADRAIN, &tmp))
|
||||
return -errno;
|
||||
|
||||
tty->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
struct winsize ws;
|
||||
int err;
|
||||
|
||||
do
|
||||
err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
|
||||
while (err == -1 && errno == EINTR);
|
||||
|
||||
if (err == -1)
|
||||
return -errno;
|
||||
|
||||
*width = ws.ws_col;
|
||||
*height = ws.ws_row;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uv_handle_type uv_guess_handle(uv_file file) {
|
||||
struct sockaddr sa;
|
||||
struct stat s;
|
||||
socklen_t len;
|
||||
int type;
|
||||
|
||||
if (file < 0)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (isatty(file))
|
||||
return UV_TTY;
|
||||
|
||||
if (fstat(file, &s))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (S_ISREG(s.st_mode))
|
||||
return UV_FILE;
|
||||
|
||||
if (S_ISCHR(s.st_mode))
|
||||
return UV_FILE; /* XXX UV_NAMED_PIPE? */
|
||||
|
||||
if (S_ISFIFO(s.st_mode))
|
||||
return UV_NAMED_PIPE;
|
||||
|
||||
if (!S_ISSOCK(s.st_mode))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(type);
|
||||
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(sa);
|
||||
if (getsockname(file, &sa, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (type == SOCK_DGRAM)
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_UDP;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
if (len == 0)
|
||||
return UV_NAMED_PIPE;
|
||||
#endif /* defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
return UV_TCP;
|
||||
if (sa.sa_family == AF_UNIX)
|
||||
return UV_NAMED_PIPE;
|
||||
}
|
||||
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
/* This function is async signal-safe, meaning that it's safe to call from
|
||||
* inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
|
||||
* critical section when the signal was raised.
|
||||
*/
|
||||
int uv_tty_reset_mode(void) {
|
||||
int saved_errno;
|
||||
int err;
|
||||
|
||||
saved_errno = errno;
|
||||
if (!uv_spinlock_trylock(&termios_spinlock))
|
||||
return -EBUSY; /* In uv_tty_set_mode(). */
|
||||
|
||||
err = 0;
|
||||
if (orig_termios_fd != -1)
|
||||
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
|
||||
err = -errno;
|
||||
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
errno = saved_errno;
|
||||
|
||||
return err;
|
||||
}
|
||||
895
Utilities/cmlibuv/src/unix/udp.c
Normal file
895
Utilities/cmlibuv/src/unix/udp.c
Normal file
@@ -0,0 +1,895 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__MVS__)
|
||||
#include <xti.h>
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
|
||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
|
||||
# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#endif
|
||||
|
||||
|
||||
static void uv__udp_run_completed(uv_udp_t* handle);
|
||||
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle);
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle);
|
||||
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
int domain,
|
||||
unsigned int flags);
|
||||
|
||||
|
||||
void uv__udp_close(uv_udp_t* handle) {
|
||||
uv__io_close(handle->loop, &handle->io_watcher);
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->io_watcher.fd != -1) {
|
||||
uv__close(handle->io_watcher.fd);
|
||||
handle->io_watcher.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__udp_finish_close(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
|
||||
assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
|
||||
assert(handle->io_watcher.fd == -1);
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
req->status = -ECANCELED;
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
|
||||
uv__udp_run_completed(handle);
|
||||
|
||||
assert(handle->send_queue_size == 0);
|
||||
assert(handle->send_queue_count == 0);
|
||||
|
||||
/* Now tear down the handle. */
|
||||
handle->recv_cb = NULL;
|
||||
handle->alloc_cb = NULL;
|
||||
/* but _do not_ touch close_cb */
|
||||
}
|
||||
|
||||
|
||||
static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
|
||||
assert(!(handle->flags & UV_UDP_PROCESSING));
|
||||
handle->flags |= UV_UDP_PROCESSING;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_completed_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
uv__req_unregister(handle->loop, req);
|
||||
|
||||
handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
|
||||
handle->send_queue_count--;
|
||||
|
||||
if (req->bufs != req->bufsml)
|
||||
uv__free(req->bufs);
|
||||
req->bufs = NULL;
|
||||
|
||||
if (req->send_cb == NULL)
|
||||
continue;
|
||||
|
||||
/* req->status >= 0 == bytes written
|
||||
* req->status < 0 == errno
|
||||
*/
|
||||
if (req->status >= 0)
|
||||
req->send_cb(req, 0);
|
||||
else
|
||||
req->send_cb(req, req->status);
|
||||
}
|
||||
|
||||
if (QUEUE_EMPTY(&handle->write_queue)) {
|
||||
/* Pending queue and completion queue empty, stop watcher. */
|
||||
uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
if (!uv__io_active(&handle->io_watcher, POLLIN))
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~UV_UDP_PROCESSING;
|
||||
}
|
||||
|
||||
|
||||
static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
|
||||
uv_udp_t* handle;
|
||||
|
||||
handle = container_of(w, uv_udp_t, io_watcher);
|
||||
assert(handle->type == UV_UDP);
|
||||
|
||||
if (revents & POLLIN)
|
||||
uv__udp_recvmsg(handle);
|
||||
|
||||
if (revents & POLLOUT) {
|
||||
uv__udp_sendmsg(handle);
|
||||
uv__udp_run_completed(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
struct sockaddr_storage peer;
|
||||
struct msghdr h;
|
||||
ssize_t nread;
|
||||
uv_buf_t buf;
|
||||
int flags;
|
||||
int count;
|
||||
|
||||
assert(handle->recv_cb != NULL);
|
||||
assert(handle->alloc_cb != NULL);
|
||||
|
||||
/* Prevent loop starvation when the data comes in as fast as (or faster than)
|
||||
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
|
||||
*/
|
||||
count = 32;
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
assert(buf.base != NULL);
|
||||
|
||||
h.msg_namelen = sizeof(peer);
|
||||
h.msg_iov = (void*) &buf;
|
||||
h.msg_iovlen = 1;
|
||||
|
||||
do {
|
||||
nread = recvmsg(handle->io_watcher.fd, &h, 0);
|
||||
}
|
||||
while (nread == -1 && errno == EINTR);
|
||||
|
||||
if (nread == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
handle->recv_cb(handle, 0, &buf, NULL, 0);
|
||||
else
|
||||
handle->recv_cb(handle, -errno, &buf, NULL, 0);
|
||||
}
|
||||
else {
|
||||
const struct sockaddr *addr;
|
||||
if (h.msg_namelen == 0)
|
||||
addr = NULL;
|
||||
else
|
||||
addr = (const struct sockaddr*) &peer;
|
||||
|
||||
flags = 0;
|
||||
if (h.msg_flags & MSG_TRUNC)
|
||||
flags |= UV_UDP_PARTIAL;
|
||||
|
||||
handle->recv_cb(handle, nread, &buf, addr, flags);
|
||||
}
|
||||
}
|
||||
/* recv_cb callback may decide to pause or close the handle */
|
||||
while (nread != -1
|
||||
&& count-- > 0
|
||||
&& handle->io_watcher.fd != -1
|
||||
&& handle->recv_cb != NULL);
|
||||
}
|
||||
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
struct msghdr h;
|
||||
ssize_t size;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
assert(q != NULL);
|
||||
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
h.msg_name = &req->addr;
|
||||
h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
|
||||
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
|
||||
h.msg_iov = (struct iovec*) req->bufs;
|
||||
h.msg_iovlen = req->nbufs;
|
||||
|
||||
do {
|
||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
||||
} while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||
break;
|
||||
|
||||
req->status = (size == -1 ? -errno : size);
|
||||
|
||||
/* Sending a datagram is an atomic operation: either all data
|
||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
||||
* why we don't handle partial writes. Just pop the request
|
||||
* off the write queue and onto the completed queue, done.
|
||||
*/
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||
* refinements for programs that use multicast.
|
||||
*
|
||||
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
|
||||
* are different from the BSDs: it _shares_ the port rather than steal it
|
||||
* from the current listener. While useful, it's not something we can emulate
|
||||
* on other platforms so we don't enable it.
|
||||
*/
|
||||
static int uv__set_reuse(int fd) {
|
||||
int yes;
|
||||
|
||||
#if defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
yes = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return -errno;
|
||||
#else
|
||||
yes = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
|
||||
return -errno;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags) {
|
||||
int err;
|
||||
int yes;
|
||||
int fd;
|
||||
|
||||
/* Check for bad flags. */
|
||||
if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
|
||||
return -EINVAL;
|
||||
|
||||
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
||||
if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
|
||||
return -EINVAL;
|
||||
|
||||
fd = handle->io_watcher.fd;
|
||||
if (fd == -1) {
|
||||
err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
fd = err;
|
||||
handle->io_watcher.fd = fd;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_REUSEADDR) {
|
||||
err = uv__set_reuse(fd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & UV_UDP_IPV6ONLY) {
|
||||
#ifdef IPV6_V6ONLY
|
||||
yes = 1;
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
err = -ENOTSUP;
|
||||
goto out;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (bind(fd, addr, addrlen)) {
|
||||
err = -errno;
|
||||
if (errno == EAFNOSUPPORT)
|
||||
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
|
||||
* socket created with AF_INET to an AF_INET6 address or vice versa. */
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET6)
|
||||
handle->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
uv__close(handle->io_watcher.fd);
|
||||
handle->io_watcher.fd = -1;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
int domain,
|
||||
unsigned int flags) {
|
||||
unsigned char taddr[sizeof(struct sockaddr_in6)];
|
||||
socklen_t addrlen;
|
||||
|
||||
if (handle->io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
switch (domain) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in* addr = (void*)&taddr;
|
||||
memset(addr, 0, sizeof *addr);
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_addr.s_addr = INADDR_ANY;
|
||||
addrlen = sizeof *addr;
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6* addr = (void*)&taddr;
|
||||
memset(addr, 0, sizeof *addr);
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_addr = in6addr_any;
|
||||
addrlen = sizeof *addr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
|
||||
return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags);
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_udp_send_cb send_cb) {
|
||||
int err;
|
||||
int empty_queue;
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* It's legal for send_queue_count > 0 even when the write_queue is empty;
|
||||
* it means there are error-state requests in the write_completed_queue that
|
||||
* will touch up send_queue_size/count later.
|
||||
*/
|
||||
empty_queue = (handle->send_queue_count == 0);
|
||||
|
||||
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
||||
assert(addrlen <= sizeof(req->addr));
|
||||
memcpy(&req->addr, addr, addrlen);
|
||||
req->send_cb = send_cb;
|
||||
req->handle = handle;
|
||||
req->nbufs = nbufs;
|
||||
|
||||
req->bufs = req->bufsml;
|
||||
if (nbufs > ARRAY_SIZE(req->bufsml))
|
||||
req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
|
||||
|
||||
if (req->bufs == NULL) {
|
||||
uv__req_unregister(handle->loop, req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
|
||||
handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
|
||||
handle->send_queue_count++;
|
||||
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
|
||||
uv__udp_sendmsg(handle);
|
||||
} else {
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen) {
|
||||
int err;
|
||||
struct msghdr h;
|
||||
ssize_t size;
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
/* already sending a message */
|
||||
if (handle->send_queue_count != 0)
|
||||
return -EAGAIN;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
h.msg_name = (struct sockaddr*) addr;
|
||||
h.msg_namelen = addrlen;
|
||||
h.msg_iov = (struct iovec*) bufs;
|
||||
h.msg_iovlen = nbufs;
|
||||
|
||||
do {
|
||||
size = sendmsg(handle->io_watcher.fd, &h, 0);
|
||||
} while (size == -1 && errno == EINTR);
|
||||
|
||||
if (size == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_membership4(uv_udp_t* handle,
|
||||
const struct sockaddr_in* multicast_addr,
|
||||
const char* interface_addr,
|
||||
uv_membership membership) {
|
||||
struct ip_mreq mreq;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
memset(&mreq, 0, sizeof mreq);
|
||||
|
||||
if (interface_addr) {
|
||||
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
||||
|
||||
switch (membership) {
|
||||
case UV_JOIN_GROUP:
|
||||
optname = IP_ADD_MEMBERSHIP;
|
||||
break;
|
||||
case UV_LEAVE_GROUP:
|
||||
optname = IP_DROP_MEMBERSHIP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IP,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
const struct sockaddr_in6* multicast_addr,
|
||||
const char* interface_addr,
|
||||
uv_membership membership) {
|
||||
int optname;
|
||||
struct ipv6_mreq mreq;
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
memset(&mreq, 0, sizeof mreq);
|
||||
|
||||
if (interface_addr) {
|
||||
if (uv_ip6_addr(interface_addr, 0, &addr6))
|
||||
return -EINVAL;
|
||||
mreq.ipv6mr_interface = addr6.sin6_scope_id;
|
||||
} else {
|
||||
mreq.ipv6mr_interface = 0;
|
||||
}
|
||||
|
||||
mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
|
||||
|
||||
switch (membership) {
|
||||
case UV_JOIN_GROUP:
|
||||
optname = IPV6_ADD_MEMBERSHIP;
|
||||
break;
|
||||
case UV_LEAVE_GROUP:
|
||||
optname = IPV6_DROP_MEMBERSHIP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
#if defined(__MVS__)
|
||||
if (errno == ENXIO)
|
||||
return -ENODEV;
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
int domain;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
/* Use the lower 8 bits for the domain */
|
||||
domain = flags & 0xFF;
|
||||
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & ~0xFF)
|
||||
return -EINVAL;
|
||||
|
||||
if (domain != AF_UNSPEC) {
|
||||
err = uv__socket(domain, SOCK_DGRAM, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
fd = err;
|
||||
} else {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
|
||||
handle->alloc_cb = NULL;
|
||||
handle->recv_cb = NULL;
|
||||
handle->send_queue_size = 0;
|
||||
handle->send_queue_count = 0;
|
||||
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
|
||||
QUEUE_INIT(&handle->write_queue);
|
||||
QUEUE_INIT(&handle->write_completed_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
return uv_udp_init_ex(loop, handle, AF_UNSPEC);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
int err;
|
||||
|
||||
/* Check for already active socket. */
|
||||
if (handle->io_watcher.fd != -1)
|
||||
return -EBUSY;
|
||||
|
||||
err = uv__nonblock(sock, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv__set_reuse(sock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
handle->io_watcher.fd = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
uv_membership membership) {
|
||||
int err;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
|
||||
if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
|
||||
} else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int uv__setsockopt(uv_udp_t* handle,
|
||||
int option4,
|
||||
int option6,
|
||||
const void* val,
|
||||
size_t size) {
|
||||
int r;
|
||||
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
r = setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
option6,
|
||||
val,
|
||||
size);
|
||||
else
|
||||
r = setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IP,
|
||||
option4,
|
||||
val,
|
||||
size);
|
||||
if (r)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__setsockopt_maybe_char(uv_udp_t* handle,
|
||||
int option4,
|
||||
int option6,
|
||||
int val) {
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
char arg = val;
|
||||
#elif defined(__OpenBSD__)
|
||||
unsigned char arg = val;
|
||||
#else
|
||||
int arg = val;
|
||||
#endif
|
||||
|
||||
if (val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
SOL_SOCKET,
|
||||
SO_BROADCAST,
|
||||
&on,
|
||||
sizeof(on))) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
if (ttl < 1 || ttl > 255)
|
||||
return -EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (!(handle->flags & UV_HANDLE_IPV6))
|
||||
return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On Solaris and derivatives such as SmartOS, the length of socket options
|
||||
* is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
|
||||
* so hardcode the size of these options on this platform,
|
||||
* and use the general uv__setsockopt_maybe_char call on other platforms.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
|
||||
return uv__setsockopt(handle,
|
||||
IP_TTL,
|
||||
IPV6_UNICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_TTL,
|
||||
IPV6_UNICAST_HOPS,
|
||||
ttl);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
/*
|
||||
* On Solaris and derivatives such as SmartOS, the length of socket options
|
||||
* is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
|
||||
* IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
ttl);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
/*
|
||||
* On Solaris and derivatives such as SmartOS, the length of socket options
|
||||
* is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
|
||||
* IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
on);
|
||||
}
|
||||
|
||||
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
|
||||
struct sockaddr_storage addr_st;
|
||||
struct sockaddr_in* addr4;
|
||||
struct sockaddr_in6* addr6;
|
||||
|
||||
addr4 = (struct sockaddr_in*) &addr_st;
|
||||
addr6 = (struct sockaddr_in6*) &addr_st;
|
||||
|
||||
if (!interface_addr) {
|
||||
memset(&addr_st, 0, sizeof addr_st);
|
||||
if (handle->flags & UV_HANDLE_IPV6) {
|
||||
addr_st.ss_family = AF_INET6;
|
||||
addr6->sin6_scope_id = 0;
|
||||
} else {
|
||||
addr_st.ss_family = AF_INET;
|
||||
addr4->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
} else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
|
||||
/* nothing, address was parsed */
|
||||
} else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
|
||||
/* nothing, address was parsed */
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (addr_st.ss_family == AF_INET) {
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IP,
|
||||
IP_MULTICAST_IF,
|
||||
(void*) &addr4->sin_addr,
|
||||
sizeof(addr4->sin_addr)) == -1) {
|
||||
return -errno;
|
||||
}
|
||||
} else if (addr_st.ss_family == AF_INET6) {
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
IPV6_MULTICAST_IF,
|
||||
&addr6->sin6_scope_id,
|
||||
sizeof(addr6->sin6_scope_id)) == -1) {
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
assert(0 && "unexpected address family");
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->io_watcher.fd == -1)
|
||||
return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getsockname(handle->io_watcher.fd, name, &socklen))
|
||||
return -errno;
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_recv_start(uv_udp_t* handle,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb) {
|
||||
int err;
|
||||
|
||||
if (alloc_cb == NULL || recv_cb == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (uv__io_active(&handle->io_watcher, POLLIN))
|
||||
return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
handle->alloc_cb = alloc_cb;
|
||||
handle->recv_cb = recv_cb;
|
||||
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_recv_stop(uv_udp_t* handle) {
|
||||
uv__io_stop(handle->loop, &handle->io_watcher, POLLIN);
|
||||
|
||||
if (!uv__io_active(&handle->io_watcher, POLLOUT))
|
||||
uv__handle_stop(handle);
|
||||
|
||||
handle->alloc_cb = NULL;
|
||||
handle->recv_cb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
654
Utilities/cmlibuv/src/uv-common.c
Normal file
654
Utilities/cmlibuv/src/uv-common.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <string.h> /* memset */
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <malloc.h> /* malloc */
|
||||
#else
|
||||
# include <net/if.h> /* if_nametoindex */
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
uv_malloc_func local_malloc;
|
||||
uv_realloc_func local_realloc;
|
||||
uv_calloc_func local_calloc;
|
||||
uv_free_func local_free;
|
||||
} uv__allocator_t;
|
||||
|
||||
static uv__allocator_t uv__allocator = {
|
||||
malloc,
|
||||
realloc,
|
||||
calloc,
|
||||
free,
|
||||
};
|
||||
|
||||
char* uv__strdup(const char* s) {
|
||||
size_t len = strlen(s) + 1;
|
||||
char* m = uv__malloc(len);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
return memcpy(m, s, len);
|
||||
}
|
||||
|
||||
char* uv__strndup(const char* s, size_t n) {
|
||||
char* m;
|
||||
size_t len = strlen(s);
|
||||
if (n < len)
|
||||
len = n;
|
||||
m = uv__malloc(len + 1);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
m[len] = '\0';
|
||||
return memcpy(m, s, len);
|
||||
}
|
||||
|
||||
void* uv__malloc(size_t size) {
|
||||
return uv__allocator.local_malloc(size);
|
||||
}
|
||||
|
||||
void uv__free(void* ptr) {
|
||||
int saved_errno;
|
||||
|
||||
/* Libuv expects that free() does not clobber errno. The system allocator
|
||||
* honors that assumption but custom allocators may not be so careful.
|
||||
*/
|
||||
saved_errno = errno;
|
||||
uv__allocator.local_free(ptr);
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
void* uv__calloc(size_t count, size_t size) {
|
||||
return uv__allocator.local_calloc(count, size);
|
||||
}
|
||||
|
||||
void* uv__realloc(void* ptr, size_t size) {
|
||||
return uv__allocator.local_realloc(ptr, size);
|
||||
}
|
||||
|
||||
int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
uv_realloc_func realloc_func,
|
||||
uv_calloc_func calloc_func,
|
||||
uv_free_func free_func) {
|
||||
if (malloc_func == NULL || realloc_func == NULL ||
|
||||
calloc_func == NULL || free_func == NULL) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv__allocator.local_malloc = malloc_func;
|
||||
uv__allocator.local_realloc = realloc_func;
|
||||
uv__allocator.local_calloc = calloc_func;
|
||||
uv__allocator.local_free = free_func;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
|
||||
|
||||
size_t uv_handle_size(uv_handle_type type) {
|
||||
switch (type) {
|
||||
UV_HANDLE_TYPE_MAP(XX)
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t uv_req_size(uv_req_type type) {
|
||||
switch(type) {
|
||||
UV_REQ_TYPE_MAP(XX)
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef XX
|
||||
|
||||
|
||||
size_t uv_loop_size(void) {
|
||||
return sizeof(uv_loop_t);
|
||||
}
|
||||
|
||||
|
||||
uv_buf_t uv_buf_init(char* base, unsigned int len) {
|
||||
uv_buf_t buf;
|
||||
buf.base = base;
|
||||
buf.len = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static const char* uv__unknown_err_code(int err) {
|
||||
char buf[32];
|
||||
char* copy;
|
||||
|
||||
snprintf(buf, sizeof(buf), "Unknown system error %d", err);
|
||||
copy = uv__strdup(buf);
|
||||
|
||||
return copy != NULL ? copy : "Unknown system error";
|
||||
}
|
||||
|
||||
|
||||
#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
|
||||
const char* uv_err_name(int err) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_ERR_NAME_GEN)
|
||||
}
|
||||
return uv__unknown_err_code(err);
|
||||
}
|
||||
#undef UV_ERR_NAME_GEN
|
||||
|
||||
|
||||
#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
|
||||
const char* uv_strerror(int err) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_STRERROR_GEN)
|
||||
}
|
||||
return uv__unknown_err_code(err);
|
||||
}
|
||||
#undef UV_STRERROR_GEN
|
||||
|
||||
|
||||
int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(port);
|
||||
return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
|
||||
}
|
||||
|
||||
|
||||
int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
|
||||
char address_part[40];
|
||||
size_t address_part_size;
|
||||
const char* zone_index;
|
||||
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(port);
|
||||
|
||||
zone_index = strchr(ip, '%');
|
||||
if (zone_index != NULL) {
|
||||
address_part_size = zone_index - ip;
|
||||
if (address_part_size >= sizeof(address_part))
|
||||
address_part_size = sizeof(address_part) - 1;
|
||||
|
||||
memcpy(address_part, ip, address_part_size);
|
||||
address_part[address_part_size] = '\0';
|
||||
ip = address_part;
|
||||
|
||||
zone_index++; /* skip '%' */
|
||||
/* NOTE: unknown interface (id=0) is silently ignored */
|
||||
#ifdef _WIN32
|
||||
addr->sin6_scope_id = atoi(zone_index);
|
||||
#else
|
||||
addr->sin6_scope_id = if_nametoindex(zone_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
|
||||
}
|
||||
|
||||
|
||||
int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
|
||||
return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
|
||||
}
|
||||
|
||||
|
||||
int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
|
||||
return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_bind(uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int flags) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_TCP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__tcp_bind(handle, addr, addrlen, flags);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int flags) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__udp_bind(handle, addr, addrlen, flags);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
uv_connect_cb cb) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_TCP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__tcp_connect(req, handle, addr, addrlen, cb);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
uv_udp_send_cb send_cb) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_recv_start(uv_udp_t* handle,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb) {
|
||||
if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
return uv__udp_recv_start(handle, alloc_cb, recv_cb);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_recv_stop(uv_udp_t* handle) {
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
return uv__udp_recv_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
QUEUE queue;
|
||||
QUEUE* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
QUEUE_MOVE(&loop->handle_queue, &queue);
|
||||
while (!QUEUE_EMPTY(&queue)) {
|
||||
q = QUEUE_HEAD(&queue);
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
|
||||
|
||||
if (h->flags & UV__HANDLE_INTERNAL) continue;
|
||||
walk_cb(h, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
|
||||
const char* type;
|
||||
QUEUE* q;
|
||||
uv_handle_t* h;
|
||||
|
||||
if (loop == NULL)
|
||||
loop = uv_default_loop();
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
|
||||
if (only_active && !uv__is_active(h))
|
||||
continue;
|
||||
|
||||
switch (h->type) {
|
||||
#define X(uc, lc) case UV_##uc: type = #lc; break;
|
||||
UV_HANDLE_TYPE_MAP(X)
|
||||
#undef X
|
||||
default: type = "<unknown>";
|
||||
}
|
||||
|
||||
fprintf(stream,
|
||||
"[%c%c%c] %-8s %p\n",
|
||||
"R-"[!(h->flags & UV__HANDLE_REF)],
|
||||
"A-"[!(h->flags & UV__HANDLE_ACTIVE)],
|
||||
"I-"[!(h->flags & UV__HANDLE_INTERNAL)],
|
||||
type,
|
||||
(void*)h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
|
||||
uv__print_handles(loop, 0, stream);
|
||||
}
|
||||
|
||||
|
||||
void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
|
||||
uv__print_handles(loop, 1, stream);
|
||||
}
|
||||
|
||||
|
||||
void uv_ref(uv_handle_t* handle) {
|
||||
uv__handle_ref(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_unref(uv_handle_t* handle) {
|
||||
uv__handle_unref(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_has_ref(const uv_handle_t* handle) {
|
||||
return uv__has_ref(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_stop(uv_loop_t* loop) {
|
||||
loop->stop_flag = 1;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_now(const uv_loop_t* loop) {
|
||||
return loop->time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
|
||||
unsigned int i;
|
||||
size_t bytes;
|
||||
|
||||
bytes = 0;
|
||||
for (i = 0; i < nbufs; i++)
|
||||
bytes += (size_t) bufs[i].len;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
|
||||
return uv__socket_sockopt(handle, SO_RCVBUF, value);
|
||||
}
|
||||
|
||||
int uv_send_buffer_size(uv_handle_t* handle, int *value) {
|
||||
return uv__socket_sockopt(handle, SO_SNDBUF, value);
|
||||
}
|
||||
|
||||
int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
|
||||
size_t required_len;
|
||||
|
||||
if (!uv__is_active(handle)) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
required_len = strlen(handle->path);
|
||||
if (required_len >= *size) {
|
||||
*size = required_len + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, handle->path, required_len);
|
||||
*size = required_len;
|
||||
buffer[required_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The windows implementation does not have the same structure layout as
|
||||
* the unix implementation (nbufs is not directly inside req but is
|
||||
* contained in a nested union/struct) so this function locates it.
|
||||
*/
|
||||
static unsigned int* uv__get_nbufs(uv_fs_t* req) {
|
||||
#ifdef _WIN32
|
||||
return &req->fs.info.nbufs;
|
||||
#else
|
||||
return &req->nbufs;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
|
||||
* systems. So, the memory should be released using free(). On Windows,
|
||||
* uv__malloc() is used, so use uv__free() to free memory.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
# define uv__fs_scandir_free uv__free
|
||||
#else
|
||||
# define uv__fs_scandir_free free
|
||||
#endif
|
||||
|
||||
void uv__fs_scandir_cleanup(uv_fs_t* req) {
|
||||
uv__dirent_t** dents;
|
||||
|
||||
unsigned int* nbufs = uv__get_nbufs(req);
|
||||
|
||||
dents = req->ptr;
|
||||
if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
|
||||
(*nbufs)--;
|
||||
for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
|
||||
uv__fs_scandir_free(dents[*nbufs]);
|
||||
|
||||
uv__fs_scandir_free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
|
||||
uv__dirent_t** dents;
|
||||
uv__dirent_t* dent;
|
||||
|
||||
unsigned int* nbufs = uv__get_nbufs(req);
|
||||
|
||||
dents = req->ptr;
|
||||
|
||||
/* Free previous entity */
|
||||
if (*nbufs > 0)
|
||||
uv__fs_scandir_free(dents[*nbufs - 1]);
|
||||
|
||||
/* End was already reached */
|
||||
if (*nbufs == (unsigned int) req->result) {
|
||||
uv__fs_scandir_free(dents);
|
||||
req->ptr = NULL;
|
||||
return UV_EOF;
|
||||
}
|
||||
|
||||
dent = dents[(*nbufs)++];
|
||||
|
||||
ent->name = dent->d_name;
|
||||
#ifdef HAVE_DIRENT_TYPES
|
||||
switch (dent->d_type) {
|
||||
case UV__DT_DIR:
|
||||
ent->type = UV_DIRENT_DIR;
|
||||
break;
|
||||
case UV__DT_FILE:
|
||||
ent->type = UV_DIRENT_FILE;
|
||||
break;
|
||||
case UV__DT_LINK:
|
||||
ent->type = UV_DIRENT_LINK;
|
||||
break;
|
||||
case UV__DT_FIFO:
|
||||
ent->type = UV_DIRENT_FIFO;
|
||||
break;
|
||||
case UV__DT_SOCKET:
|
||||
ent->type = UV_DIRENT_SOCKET;
|
||||
break;
|
||||
case UV__DT_CHAR:
|
||||
ent->type = UV_DIRENT_CHAR;
|
||||
break;
|
||||
case UV__DT_BLOCK:
|
||||
ent->type = UV_DIRENT_BLOCK;
|
||||
break;
|
||||
default:
|
||||
ent->type = UV_DIRENT_UNKNOWN;
|
||||
}
|
||||
#else
|
||||
ent->type = UV_DIRENT_UNKNOWN;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
|
||||
va_list ap;
|
||||
int err;
|
||||
|
||||
va_start(ap, option);
|
||||
/* Any platform-agnostic options should be handled here. */
|
||||
err = uv__loop_configure(loop, option, ap);
|
||||
va_end(ap);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static uv_loop_t default_loop_struct;
|
||||
static uv_loop_t* default_loop_ptr;
|
||||
|
||||
|
||||
uv_loop_t* uv_default_loop(void) {
|
||||
if (default_loop_ptr != NULL)
|
||||
return default_loop_ptr;
|
||||
|
||||
if (uv_loop_init(&default_loop_struct))
|
||||
return NULL;
|
||||
|
||||
default_loop_ptr = &default_loop_struct;
|
||||
return default_loop_ptr;
|
||||
}
|
||||
|
||||
|
||||
uv_loop_t* uv_loop_new(void) {
|
||||
uv_loop_t* loop;
|
||||
|
||||
loop = uv__malloc(sizeof(*loop));
|
||||
if (loop == NULL)
|
||||
return NULL;
|
||||
|
||||
if (uv_loop_init(loop)) {
|
||||
uv__free(loop);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return loop;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_close(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
uv_handle_t* h;
|
||||
#ifndef NDEBUG
|
||||
void* saved_data;
|
||||
#endif
|
||||
|
||||
if (!QUEUE_EMPTY(&(loop)->active_reqs))
|
||||
return UV_EBUSY;
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
if (!(h->flags & UV__HANDLE_INTERNAL))
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
uv__loop_close(loop);
|
||||
|
||||
#ifndef NDEBUG
|
||||
saved_data = loop->data;
|
||||
memset(loop, -1, sizeof(*loop));
|
||||
loop->data = saved_data;
|
||||
#endif
|
||||
if (loop == default_loop_ptr)
|
||||
default_loop_ptr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_loop_delete(uv_loop_t* loop) {
|
||||
uv_loop_t* default_loop;
|
||||
int err;
|
||||
|
||||
default_loop = default_loop_ptr;
|
||||
|
||||
err = uv_loop_close(loop);
|
||||
(void) err; /* Squelch compiler warnings. */
|
||||
assert(err == 0);
|
||||
if (loop != default_loop)
|
||||
uv__free(loop);
|
||||
}
|
||||
227
Utilities/cmlibuv/src/uv-common.h
Normal file
227
Utilities/cmlibuv/src/uv-common.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is private to libuv. It provides common functionality to both
|
||||
* Windows and Unix backends.
|
||||
*/
|
||||
|
||||
#ifndef UV_COMMON_H_
|
||||
#define UV_COMMON_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "queue.h"
|
||||
|
||||
#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
|
||||
extern int snprintf(char*, size_t, const char*, ...);
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *) ((char *) (ptr) - offsetof(type, member)))
|
||||
|
||||
#define STATIC_ASSERT(expr) \
|
||||
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
|
||||
|
||||
#ifndef _WIN32
|
||||
enum {
|
||||
UV__HANDLE_INTERNAL = 0x8000,
|
||||
UV__HANDLE_ACTIVE = 0x4000,
|
||||
UV__HANDLE_REF = 0x2000,
|
||||
UV__HANDLE_CLOSING = 0 /* no-op on unix */
|
||||
};
|
||||
#else
|
||||
# define UV__HANDLE_INTERNAL 0x80
|
||||
# define UV__HANDLE_ACTIVE 0x40
|
||||
# define UV__HANDLE_REF 0x20
|
||||
# define UV__HANDLE_CLOSING 0x01
|
||||
#endif
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|
||||
|
||||
void uv__loop_close(uv_loop_t* loop);
|
||||
|
||||
int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags);
|
||||
|
||||
int uv__tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_connect_cb cb);
|
||||
|
||||
int uv__udp_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags);
|
||||
|
||||
int uv__udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen,
|
||||
uv_udp_send_cb send_cb);
|
||||
|
||||
int uv__udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen);
|
||||
|
||||
int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
|
||||
uv_udp_recv_cb recv_cb);
|
||||
|
||||
int uv__udp_recv_stop(uv_udp_t* handle);
|
||||
|
||||
void uv__fs_poll_close(uv_fs_poll_t* handle);
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work *w,
|
||||
void (*work)(struct uv__work *w),
|
||||
void (*done)(struct uv__work *w, int status));
|
||||
|
||||
void uv__work_done(uv_async_t* handle);
|
||||
|
||||
size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
|
||||
|
||||
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
|
||||
|
||||
void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
|
||||
#define uv__has_active_reqs(loop) \
|
||||
(QUEUE_EMPTY(&(loop)->active_reqs) == 0)
|
||||
|
||||
#define uv__req_register(loop, req) \
|
||||
do { \
|
||||
QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__req_unregister(loop, req) \
|
||||
do { \
|
||||
assert(uv__has_active_reqs(loop)); \
|
||||
QUEUE_REMOVE(&(req)->active_queue); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__has_active_handles(loop) \
|
||||
((loop)->active_handles > 0)
|
||||
|
||||
#define uv__active_handle_add(h) \
|
||||
do { \
|
||||
(h)->loop->active_handles++; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__active_handle_rm(h) \
|
||||
do { \
|
||||
(h)->loop->active_handles--; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__is_active(h) \
|
||||
(((h)->flags & UV__HANDLE_ACTIVE) != 0)
|
||||
|
||||
#define uv__is_closing(h) \
|
||||
(((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
|
||||
|
||||
#define uv__handle_start(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_stop(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_ref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_unref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__has_ref(h) \
|
||||
(((h)->flags & UV__HANDLE_REF) != 0)
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define uv__handle_platform_init(h) ((h)->u.fd = -1)
|
||||
#else
|
||||
# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
|
||||
#endif
|
||||
|
||||
#define uv__handle_init(loop_, h, type_) \
|
||||
do { \
|
||||
(h)->loop = (loop_); \
|
||||
(h)->type = (type_); \
|
||||
(h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
|
||||
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
|
||||
uv__handle_platform_init(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
/* Allocator prototypes */
|
||||
void *uv__calloc(size_t count, size_t size);
|
||||
char *uv__strdup(const char* s);
|
||||
char *uv__strndup(const char* s, size_t n);
|
||||
void* uv__malloc(size_t size);
|
||||
void uv__free(void* ptr);
|
||||
void* uv__realloc(void* ptr, size_t size);
|
||||
|
||||
#endif /* UV_COMMON_H_ */
|
||||
45
Utilities/cmlibuv/src/version.c
Normal file
45
Utilities/cmlibuv/src/version.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
|
||||
#define UV_STRINGIFY_HELPER(v) #v
|
||||
|
||||
#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
|
||||
UV_STRINGIFY(UV_VERSION_MINOR) "." \
|
||||
UV_STRINGIFY(UV_VERSION_PATCH)
|
||||
|
||||
#if UV_VERSION_IS_RELEASE
|
||||
# define UV_VERSION_STRING UV_VERSION_STRING_BASE
|
||||
#else
|
||||
# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
|
||||
#endif
|
||||
|
||||
|
||||
unsigned int uv_version(void) {
|
||||
return UV_VERSION_HEX;
|
||||
}
|
||||
|
||||
|
||||
const char* uv_version_string(void) {
|
||||
return UV_VERSION_STRING;
|
||||
}
|
||||
99
Utilities/cmlibuv/src/win/async.c
Normal file
99
Utilities/cmlibuv/src/win/async.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "atomicops-inl.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
!handle->async_sent) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
uv_req_t* req;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
|
||||
handle->async_sent = 0;
|
||||
handle->async_cb = async_cb;
|
||||
|
||||
req = &handle->async_req;
|
||||
uv_req_init(loop, req);
|
||||
req->type = UV_WAKEUP;
|
||||
req->data = handle;
|
||||
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
|
||||
if (!((uv_async_t*)handle)->async_sent) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
uv__handle_closing(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_async_send(uv_async_t* handle) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (handle->type != UV_ASYNC) {
|
||||
/* Can't set errno because that's not thread-safe. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The user should make sure never to call uv_async_send to a closing */
|
||||
/* or closed handle. */
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
|
||||
if (!uv__atomic_exchange_set(&handle->async_sent)) {
|
||||
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
|
||||
uv_req_t* req) {
|
||||
assert(handle->type == UV_ASYNC);
|
||||
assert(req->type == UV_WAKEUP);
|
||||
|
||||
handle->async_sent = 0;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (handle->async_cb != NULL) {
|
||||
handle->async_cb(handle);
|
||||
}
|
||||
}
|
||||
56
Utilities/cmlibuv/src/win/atomicops-inl.h
Normal file
56
Utilities/cmlibuv/src/win/atomicops-inl.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_WIN_ATOMICOPS_INL_H_
|
||||
#define UV_WIN_ATOMICOPS_INL_H_
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
|
||||
/* Atomic set operation on char */
|
||||
#ifdef _MSC_VER /* MSVC */
|
||||
|
||||
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
|
||||
/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
|
||||
/* exist, and interlocked operations on larger targets might require the */
|
||||
/* target to be aligned. */
|
||||
#pragma intrinsic(_InterlockedOr8)
|
||||
|
||||
static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
|
||||
return _InterlockedOr8(target, 1);
|
||||
}
|
||||
|
||||
#else /* GCC */
|
||||
|
||||
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
|
||||
static inline char uv__atomic_exchange_set(char volatile* target) {
|
||||
const char one = 1;
|
||||
char old_value;
|
||||
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
|
||||
: "=r"(old_value), "=m"(*target)
|
||||
: "0"(one), "m"(*target)
|
||||
: "memory");
|
||||
return old_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* UV_WIN_ATOMICOPS_INL_H_ */
|
||||
602
Utilities/cmlibuv/src/win/core.c
Normal file
602
Utilities/cmlibuv/src/win/core.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
static uv_loop_t default_loop_struct;
|
||||
static uv_loop_t* default_loop_ptr;
|
||||
|
||||
/* uv_once initialization guards */
|
||||
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
|
||||
|
||||
|
||||
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
|
||||
/* Our crt debug report handler allows us to temporarily disable asserts
|
||||
* just for the current thread.
|
||||
*/
|
||||
|
||||
UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
|
||||
|
||||
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
|
||||
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
|
||||
return FALSE;
|
||||
|
||||
if (ret_val) {
|
||||
/* Set ret_val to 0 to continue with normal execution.
|
||||
* Set ret_val to 1 to trigger a breakpoint.
|
||||
*/
|
||||
|
||||
if(IsDebuggerPresent())
|
||||
*ret_val = 1;
|
||||
else
|
||||
*ret_val = 0;
|
||||
}
|
||||
|
||||
/* Don't call _CrtDbgReport. */
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
|
||||
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
||||
const wchar_t* function, const wchar_t * file, unsigned int line,
|
||||
uintptr_t reserved) {
|
||||
/* No-op. */
|
||||
}
|
||||
#endif
|
||||
|
||||
static uv_loop_t** uv__loops;
|
||||
static int uv__loops_size;
|
||||
static int uv__loops_capacity;
|
||||
#define UV__LOOPS_CHUNK_SIZE 8
|
||||
static uv_mutex_t uv__loops_lock;
|
||||
|
||||
static void uv__loops_init() {
|
||||
uv_mutex_init(&uv__loops_lock);
|
||||
uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
|
||||
if (!uv__loops)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
uv__loops_size = 0;
|
||||
uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static int uv__loops_add(uv_loop_t* loop) {
|
||||
uv_loop_t** new_loops;
|
||||
int new_capacity, i;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
if (uv__loops_size == uv__loops_capacity) {
|
||||
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
|
||||
if (!new_loops)
|
||||
goto failed_loops_realloc;
|
||||
uv__loops = new_loops;
|
||||
for (i = uv__loops_capacity; i < new_capacity; ++i)
|
||||
uv__loops[i] = NULL;
|
||||
uv__loops_capacity = new_capacity;
|
||||
}
|
||||
uv__loops[uv__loops_size] = loop;
|
||||
++uv__loops_size;
|
||||
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return 0;
|
||||
|
||||
failed_loops_realloc:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
uv_loop_t** new_loops;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
|
||||
if (uv__loops[loop_index] == loop)
|
||||
break;
|
||||
}
|
||||
/* If loop was not found, ignore */
|
||||
if (loop_index == uv__loops_size)
|
||||
goto loop_removed;
|
||||
|
||||
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
|
||||
uv__loops[uv__loops_size - 1] = NULL;
|
||||
--uv__loops_size;
|
||||
|
||||
/* If we didn't grow to big skip downsizing */
|
||||
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
|
||||
goto loop_removed;
|
||||
|
||||
/* Downsize only if more than half of buffer is free */
|
||||
smaller_capacity = uv__loops_capacity / 2;
|
||||
if (uv__loops_size >= smaller_capacity)
|
||||
goto loop_removed;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
|
||||
if (!new_loops)
|
||||
goto loop_removed;
|
||||
uv__loops = new_loops;
|
||||
uv__loops_capacity = smaller_capacity;
|
||||
|
||||
loop_removed:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
void uv__wake_all_loops() {
|
||||
int i;
|
||||
uv_loop_t* loop;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
for (i = 0; i < uv__loops_size; ++i) {
|
||||
loop = uv__loops[i];
|
||||
assert(loop);
|
||||
if (loop->iocp != INVALID_HANDLE_VALUE)
|
||||
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
|
||||
}
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
static void uv_init(void) {
|
||||
/* Tell Windows that we will handle critical errors. */
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
|
||||
SEM_NOOPENFILEERRORBOX);
|
||||
|
||||
/* Tell the CRT to not exit the application when an invalid parameter is
|
||||
* passed. The main issue is that invalid FDs will trigger this behavior.
|
||||
*/
|
||||
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
|
||||
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
|
||||
#endif
|
||||
|
||||
/* We also need to setup our debug report handler because some CRT
|
||||
* functions (eg _get_osfhandle) raise an assert when called with invalid
|
||||
* FDs even though they return the proper error code in the release build.
|
||||
*/
|
||||
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
|
||||
_CrtSetReportHook(uv__crt_dbg_report_handler);
|
||||
#endif
|
||||
|
||||
/* Initialize tracking of all uv loops */
|
||||
uv__loops_init();
|
||||
|
||||
/* Fetch winapi function pointers. This must be done first because other
|
||||
* initialization code might need these function pointers to be loaded.
|
||||
*/
|
||||
uv_winapi_init();
|
||||
|
||||
/* Initialize winsock */
|
||||
uv_winsock_init();
|
||||
|
||||
/* Initialize FS */
|
||||
uv_fs_init();
|
||||
|
||||
/* Initialize signal stuff */
|
||||
uv_signals_init();
|
||||
|
||||
/* Initialize console */
|
||||
uv_console_init();
|
||||
|
||||
/* Initialize utilities */
|
||||
uv__util_init();
|
||||
|
||||
/* Initialize system wakeup detection */
|
||||
uv__init_detect_system_wakeup();
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
int err;
|
||||
|
||||
/* Initialize libuv itself first */
|
||||
uv__once_init();
|
||||
|
||||
/* Create an I/O completion port */
|
||||
loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
|
||||
if (loop->iocp == NULL)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
/* To prevent uninitialized memory access, loop->time must be initialized
|
||||
* to zero before calling uv_update_time for the first time.
|
||||
*/
|
||||
loop->time = 0;
|
||||
uv_update_time(loop);
|
||||
|
||||
QUEUE_INIT(&loop->wq);
|
||||
QUEUE_INIT(&loop->handle_queue);
|
||||
QUEUE_INIT(&loop->active_reqs);
|
||||
loop->active_handles = 0;
|
||||
|
||||
loop->pending_reqs_tail = NULL;
|
||||
|
||||
loop->endgame_handles = NULL;
|
||||
|
||||
RB_INIT(&loop->timers);
|
||||
|
||||
loop->check_handles = NULL;
|
||||
loop->prepare_handles = NULL;
|
||||
loop->idle_handles = NULL;
|
||||
|
||||
loop->next_prepare_handle = NULL;
|
||||
loop->next_check_handle = NULL;
|
||||
loop->next_idle_handle = NULL;
|
||||
|
||||
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
|
||||
|
||||
loop->active_tcp_streams = 0;
|
||||
loop->active_udp_streams = 0;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
loop->stop_flag = 0;
|
||||
|
||||
err = uv_mutex_init(&loop->wq_mutex);
|
||||
if (err)
|
||||
goto fail_mutex_init;
|
||||
|
||||
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
CloseHandle(loop->iocp);
|
||||
loop->iocp = INVALID_HANDLE_VALUE;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void uv__once_init(void) {
|
||||
uv_once(&uv_init_guard_, uv_init);
|
||||
}
|
||||
|
||||
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
size_t i;
|
||||
|
||||
uv__loops_remove(loop);
|
||||
|
||||
/* close the async handle without needing an extra loop iteration */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
loop->wq_async.close_cb = NULL;
|
||||
uv__handle_closing(&loop->wq_async);
|
||||
uv__handle_close(&loop->wq_async);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
|
||||
SOCKET sock = loop->poll_peer_sockets[i];
|
||||
if (sock != 0 && sock != INVALID_SOCKET)
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
uv_mutex_lock(&loop->wq_mutex);
|
||||
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
|
||||
assert(!uv__has_active_reqs(loop));
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
CloseHandle(loop->iocp);
|
||||
}
|
||||
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int uv_backend_fd(const uv_loop_t* loop) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
if (loop->stop_flag != 0)
|
||||
return 0;
|
||||
|
||||
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
|
||||
return 0;
|
||||
|
||||
if (loop->pending_reqs_tail)
|
||||
return 0;
|
||||
|
||||
if (loop->endgame_handles)
|
||||
return 0;
|
||||
|
||||
if (loop->idle_handles)
|
||||
return 0;
|
||||
|
||||
return uv__next_timeout(loop);
|
||||
}
|
||||
|
||||
|
||||
static void uv_poll(uv_loop_t* loop, DWORD timeout) {
|
||||
DWORD bytes;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* overlapped;
|
||||
uv_req_t* req;
|
||||
int repeat;
|
||||
uint64_t timeout_time;
|
||||
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
GetQueuedCompletionStatus(loop->iocp,
|
||||
&bytes,
|
||||
&key,
|
||||
&overlapped,
|
||||
timeout);
|
||||
|
||||
if (overlapped) {
|
||||
/* Package was dequeued */
|
||||
req = uv_overlapped_to_req(overlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
* so update the loop time here.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
} else if (GetLastError() != WAIT_TIMEOUT) {
|
||||
/* Serious error */
|
||||
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
|
||||
} else if (timeout > 0) {
|
||||
/* GetQueuedCompletionStatus can occasionally return a little early.
|
||||
* Make sure that the desired timeout target time is reached.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
if (timeout_time > loop->time) {
|
||||
timeout = (DWORD)(timeout_time - loop->time);
|
||||
/* The first call to GetQueuedCompletionStatus should return very
|
||||
* close to the target time and the second should reach it, but
|
||||
* this is not stated in the documentation. To make sure a busy
|
||||
* loop cannot happen, the timeout is increased exponentially
|
||||
* starting on the third round.
|
||||
*/
|
||||
timeout += repeat ? (1 << (repeat - 1)) : 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
|
||||
BOOL success;
|
||||
uv_req_t* req;
|
||||
OVERLAPPED_ENTRY overlappeds[128];
|
||||
ULONG count;
|
||||
ULONG i;
|
||||
int repeat;
|
||||
uint64_t timeout_time;
|
||||
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Package was dequeued, but see if it is not a empty package
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
* so update the loop time here.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
} else if (GetLastError() != WAIT_TIMEOUT) {
|
||||
/* Serious error */
|
||||
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
|
||||
} else if (timeout > 0) {
|
||||
/* GetQueuedCompletionStatus can occasionally return a little early.
|
||||
* Make sure that the desired timeout target time is reached.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
if (timeout_time > loop->time) {
|
||||
timeout = (DWORD)(timeout_time - loop->time);
|
||||
/* The first call to GetQueuedCompletionStatus should return very
|
||||
* close to the target time and the second should reach it, but
|
||||
* this is not stated in the documentation. To make sure a busy
|
||||
* loop cannot happen, the timeout is increased exponentially
|
||||
* starting on the third round.
|
||||
*/
|
||||
timeout += repeat ? (1 << (repeat - 1)) : 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__loop_alive(const uv_loop_t* loop) {
|
||||
return loop->active_handles > 0 ||
|
||||
!QUEUE_EMPTY(&loop->active_reqs) ||
|
||||
loop->endgame_handles != NULL;
|
||||
}
|
||||
|
||||
|
||||
int uv_loop_alive(const uv_loop_t* loop) {
|
||||
return uv__loop_alive(loop);
|
||||
}
|
||||
|
||||
|
||||
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
DWORD timeout;
|
||||
int r;
|
||||
int ran_pending;
|
||||
void (*poll)(uv_loop_t* loop, DWORD timeout);
|
||||
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
poll = &uv_poll_ex;
|
||||
else
|
||||
poll = &uv_poll;
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (!r)
|
||||
uv_update_time(loop);
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
uv_update_time(loop);
|
||||
uv_process_timers(loop);
|
||||
|
||||
ran_pending = uv_process_reqs(loop);
|
||||
uv_idle_invoke(loop);
|
||||
uv_prepare_invoke(loop);
|
||||
|
||||
timeout = 0;
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
|
||||
(*poll)(loop, timeout);
|
||||
|
||||
uv_check_invoke(loop);
|
||||
uv_process_endgames(loop);
|
||||
|
||||
if (mode == UV_RUN_ONCE) {
|
||||
/* UV_RUN_ONCE implies forward progress: at least one callback must have
|
||||
* been invoked when it returns. uv__io_poll() can return without doing
|
||||
* I/O (meaning: no callbacks) when its timeout expires - which means we
|
||||
* have pending timers that satisfy the forward progress constraint.
|
||||
*
|
||||
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
|
||||
* the check.
|
||||
*/
|
||||
uv_process_timers(loop);
|
||||
}
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
|
||||
break;
|
||||
}
|
||||
|
||||
/* The if statement lets the compiler compile it to a conditional store.
|
||||
* Avoids dirtying a cache line.
|
||||
*/
|
||||
if (loop->stop_flag != 0)
|
||||
loop->stop_flag = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
|
||||
uv_os_fd_t fd_out;
|
||||
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
fd_out = ((uv_pipe_t*) handle)->handle;
|
||||
break;
|
||||
|
||||
case UV_TTY:
|
||||
fd_out = ((uv_tty_t*) handle)->handle;
|
||||
break;
|
||||
|
||||
case UV_UDP:
|
||||
fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
|
||||
break;
|
||||
|
||||
case UV_POLL:
|
||||
fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
|
||||
break;
|
||||
|
||||
default:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
|
||||
return UV_EBADF;
|
||||
|
||||
*fd = fd_out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
|
||||
int r;
|
||||
int len;
|
||||
SOCKET socket;
|
||||
|
||||
if (handle == NULL || value == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (handle->type == UV_TCP)
|
||||
socket = ((uv_tcp_t*) handle)->socket;
|
||||
else if (handle->type == UV_UDP)
|
||||
socket = ((uv_udp_t*) handle)->socket;
|
||||
else
|
||||
return UV_ENOTSUP;
|
||||
|
||||
len = sizeof(*value);
|
||||
|
||||
if (*value == 0)
|
||||
r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
|
||||
else
|
||||
r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
|
||||
|
||||
if (r == SOCKET_ERROR)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
Utilities/cmlibuv/src/win/detect-wakeup.c
Normal file
35
Utilities/cmlibuv/src/win/detect-wakeup.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "winapi.h"
|
||||
|
||||
static void uv__register_system_resume_callback();
|
||||
|
||||
void uv__init_detect_system_wakeup() {
|
||||
/* Try registering system power event callback. This is the cleanest
|
||||
* method, but it will only work on Win8 and above.
|
||||
*/
|
||||
uv__register_system_resume_callback();
|
||||
}
|
||||
|
||||
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting) {
|
||||
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
|
||||
uv__wake_all_loops();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__register_system_resume_callback() {
|
||||
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
|
||||
_HPOWERNOTIFY registration_handle;
|
||||
|
||||
if (pPowerRegisterSuspendResumeNotification == NULL)
|
||||
return;
|
||||
|
||||
recipient.Callback = uv__system_resume_callback;
|
||||
recipient.Context = NULL;
|
||||
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
|
||||
&recipient,
|
||||
®istration_handle);
|
||||
}
|
||||
118
Utilities/cmlibuv/src/win/dl.c
Normal file
118
Utilities/cmlibuv/src/win/dl.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib, int errorno);
|
||||
|
||||
|
||||
int uv_dlopen(const char* filename, uv_lib_t* lib) {
|
||||
WCHAR filename_w[32768];
|
||||
|
||||
lib->handle = NULL;
|
||||
lib->errmsg = NULL;
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
filename,
|
||||
-1,
|
||||
filename_w,
|
||||
ARRAY_SIZE(filename_w))) {
|
||||
return uv__dlerror(lib, GetLastError());
|
||||
}
|
||||
|
||||
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (lib->handle == NULL) {
|
||||
return uv__dlerror(lib, GetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_dlclose(uv_lib_t* lib) {
|
||||
if (lib->errmsg) {
|
||||
LocalFree((void*)lib->errmsg);
|
||||
lib->errmsg = NULL;
|
||||
}
|
||||
|
||||
if (lib->handle) {
|
||||
/* Ignore errors. No good way to signal them without leaking memory. */
|
||||
FreeLibrary(lib->handle);
|
||||
lib->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
|
||||
*ptr = (void*) GetProcAddress(lib->handle, name);
|
||||
return uv__dlerror(lib, *ptr ? 0 : GetLastError());
|
||||
}
|
||||
|
||||
|
||||
const char* uv_dlerror(const uv_lib_t* lib) {
|
||||
return lib->errmsg ? lib->errmsg : "no error";
|
||||
}
|
||||
|
||||
|
||||
static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
|
||||
DWORD_PTR args[1] = { (DWORD_PTR) errorno };
|
||||
LPSTR fallback_error = "error: %1!d!";
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
fallback_error, 0, 0,
|
||||
(LPSTR) &lib->errmsg,
|
||||
0, (va_list*) args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int uv__dlerror(uv_lib_t* lib, int errorno) {
|
||||
DWORD res;
|
||||
|
||||
if (lib->errmsg) {
|
||||
LocalFree((void*)lib->errmsg);
|
||||
lib->errmsg = NULL;
|
||||
}
|
||||
|
||||
if (errorno) {
|
||||
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
(LPSTR) &lib->errmsg, 0, NULL);
|
||||
if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
|
||||
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
||||
0, (LPSTR) &lib->errmsg, 0, NULL);
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
uv__format_fallback_error(lib, errorno);
|
||||
}
|
||||
}
|
||||
|
||||
return errorno ? -1 : 0;
|
||||
}
|
||||
170
Utilities/cmlibuv/src/win/error.c
Normal file
170
Utilities/cmlibuv/src/win/error.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Display an error message and abort the event loop.
|
||||
*/
|
||||
void uv_fatal_error(const int errorno, const char* syscall) {
|
||||
char* buf = NULL;
|
||||
const char* errmsg;
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
|
||||
|
||||
if (buf) {
|
||||
errmsg = buf;
|
||||
} else {
|
||||
errmsg = "Unknown error";
|
||||
}
|
||||
|
||||
/* FormatMessage messages include a newline character already, */
|
||||
/* so don't add another. */
|
||||
if (syscall) {
|
||||
fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
|
||||
} else {
|
||||
fprintf(stderr, "(%d) %s", errorno, errmsg);
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
LocalFree(buf);
|
||||
}
|
||||
|
||||
*((char*)NULL) = 0xff; /* Force debug break */
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_translate_sys_error(int sys_errno) {
|
||||
if (sys_errno <= 0) {
|
||||
return sys_errno; /* If < 0 then it's already a libuv error. */
|
||||
}
|
||||
|
||||
switch (sys_errno) {
|
||||
case ERROR_NOACCESS: return UV_EACCES;
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
|
||||
case WSAEWOULDBLOCK: return UV_EAGAIN;
|
||||
case WSAEALREADY: return UV_EALREADY;
|
||||
case ERROR_INVALID_FLAGS: return UV_EBADF;
|
||||
case ERROR_INVALID_HANDLE: return UV_EBADF;
|
||||
case ERROR_LOCK_VIOLATION: return UV_EBUSY;
|
||||
case ERROR_PIPE_BUSY: return UV_EBUSY;
|
||||
case ERROR_SHARING_VIOLATION: return UV_EBUSY;
|
||||
case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
|
||||
case WSAEINTR: return UV_ECANCELED;
|
||||
case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
|
||||
case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
|
||||
case WSAECONNABORTED: return UV_ECONNABORTED;
|
||||
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
|
||||
case WSAECONNREFUSED: return UV_ECONNREFUSED;
|
||||
case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
|
||||
case WSAECONNRESET: return UV_ECONNRESET;
|
||||
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
|
||||
case ERROR_FILE_EXISTS: return UV_EEXIST;
|
||||
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
|
||||
case WSAEFAULT: return UV_EFAULT;
|
||||
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
|
||||
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
|
||||
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
|
||||
case ERROR_INVALID_DATA: return UV_EINVAL;
|
||||
case ERROR_INVALID_PARAMETER: return UV_EINVAL;
|
||||
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
|
||||
case WSAEINVAL: return UV_EINVAL;
|
||||
case WSAEPFNOSUPPORT: return UV_EINVAL;
|
||||
case WSAESOCKTNOSUPPORT: return UV_EINVAL;
|
||||
case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
|
||||
case ERROR_BUS_RESET: return UV_EIO;
|
||||
case ERROR_CRC: return UV_EIO;
|
||||
case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
|
||||
case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
|
||||
case ERROR_DISK_CORRUPT: return UV_EIO;
|
||||
case ERROR_EOM_OVERFLOW: return UV_EIO;
|
||||
case ERROR_FILEMARK_DETECTED: return UV_EIO;
|
||||
case ERROR_GEN_FAILURE: return UV_EIO;
|
||||
case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
|
||||
case ERROR_IO_DEVICE: return UV_EIO;
|
||||
case ERROR_NO_DATA_DETECTED: return UV_EIO;
|
||||
case ERROR_NO_SIGNAL_SENT: return UV_EIO;
|
||||
case ERROR_OPEN_FAILED: return UV_EIO;
|
||||
case ERROR_SETMARK_DETECTED: return UV_EIO;
|
||||
case ERROR_SIGNAL_REFUSED: return UV_EIO;
|
||||
case WSAEISCONN: return UV_EISCONN;
|
||||
case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
|
||||
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
|
||||
case WSAEMFILE: return UV_EMFILE;
|
||||
case WSAEMSGSIZE: return UV_EMSGSIZE;
|
||||
case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
|
||||
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
|
||||
case WSAENETUNREACH: return UV_ENETUNREACH;
|
||||
case WSAENOBUFS: return UV_ENOBUFS;
|
||||
case ERROR_BAD_PATHNAME: return UV_ENOENT;
|
||||
case ERROR_DIRECTORY: return UV_ENOENT;
|
||||
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
|
||||
case ERROR_INVALID_NAME: return UV_ENOENT;
|
||||
case ERROR_INVALID_DRIVE: return UV_ENOENT;
|
||||
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
|
||||
case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
|
||||
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
|
||||
case WSAHOST_NOT_FOUND: return UV_ENOENT;
|
||||
case WSANO_DATA: return UV_ENOENT;
|
||||
case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
|
||||
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
|
||||
case ERROR_CANNOT_MAKE: return UV_ENOSPC;
|
||||
case ERROR_DISK_FULL: return UV_ENOSPC;
|
||||
case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
|
||||
case ERROR_END_OF_MEDIA: return UV_ENOSPC;
|
||||
case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
|
||||
case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
|
||||
case WSAENOTCONN: return UV_ENOTCONN;
|
||||
case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
|
||||
case WSAENOTSOCK: return UV_ENOTSOCK;
|
||||
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
|
||||
case ERROR_BROKEN_PIPE: return UV_EOF;
|
||||
case ERROR_ACCESS_DENIED: return UV_EPERM;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
|
||||
case ERROR_BAD_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
|
||||
case WSAESHUTDOWN: return UV_EPIPE;
|
||||
case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
|
||||
case ERROR_WRITE_PROTECT: return UV_EROFS;
|
||||
case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
|
||||
case WSAETIMEDOUT: return UV_ETIMEDOUT;
|
||||
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
|
||||
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
|
||||
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
|
||||
default: return UV_UNKNOWN;
|
||||
}
|
||||
}
|
||||
545
Utilities/cmlibuv/src/win/fs-event.c
Normal file
545
Utilities/cmlibuv/src/win/fs-event.c
Normal file
@@ -0,0 +1,545 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
const unsigned int uv_directory_watcher_buffer_size = 4096;
|
||||
|
||||
|
||||
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
|
||||
uv_fs_event_t* handle) {
|
||||
assert(handle->dir_handle != INVALID_HANDLE_VALUE);
|
||||
assert(!handle->req_pending);
|
||||
|
||||
memset(&(handle->req.u.io.overlapped), 0,
|
||||
sizeof(handle->req.u.io.overlapped));
|
||||
if (!ReadDirectoryChangesW(handle->dir_handle,
|
||||
handle->buffer,
|
||||
uv_directory_watcher_buffer_size,
|
||||
(handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
FILE_NOTIFY_CHANGE_SIZE |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_LAST_ACCESS |
|
||||
FILE_NOTIFY_CHANGE_CREATION |
|
||||
FILE_NOTIFY_CHANGE_SECURITY,
|
||||
NULL,
|
||||
&handle->req.u.io.overlapped,
|
||||
NULL)) {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(&handle->req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
|
||||
}
|
||||
|
||||
handle->req_pending = 1;
|
||||
}
|
||||
|
||||
static void uv_relative_path(const WCHAR* filename,
|
||||
const WCHAR* dir,
|
||||
WCHAR** relpath) {
|
||||
size_t relpathlen;
|
||||
size_t filenamelen = wcslen(filename);
|
||||
size_t dirlen = wcslen(dir);
|
||||
if (dirlen > 0 && dir[dirlen - 1] == '\\')
|
||||
dirlen--;
|
||||
relpathlen = filenamelen - dirlen - 1;
|
||||
*relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
|
||||
if (!*relpath)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
|
||||
(*relpath)[relpathlen] = L'\0';
|
||||
}
|
||||
|
||||
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
WCHAR** file) {
|
||||
int len = wcslen(filename);
|
||||
int i = len;
|
||||
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
|
||||
|
||||
if (i == 0) {
|
||||
if (dir) {
|
||||
*dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
|
||||
if (!*dir) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
|
||||
uv__free(*dir);
|
||||
*dir = NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*file = wcsdup(filename);
|
||||
} else {
|
||||
if (dir) {
|
||||
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
|
||||
if (!*dir) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
wcsncpy(*dir, filename, i + 1);
|
||||
(*dir)[i + 1] = L'\0';
|
||||
}
|
||||
|
||||
*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
|
||||
if (!*file) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
wcsncpy(*file, filename + i + 1, len - i - 1);
|
||||
(*file)[len - i - 1] = L'\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
|
||||
handle->dir_handle = INVALID_HANDLE_VALUE;
|
||||
handle->buffer = NULL;
|
||||
handle->req_pending = 0;
|
||||
handle->filew = NULL;
|
||||
handle->short_filew = NULL;
|
||||
handle->dirw = NULL;
|
||||
|
||||
uv_req_init(loop, (uv_req_t*)&handle->req);
|
||||
handle->req.type = UV_FS_EVENT_REQ;
|
||||
handle->req.data = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int name_size, is_path_dir;
|
||||
DWORD attr, last_error;
|
||||
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
|
||||
WCHAR short_path[MAX_PATH];
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
handle->cb = cb;
|
||||
handle->path = uv__strdup(path);
|
||||
if (!handle->path) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
|
||||
/* Convert name to UTF16. */
|
||||
|
||||
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
|
||||
sizeof(WCHAR);
|
||||
pathw = (WCHAR*)uv__malloc(name_size);
|
||||
if (!pathw) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
path,
|
||||
-1,
|
||||
pathw,
|
||||
name_size / sizeof(WCHAR))) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Determine whether path is a file or a directory. */
|
||||
attr = GetFileAttributesW(pathw);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
|
||||
|
||||
if (is_path_dir) {
|
||||
/* path is a directory, so that's the directory that we will watch. */
|
||||
handle->dirw = pathw;
|
||||
dir_to_watch = pathw;
|
||||
} else {
|
||||
/*
|
||||
* path is a file. So we split path into dir & file parts, and
|
||||
* watch the dir directory.
|
||||
*/
|
||||
|
||||
/* Convert to short path. */
|
||||
if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
dir_to_watch = dir;
|
||||
uv__free(pathw);
|
||||
pathw = NULL;
|
||||
}
|
||||
|
||||
handle->dir_handle = CreateFileW(dir_to_watch,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_DELETE |
|
||||
FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS |
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if (dir) {
|
||||
uv__free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
|
||||
if (handle->dir_handle == INVALID_HANDLE_VALUE) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (CreateIoCompletionPort(handle->dir_handle,
|
||||
handle->loop->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
0) == NULL) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!handle->buffer) {
|
||||
handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
|
||||
}
|
||||
if (!handle->buffer) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
memset(&(handle->req.u.io.overlapped), 0,
|
||||
sizeof(handle->req.u.io.overlapped));
|
||||
|
||||
if (!ReadDirectoryChangesW(handle->dir_handle,
|
||||
handle->buffer,
|
||||
uv_directory_watcher_buffer_size,
|
||||
(flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
FILE_NOTIFY_CHANGE_SIZE |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_LAST_ACCESS |
|
||||
FILE_NOTIFY_CHANGE_CREATION |
|
||||
FILE_NOTIFY_CHANGE_SECURITY,
|
||||
NULL,
|
||||
&handle->req.u.io.overlapped,
|
||||
NULL)) {
|
||||
last_error = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->req_pending = 1;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (handle->path) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
|
||||
if (handle->filew) {
|
||||
uv__free(handle->filew);
|
||||
handle->filew = NULL;
|
||||
}
|
||||
|
||||
if (handle->short_filew) {
|
||||
uv__free(handle->short_filew);
|
||||
handle->short_filew = NULL;
|
||||
}
|
||||
|
||||
uv__free(pathw);
|
||||
|
||||
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->dir_handle);
|
||||
handle->dir_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (handle->buffer) {
|
||||
uv__free(handle->buffer);
|
||||
handle->buffer = NULL;
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(last_error);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->dir_handle);
|
||||
handle->dir_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (handle->filew) {
|
||||
uv__free(handle->filew);
|
||||
handle->filew = NULL;
|
||||
}
|
||||
|
||||
if (handle->short_filew) {
|
||||
uv__free(handle->short_filew);
|
||||
handle->short_filew = NULL;
|
||||
}
|
||||
|
||||
if (handle->path) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
|
||||
if (handle->dirw) {
|
||||
uv__free(handle->dirw);
|
||||
handle->dirw = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
|
||||
int str_len;
|
||||
|
||||
str_len = wcslen(str);
|
||||
|
||||
/*
|
||||
Since we only care about equality, return early if the strings
|
||||
aren't the same length
|
||||
*/
|
||||
if (str_len != (file_name_len / sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
return _wcsnicmp(str, file_name, str_len);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
uv_fs_event_t* handle) {
|
||||
FILE_NOTIFY_INFORMATION* file_info;
|
||||
int err, sizew, size;
|
||||
char* filename = NULL;
|
||||
WCHAR* filenamew = NULL;
|
||||
WCHAR* long_filenamew = NULL;
|
||||
DWORD offset = 0;
|
||||
|
||||
assert(req->type == UV_FS_EVENT_REQ);
|
||||
assert(handle->req_pending);
|
||||
handle->req_pending = 0;
|
||||
|
||||
/* Don't report any callbacks if:
|
||||
* - We're closing, just push the handle onto the endgame queue
|
||||
* - We are not active, just ignore the callback
|
||||
*/
|
||||
if (!uv__is_active(handle)) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
|
||||
|
||||
if (REQ_SUCCESS(req)) {
|
||||
if (req->u.io.overlapped.InternalHigh > 0) {
|
||||
do {
|
||||
file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
|
||||
assert(!filename);
|
||||
assert(!filenamew);
|
||||
assert(!long_filenamew);
|
||||
|
||||
/*
|
||||
* Fire the event only if we were asked to watch a directory,
|
||||
* or if the filename filter matches.
|
||||
*/
|
||||
if (handle->dirw ||
|
||||
file_info_cmp(handle->filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0 ||
|
||||
file_info_cmp(handle->short_filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0) {
|
||||
|
||||
if (handle->dirw) {
|
||||
/*
|
||||
* We attempt to resolve the long form of the file name explicitly.
|
||||
* We only do this for file names that might still exist on disk.
|
||||
* If this fails, we use the name given by ReadDirectoryChangesW.
|
||||
* This may be the long form or the 8.3 short name in some cases.
|
||||
*/
|
||||
if (file_info->Action != FILE_ACTION_REMOVED &&
|
||||
file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
||||
/* Construct a full path to the file. */
|
||||
size = wcslen(handle->dirw) +
|
||||
file_info->FileNameLength / sizeof(WCHAR) + 2;
|
||||
|
||||
filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
|
||||
if (!filenamew) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
|
||||
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
|
||||
file_info->FileName);
|
||||
|
||||
filenamew[size - 1] = L'\0';
|
||||
|
||||
/* Convert to long name. */
|
||||
size = GetLongPathNameW(filenamew, NULL, 0);
|
||||
|
||||
if (size) {
|
||||
long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
|
||||
if (!long_filenamew) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
size = GetLongPathNameW(filenamew, long_filenamew, size);
|
||||
if (size) {
|
||||
long_filenamew[size] = '\0';
|
||||
} else {
|
||||
uv__free(long_filenamew);
|
||||
long_filenamew = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(filenamew);
|
||||
|
||||
if (long_filenamew) {
|
||||
/* Get the file name out of the long path. */
|
||||
uv_relative_path(long_filenamew,
|
||||
handle->dirw,
|
||||
&filenamew);
|
||||
uv__free(long_filenamew);
|
||||
long_filenamew = filenamew;
|
||||
sizew = -1;
|
||||
} else {
|
||||
/* We couldn't get the long filename, use the one reported. */
|
||||
filenamew = file_info->FileName;
|
||||
sizew = file_info->FileNameLength / sizeof(WCHAR);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Removed or renamed events cannot be resolved to the long form.
|
||||
* We therefore use the name given by ReadDirectoryChangesW.
|
||||
* This may be the long form or the 8.3 short name in some cases.
|
||||
*/
|
||||
filenamew = file_info->FileName;
|
||||
sizew = file_info->FileNameLength / sizeof(WCHAR);
|
||||
}
|
||||
} else {
|
||||
/* We already have the long name of the file, so just use it. */
|
||||
filenamew = handle->filew;
|
||||
sizew = -1;
|
||||
}
|
||||
|
||||
/* Convert the filename to utf8. */
|
||||
uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
|
||||
|
||||
switch (file_info->Action) {
|
||||
case FILE_ACTION_ADDED:
|
||||
case FILE_ACTION_REMOVED:
|
||||
case FILE_ACTION_RENAMED_OLD_NAME:
|
||||
case FILE_ACTION_RENAMED_NEW_NAME:
|
||||
handle->cb(handle, filename, UV_RENAME, 0);
|
||||
break;
|
||||
|
||||
case FILE_ACTION_MODIFIED:
|
||||
handle->cb(handle, filename, UV_CHANGE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
uv__free(filename);
|
||||
filename = NULL;
|
||||
uv__free(long_filenamew);
|
||||
long_filenamew = NULL;
|
||||
filenamew = NULL;
|
||||
}
|
||||
|
||||
offset = file_info->NextEntryOffset;
|
||||
} while (offset && !(handle->flags & UV__HANDLE_CLOSING));
|
||||
} else {
|
||||
handle->cb(handle, NULL, UV_CHANGE, 0);
|
||||
}
|
||||
} else {
|
||||
err = GET_REQ_ERROR(req);
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV__HANDLE_CLOSING)) {
|
||||
uv_fs_event_queue_readdirchanges(loop, handle);
|
||||
} else {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (!handle->req_pending) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
if (handle->buffer) {
|
||||
uv__free(handle->buffer);
|
||||
handle->buffer = NULL;
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
2491
Utilities/cmlibuv/src/win/fs.c
Normal file
2491
Utilities/cmlibuv/src/win/fs.c
Normal file
File diff suppressed because it is too large
Load Diff
385
Utilities/cmlibuv/src/win/getaddrinfo.c
Normal file
385
Utilities/cmlibuv/src/win/getaddrinfo.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
/* EAI_* constants. */
|
||||
#include <winsock2.h>
|
||||
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
switch (sys_err) {
|
||||
case 0: return 0;
|
||||
case WSATRY_AGAIN: return UV_EAI_AGAIN;
|
||||
case WSAEINVAL: return UV_EAI_BADFLAGS;
|
||||
case WSANO_RECOVERY: return UV_EAI_FAIL;
|
||||
case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
|
||||
case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
|
||||
case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
|
||||
case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
|
||||
case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
|
||||
default: return uv_translate_sys_error(sys_err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MinGW is missing this
|
||||
*/
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
|
||||
typedef struct addrinfoW {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
size_t ai_addrlen;
|
||||
WCHAR* ai_canonname;
|
||||
struct sockaddr* ai_addr;
|
||||
struct addrinfoW* ai_next;
|
||||
} ADDRINFOW, *PADDRINFOW;
|
||||
|
||||
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
|
||||
const WCHAR* service,
|
||||
const ADDRINFOW* hints,
|
||||
PADDRINFOW* result);
|
||||
|
||||
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
|
||||
#endif
|
||||
|
||||
|
||||
/* adjust size value to be multiple of 4. Use to keep pointer aligned */
|
||||
/* Do we need different versions of this for different architectures? */
|
||||
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
|
||||
|
||||
|
||||
static void uv__getaddrinfo_work(struct uv__work* w) {
|
||||
uv_getaddrinfo_t* req;
|
||||
struct addrinfoW* hints;
|
||||
int err;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
hints = req->addrinfow;
|
||||
req->addrinfow = NULL;
|
||||
err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
|
||||
req->retcode = uv__getaddrinfo_translate_error(err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from uv_run when complete. Call user specified callback
|
||||
* then free returned addrinfo
|
||||
* Returned addrinfo strings are converted from UTF-16 to UTF-8.
|
||||
*
|
||||
* To minimize allocation we calculate total size required,
|
||||
* and copy all structs and referenced strings into the one block.
|
||||
* Each size calculation is adjusted to avoid unaligned pointers.
|
||||
*/
|
||||
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
uv_getaddrinfo_t* req;
|
||||
int addrinfo_len = 0;
|
||||
int name_len = 0;
|
||||
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
|
||||
struct addrinfoW* addrinfow_ptr;
|
||||
struct addrinfo* addrinfo_ptr;
|
||||
char* alloc_ptr = NULL;
|
||||
char* cur_ptr = NULL;
|
||||
|
||||
req = container_of(w, uv_getaddrinfo_t, work_req);
|
||||
|
||||
/* release input parameter memory */
|
||||
uv__free(req->alloc);
|
||||
req->alloc = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
if (req->retcode == 0) {
|
||||
/* convert addrinfoW to addrinfo */
|
||||
/* first calculate required length */
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
while (addrinfow_ptr != NULL) {
|
||||
addrinfo_len += addrinfo_struct_len +
|
||||
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (name_len == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
goto complete;
|
||||
}
|
||||
addrinfo_len += ALIGNED_SIZE(name_len);
|
||||
}
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
}
|
||||
|
||||
/* allocate memory for addrinfo results */
|
||||
alloc_ptr = (char*)uv__malloc(addrinfo_len);
|
||||
|
||||
/* do conversions */
|
||||
if (alloc_ptr != NULL) {
|
||||
cur_ptr = alloc_ptr;
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
|
||||
while (addrinfow_ptr != NULL) {
|
||||
/* copy addrinfo struct data */
|
||||
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
|
||||
addrinfo_ptr = (struct addrinfo*)cur_ptr;
|
||||
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
|
||||
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
|
||||
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
|
||||
addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
|
||||
addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
|
||||
addrinfo_ptr->ai_canonname = NULL;
|
||||
addrinfo_ptr->ai_addr = NULL;
|
||||
addrinfo_ptr->ai_next = NULL;
|
||||
|
||||
cur_ptr += addrinfo_struct_len;
|
||||
|
||||
/* copy sockaddr */
|
||||
if (addrinfo_ptr->ai_addrlen > 0) {
|
||||
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
|
||||
alloc_ptr + addrinfo_len);
|
||||
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
|
||||
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
|
||||
}
|
||||
|
||||
/* convert canonical name to UTF-8 */
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
assert(name_len > 0);
|
||||
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
|
||||
name_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
addrinfow_ptr->ai_canonname,
|
||||
-1,
|
||||
cur_ptr,
|
||||
name_len,
|
||||
NULL,
|
||||
NULL);
|
||||
assert(name_len > 0);
|
||||
addrinfo_ptr->ai_canonname = cur_ptr;
|
||||
cur_ptr += ALIGNED_SIZE(name_len);
|
||||
}
|
||||
assert(cur_ptr <= alloc_ptr + addrinfo_len);
|
||||
|
||||
/* set next ptr */
|
||||
addrinfow_ptr = addrinfow_ptr->ai_next;
|
||||
if (addrinfow_ptr != NULL) {
|
||||
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
|
||||
}
|
||||
}
|
||||
req->addrinfo = (struct addrinfo*)alloc_ptr;
|
||||
} else {
|
||||
req->retcode = UV_EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* return memory to system */
|
||||
if (req->addrinfow != NULL) {
|
||||
FreeAddrInfoW(req->addrinfow);
|
||||
req->addrinfow = NULL;
|
||||
}
|
||||
|
||||
complete:
|
||||
uv__req_unregister(req->loop, req);
|
||||
|
||||
/* finally do callback with converted result */
|
||||
if (req->getaddrinfo_cb)
|
||||
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
|
||||
}
|
||||
|
||||
|
||||
void uv_freeaddrinfo(struct addrinfo* ai) {
|
||||
char* alloc_ptr = (char*)ai;
|
||||
|
||||
/* release copied result memory */
|
||||
uv__free(alloc_ptr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entry point for getaddrinfo
|
||||
* we convert the UTF-8 strings to UNICODE
|
||||
* and save the UNICODE string pointers in the req
|
||||
* We also copy hints so that caller does not need to keep memory until the
|
||||
* callback.
|
||||
* return 0 if a callback will be made
|
||||
* return error code if validation fails
|
||||
*
|
||||
* To minimize allocation we calculate total size required,
|
||||
* and copy all structs and referenced strings into the one block.
|
||||
* Each size calculation is adjusted to avoid unaligned pointers.
|
||||
*/
|
||||
int uv_getaddrinfo(uv_loop_t* loop,
|
||||
uv_getaddrinfo_t* req,
|
||||
uv_getaddrinfo_cb getaddrinfo_cb,
|
||||
const char* node,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
int nodesize = 0;
|
||||
int servicesize = 0;
|
||||
int hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
int err;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
err = WSAEINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
uv_req_init(loop, (uv_req_t*)req);
|
||||
|
||||
req->getaddrinfo_cb = getaddrinfo_cb;
|
||||
req->addrinfo = NULL;
|
||||
req->type = UV_GETADDRINFO;
|
||||
req->loop = loop;
|
||||
req->retcode = 0;
|
||||
|
||||
/* calculate required memory size for all input values */
|
||||
if (node != NULL) {
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
|
||||
sizeof(WCHAR));
|
||||
if (nodesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
NULL,
|
||||
0) *
|
||||
sizeof(WCHAR));
|
||||
if (servicesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (hints != NULL) {
|
||||
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
|
||||
}
|
||||
|
||||
/* allocate memory for inputs, and partition it as needed */
|
||||
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
|
||||
if (!alloc_ptr) {
|
||||
err = WSAENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* save alloc_ptr now so we can free if error */
|
||||
req->alloc = (void*)alloc_ptr;
|
||||
|
||||
/* convert node string to UTF16 into allocated memory and save pointer in */
|
||||
/* the request. */
|
||||
if (node != NULL) {
|
||||
req->node = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
node,
|
||||
-1,
|
||||
(WCHAR*) alloc_ptr,
|
||||
nodesize / sizeof(WCHAR)) == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += nodesize;
|
||||
} else {
|
||||
req->node = NULL;
|
||||
}
|
||||
|
||||
/* convert service string to UTF16 into allocated memory and save pointer */
|
||||
/* in the req. */
|
||||
if (service != NULL) {
|
||||
req->service = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
(WCHAR*) alloc_ptr,
|
||||
servicesize / sizeof(WCHAR)) == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += servicesize;
|
||||
} else {
|
||||
req->service = NULL;
|
||||
}
|
||||
|
||||
/* copy hints to allocated memory and save pointer in req */
|
||||
if (hints != NULL) {
|
||||
req->addrinfow = (struct addrinfoW*)alloc_ptr;
|
||||
req->addrinfow->ai_family = hints->ai_family;
|
||||
req->addrinfow->ai_socktype = hints->ai_socktype;
|
||||
req->addrinfow->ai_protocol = hints->ai_protocol;
|
||||
req->addrinfow->ai_flags = hints->ai_flags;
|
||||
req->addrinfow->ai_addrlen = 0;
|
||||
req->addrinfow->ai_canonname = NULL;
|
||||
req->addrinfow->ai_addr = NULL;
|
||||
req->addrinfow->ai_next = NULL;
|
||||
} else {
|
||||
req->addrinfow = NULL;
|
||||
}
|
||||
|
||||
uv__req_register(loop, req);
|
||||
|
||||
if (getaddrinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getaddrinfo_work(&req->work_req);
|
||||
uv__getaddrinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
|
||||
error:
|
||||
if (req != NULL) {
|
||||
uv__free(req->alloc);
|
||||
req->alloc = NULL;
|
||||
}
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
150
Utilities/cmlibuv/src/win/getnameinfo.c
Normal file
150
Utilities/cmlibuv/src/win/getnameinfo.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
#ifndef GetNameInfo
|
||||
int WSAAPI GetNameInfoW(
|
||||
const SOCKADDR *pSockaddr,
|
||||
socklen_t SockaddrLength,
|
||||
PWCHAR pNodeBuffer,
|
||||
DWORD NodeBufferSize,
|
||||
PWCHAR pServiceBuffer,
|
||||
DWORD ServiceBufferSize,
|
||||
INT Flags
|
||||
);
|
||||
#endif
|
||||
|
||||
static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
uv_getnameinfo_t* req;
|
||||
WCHAR host[NI_MAXHOST];
|
||||
WCHAR service[NI_MAXSERV];
|
||||
int ret = 0;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
if (GetNameInfoW((struct sockaddr*)&req->storage,
|
||||
sizeof(req->storage),
|
||||
host,
|
||||
ARRAY_SIZE(host),
|
||||
service,
|
||||
ARRAY_SIZE(service),
|
||||
req->flags)) {
|
||||
ret = WSAGetLastError();
|
||||
}
|
||||
req->retcode = uv__getaddrinfo_translate_error(ret);
|
||||
|
||||
/* convert results to UTF-8 */
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
host,
|
||||
-1,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from uv_run when complete.
|
||||
*/
|
||||
static void uv__getnameinfo_done(struct uv__work* w, int status) {
|
||||
uv_getnameinfo_t* req;
|
||||
char* host;
|
||||
char* service;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
host = service = NULL;
|
||||
|
||||
if (status == UV_ECANCELED) {
|
||||
assert(req->retcode == 0);
|
||||
req->retcode = UV_EAI_CANCELED;
|
||||
} else if (req->retcode == 0) {
|
||||
host = req->host;
|
||||
service = req->service;
|
||||
}
|
||||
|
||||
if (req->getnameinfo_cb)
|
||||
req->getnameinfo_cb(req, req->retcode, host, service);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entry point for getnameinfo
|
||||
* return 0 if a callback will be made
|
||||
* return error code if validation fails
|
||||
*/
|
||||
int uv_getnameinfo(uv_loop_t* loop,
|
||||
uv_getnameinfo_t* req,
|
||||
uv_getnameinfo_cb getnameinfo_cb,
|
||||
const struct sockaddr* addr,
|
||||
int flags) {
|
||||
if (req == NULL || addr == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
memcpy(&req->storage,
|
||||
addr,
|
||||
sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv_req_init(loop, (uv_req_t*)req);
|
||||
uv__req_register(loop, req);
|
||||
|
||||
req->getnameinfo_cb = getnameinfo_cb;
|
||||
req->flags = flags;
|
||||
req->type = UV_GETNAMEINFO;
|
||||
req->loop = loop;
|
||||
req->retcode = 0;
|
||||
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
} else {
|
||||
uv__getnameinfo_work(&req->work_req);
|
||||
uv__getnameinfo_done(&req->work_req, 0);
|
||||
return req->retcode;
|
||||
}
|
||||
}
|
||||
179
Utilities/cmlibuv/src/win/handle-inl.h
Normal file
179
Utilities/cmlibuv/src/win/handle-inl.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_WIN_HANDLE_INL_H_
|
||||
#define UV_WIN_HANDLE_INL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#define DECREASE_ACTIVE_COUNT(loop, handle) \
|
||||
do { \
|
||||
if (--(handle)->activecnt == 0 && \
|
||||
!((handle)->flags & UV__HANDLE_CLOSING)) { \
|
||||
uv__handle_stop((handle)); \
|
||||
} \
|
||||
assert((handle)->activecnt >= 0); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define INCREASE_ACTIVE_COUNT(loop, handle) \
|
||||
do { \
|
||||
if ((handle)->activecnt++ == 0) { \
|
||||
uv__handle_start((handle)); \
|
||||
} \
|
||||
assert((handle)->activecnt > 0); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define DECREASE_PENDING_REQ_COUNT(handle) \
|
||||
do { \
|
||||
assert(handle->reqs_pending > 0); \
|
||||
handle->reqs_pending--; \
|
||||
\
|
||||
if (handle->flags & UV__HANDLE_CLOSING && \
|
||||
handle->reqs_pending == 0) { \
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define uv__handle_closing(handle) \
|
||||
do { \
|
||||
assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
|
||||
\
|
||||
if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
|
||||
((handle)->flags & UV__HANDLE_REF))) \
|
||||
uv__active_handle_add((uv_handle_t*) (handle)); \
|
||||
\
|
||||
(handle)->flags |= UV__HANDLE_CLOSING; \
|
||||
(handle)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define uv__handle_close(handle) \
|
||||
do { \
|
||||
QUEUE_REMOVE(&(handle)->handle_queue); \
|
||||
uv__active_handle_rm((uv_handle_t*) (handle)); \
|
||||
\
|
||||
(handle)->flags |= UV_HANDLE_CLOSED; \
|
||||
\
|
||||
if ((handle)->close_cb) \
|
||||
(handle)->close_cb((uv_handle_t*) (handle)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
|
||||
handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
|
||||
|
||||
handle->endgame_next = loop->endgame_handles;
|
||||
loop->endgame_handles = handle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
uv_handle_t* handle;
|
||||
|
||||
while (loop->endgame_handles) {
|
||||
handle = loop->endgame_handles;
|
||||
loop->endgame_handles = handle->endgame_next;
|
||||
|
||||
handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
|
||||
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
uv_tcp_endgame(loop, (uv_tcp_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
uv_pipe_endgame(loop, (uv_pipe_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_TTY:
|
||||
uv_tty_endgame(loop, (uv_tty_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_UDP:
|
||||
uv_udp_endgame(loop, (uv_udp_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_POLL:
|
||||
uv_poll_endgame(loop, (uv_poll_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_endgame(loop, (uv_timer_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_PREPARE:
|
||||
case UV_CHECK:
|
||||
case UV_IDLE:
|
||||
uv_loop_watcher_endgame(loop, handle);
|
||||
break;
|
||||
|
||||
case UV_ASYNC:
|
||||
uv_async_endgame(loop, (uv_async_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv_signal_endgame(loop, (uv_signal_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_PROCESS:
|
||||
uv_process_endgame(loop, (uv_process_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_FS_EVENT:
|
||||
uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
|
||||
break;
|
||||
|
||||
case UV_FS_POLL:
|
||||
uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INLINE static HANDLE uv__get_osfhandle(int fd)
|
||||
{
|
||||
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
|
||||
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
|
||||
/* for invalid FDs in release builds (or if you let the assert continue). */
|
||||
/* So this wrapper function disables asserts when calling _get_osfhandle. */
|
||||
|
||||
HANDLE handle;
|
||||
UV_BEGIN_DISABLE_CRT_ASSERT();
|
||||
handle = (HANDLE) _get_osfhandle(fd);
|
||||
UV_END_DISABLE_CRT_ASSERT();
|
||||
return handle;
|
||||
}
|
||||
|
||||
#endif /* UV_WIN_HANDLE_INL_H_ */
|
||||
154
Utilities/cmlibuv/src/win/handle.c
Normal file
154
Utilities/cmlibuv/src/win/handle.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
uv_handle_type uv_guess_handle(uv_file file) {
|
||||
HANDLE handle;
|
||||
DWORD mode;
|
||||
|
||||
if (file < 0) {
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
handle = uv__get_osfhandle(file);
|
||||
|
||||
switch (GetFileType(handle)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
if (GetConsoleMode(handle, &mode)) {
|
||||
return UV_TTY;
|
||||
} else {
|
||||
return UV_FILE;
|
||||
}
|
||||
|
||||
case FILE_TYPE_PIPE:
|
||||
return UV_NAMED_PIPE;
|
||||
|
||||
case FILE_TYPE_DISK:
|
||||
return UV_FILE;
|
||||
|
||||
default:
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_is_active(const uv_handle_t* handle) {
|
||||
return (handle->flags & UV__HANDLE_ACTIVE) &&
|
||||
!(handle->flags & UV__HANDLE_CLOSING);
|
||||
}
|
||||
|
||||
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
handle->close_cb = cb;
|
||||
|
||||
/* Handle-specific close actions */
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
uv_tcp_close(loop, (uv_tcp_t*)handle);
|
||||
return;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
uv_pipe_close(loop, (uv_pipe_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_TTY:
|
||||
uv_tty_close((uv_tty_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_UDP:
|
||||
uv_udp_close(loop, (uv_udp_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_POLL:
|
||||
uv_poll_close(loop, (uv_poll_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_stop((uv_timer_t*)handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
case UV_PREPARE:
|
||||
uv_prepare_stop((uv_prepare_t*)handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
case UV_CHECK:
|
||||
uv_check_stop((uv_check_t*)handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
case UV_IDLE:
|
||||
uv_idle_stop((uv_idle_t*)handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
case UV_ASYNC:
|
||||
uv_async_close(loop, (uv_async_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv_signal_close(loop, (uv_signal_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_PROCESS:
|
||||
uv_process_close(loop, (uv_process_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_FS_EVENT:
|
||||
uv_fs_event_close(loop, (uv_fs_event_t*) handle);
|
||||
return;
|
||||
|
||||
case UV_FS_POLL:
|
||||
uv__fs_poll_close((uv_fs_poll_t*) handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
default:
|
||||
/* Not supported */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_is_closing(const uv_handle_t* handle) {
|
||||
return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
|
||||
}
|
||||
398
Utilities/cmlibuv/src/win/internal.h
Normal file
398
Utilities/cmlibuv/src/win/internal.h
Normal file
@@ -0,0 +1,398 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_WIN_INTERNAL_H_
|
||||
#define UV_WIN_INTERNAL_H_
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(push,1)
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "../uv-common.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "winapi.h"
|
||||
#include "winsock.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define INLINE __inline
|
||||
# define UV_THREAD_LOCAL __declspec( thread )
|
||||
#else
|
||||
# define INLINE inline
|
||||
# define UV_THREAD_LOCAL __thread
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
|
||||
|
||||
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
|
||||
{ \
|
||||
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
|
||||
uv__crt_assert_enabled = FALSE;
|
||||
|
||||
|
||||
#define UV_END_DISABLE_CRT_ASSERT() \
|
||||
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
|
||||
}
|
||||
|
||||
#else
|
||||
#define UV_BEGIN_DISABLE_CRT_ASSERT()
|
||||
#define UV_END_DISABLE_CRT_ASSERT()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handles
|
||||
* (also see handle-inl.h)
|
||||
*/
|
||||
|
||||
/* Used by all handles. */
|
||||
#define UV_HANDLE_CLOSED 0x00000002
|
||||
#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
|
||||
|
||||
/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
|
||||
/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
|
||||
/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
|
||||
/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
|
||||
|
||||
/* Used by streams and UDP handles. */
|
||||
#define UV_HANDLE_READING 0x00000100
|
||||
#define UV_HANDLE_BOUND 0x00000200
|
||||
#define UV_HANDLE_LISTENING 0x00000800
|
||||
#define UV_HANDLE_CONNECTION 0x00001000
|
||||
#define UV_HANDLE_READABLE 0x00008000
|
||||
#define UV_HANDLE_WRITABLE 0x00010000
|
||||
#define UV_HANDLE_READ_PENDING 0x00020000
|
||||
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
|
||||
#define UV_HANDLE_ZERO_READ 0x00080000
|
||||
#define UV_HANDLE_EMULATE_IOCP 0x00100000
|
||||
#define UV_HANDLE_BLOCKING_WRITES 0x00200000
|
||||
#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
#define UV_HANDLE_IPV6 0x01000000
|
||||
|
||||
/* Only used by uv_tcp_t handles. */
|
||||
#define UV_HANDLE_TCP_NODELAY 0x02000000
|
||||
#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
|
||||
#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
|
||||
#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
|
||||
#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
|
||||
#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
|
||||
|
||||
/* Only used by uv_pipe_t handles. */
|
||||
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
|
||||
#define UV_HANDLE_PIPESERVER 0x02000000
|
||||
#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
#define UV_HANDLE_TTY_READABLE 0x01000000
|
||||
#define UV_HANDLE_TTY_RAW 0x02000000
|
||||
#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
|
||||
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
#define UV_HANDLE_POLL_SLOW 0x02000000
|
||||
|
||||
|
||||
/*
|
||||
* Requests: see req-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Streams: see stream-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TCP
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
WSAPROTOCOL_INFOW socket_info;
|
||||
int delayed_error;
|
||||
} uv__ipc_socket_info_ex;
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
|
||||
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
|
||||
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
|
||||
int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
|
||||
unsigned int nbufs);
|
||||
|
||||
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
|
||||
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_write_t* req);
|
||||
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* req);
|
||||
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_connect_t* req);
|
||||
|
||||
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
|
||||
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
|
||||
|
||||
int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
|
||||
int tcp_connection);
|
||||
|
||||
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
|
||||
LPWSAPROTOCOL_INFOW protocol_info);
|
||||
|
||||
|
||||
/*
|
||||
* UDP
|
||||
*/
|
||||
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
|
||||
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
uv_udp_send_t* req);
|
||||
|
||||
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
|
||||
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Pipes
|
||||
*/
|
||||
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
|
||||
char* name, size_t nameSize);
|
||||
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
|
||||
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
|
||||
int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
|
||||
uv_write_cb cb);
|
||||
void uv__pipe_pause_read(uv_pipe_t* handle);
|
||||
void uv__pipe_unpause_read(uv_pipe_t* handle);
|
||||
void uv__pipe_stop_read(uv_pipe_t* handle);
|
||||
|
||||
void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_req_t* req);
|
||||
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_write_t* req);
|
||||
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_req_t* raw_req);
|
||||
void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_connect_t* req);
|
||||
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_shutdown_t* req);
|
||||
|
||||
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* TTY
|
||||
*/
|
||||
void uv_console_init();
|
||||
|
||||
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
int uv_tty_read_stop(uv_tty_t* handle);
|
||||
int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
|
||||
int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
|
||||
unsigned int nbufs);
|
||||
void uv_tty_close(uv_tty_t* handle);
|
||||
|
||||
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_req_t* req);
|
||||
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_write_t* req);
|
||||
/* TODO: remove me */
|
||||
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_req_t* raw_req);
|
||||
/* TODO: remove me */
|
||||
void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_connect_t* req);
|
||||
|
||||
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Poll watchers
|
||||
*/
|
||||
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_req_t* req);
|
||||
|
||||
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*/
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
|
||||
|
||||
DWORD uv__next_timeout(const uv_loop_t* loop);
|
||||
void uv_process_timers(uv_loop_t* loop);
|
||||
|
||||
|
||||
/*
|
||||
* Loop watchers
|
||||
*/
|
||||
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
|
||||
|
||||
void uv_prepare_invoke(uv_loop_t* loop);
|
||||
void uv_check_invoke(uv_loop_t* loop);
|
||||
void uv_idle_invoke(uv_loop_t* loop);
|
||||
|
||||
void uv__once_init();
|
||||
|
||||
|
||||
/*
|
||||
* Async watcher
|
||||
*/
|
||||
void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
|
||||
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
|
||||
|
||||
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
|
||||
uv_req_t* req);
|
||||
|
||||
|
||||
/*
|
||||
* Signal watcher
|
||||
*/
|
||||
void uv_signals_init();
|
||||
int uv__signal_dispatch(int signum);
|
||||
|
||||
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
|
||||
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
|
||||
|
||||
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
|
||||
uv_req_t* req);
|
||||
|
||||
|
||||
/*
|
||||
* Spawn
|
||||
*/
|
||||
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
|
||||
void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
|
||||
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Error
|
||||
*/
|
||||
int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
|
||||
/*
|
||||
* FS
|
||||
*/
|
||||
void uv_fs_init();
|
||||
|
||||
|
||||
/*
|
||||
* FS Event
|
||||
*/
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
uv_fs_event_t* handle);
|
||||
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
|
||||
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Stat poller.
|
||||
*/
|
||||
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Utilities.
|
||||
*/
|
||||
void uv__util_init();
|
||||
|
||||
uint64_t uv__hrtime(double scale);
|
||||
int uv_parent_pid();
|
||||
int uv_current_pid();
|
||||
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
|
||||
|
||||
|
||||
/*
|
||||
* Process stdio handles.
|
||||
*/
|
||||
int uv__stdio_create(uv_loop_t* loop,
|
||||
const uv_process_options_t* options,
|
||||
BYTE** buffer_ptr);
|
||||
void uv__stdio_destroy(BYTE* buffer);
|
||||
void uv__stdio_noinherit(BYTE* buffer);
|
||||
int uv__stdio_verify(BYTE* buffer, WORD size);
|
||||
WORD uv__stdio_size(BYTE* buffer);
|
||||
HANDLE uv__stdio_handle(BYTE* buffer, int fd);
|
||||
|
||||
|
||||
/*
|
||||
* Winapi and ntapi utility functions
|
||||
*/
|
||||
void uv_winapi_init();
|
||||
|
||||
|
||||
/*
|
||||
* Winsock utility functions
|
||||
*/
|
||||
void uv_winsock_init();
|
||||
|
||||
int uv_ntstatus_to_winsock_error(NTSTATUS status);
|
||||
|
||||
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
|
||||
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
|
||||
|
||||
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
|
||||
int* addr_len, WSAOVERLAPPED *overlapped,
|
||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||
|
||||
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
|
||||
|
||||
/* Whether there are any non-IFS LSPs stacked on TCP */
|
||||
extern int uv_tcp_non_ifs_lsp_ipv4;
|
||||
extern int uv_tcp_non_ifs_lsp_ipv6;
|
||||
|
||||
/* Ip address used to bind to any port at any interface */
|
||||
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/*
|
||||
* Wake all loops with fake message
|
||||
*/
|
||||
void uv__wake_all_loops();
|
||||
|
||||
/*
|
||||
* Init system wake-up detection
|
||||
*/
|
||||
void uv__init_detect_system_wakeup();
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
122
Utilities/cmlibuv/src/win/loop-watcher.c
Normal file
122
Utilities/cmlibuv/src/win/loop-watcher.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
|
||||
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
|
||||
uv_loop_t* loop = handle->loop; \
|
||||
uv_##name##_t* old_head; \
|
||||
\
|
||||
assert(handle->type == UV_##NAME); \
|
||||
\
|
||||
if (uv__is_active(handle)) \
|
||||
return 0; \
|
||||
\
|
||||
if (cb == NULL) \
|
||||
return UV_EINVAL; \
|
||||
\
|
||||
old_head = loop->name##_handles; \
|
||||
\
|
||||
handle->name##_next = old_head; \
|
||||
handle->name##_prev = NULL; \
|
||||
\
|
||||
if (old_head) { \
|
||||
old_head->name##_prev = handle; \
|
||||
} \
|
||||
\
|
||||
loop->name##_handles = handle; \
|
||||
\
|
||||
handle->name##_cb = cb; \
|
||||
uv__handle_start(handle); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int uv_##name##_stop(uv_##name##_t* handle) { \
|
||||
uv_loop_t* loop = handle->loop; \
|
||||
\
|
||||
assert(handle->type == UV_##NAME); \
|
||||
\
|
||||
if (!uv__is_active(handle)) \
|
||||
return 0; \
|
||||
\
|
||||
/* Update loop head if needed */ \
|
||||
if (loop->name##_handles == handle) { \
|
||||
loop->name##_handles = handle->name##_next; \
|
||||
} \
|
||||
\
|
||||
/* Update the iterator-next pointer of needed */ \
|
||||
if (loop->next_##name##_handle == handle) { \
|
||||
loop->next_##name##_handle = handle->name##_next; \
|
||||
} \
|
||||
\
|
||||
if (handle->name##_prev) { \
|
||||
handle->name##_prev->name##_next = handle->name##_next; \
|
||||
} \
|
||||
if (handle->name##_next) { \
|
||||
handle->name##_next->name##_prev = handle->name##_prev; \
|
||||
} \
|
||||
\
|
||||
uv__handle_stop(handle); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
void uv_##name##_invoke(uv_loop_t* loop) { \
|
||||
uv_##name##_t* handle; \
|
||||
\
|
||||
(loop)->next_##name##_handle = (loop)->name##_handles; \
|
||||
\
|
||||
while ((loop)->next_##name##_handle != NULL) { \
|
||||
handle = (loop)->next_##name##_handle; \
|
||||
(loop)->next_##name##_handle = handle->name##_next; \
|
||||
\
|
||||
handle->name##_cb(handle); \
|
||||
} \
|
||||
}
|
||||
|
||||
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
|
||||
UV_LOOP_WATCHER_DEFINE(check, CHECK)
|
||||
UV_LOOP_WATCHER_DEFINE(idle, IDLE)
|
||||
2130
Utilities/cmlibuv/src/win/pipe.c
Normal file
2130
Utilities/cmlibuv/src/win/pipe.c
Normal file
File diff suppressed because it is too large
Load Diff
646
Utilities/cmlibuv/src/win/poll.c
Normal file
646
Utilities/cmlibuv/src/win/poll.c
Normal file
@@ -0,0 +1,646 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
|
||||
{0xe70f1aa0, 0xab8b, 0x11cf,
|
||||
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
|
||||
{0xf9eab0c0, 0x26d4, 0x11d0,
|
||||
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
|
||||
{0x9fc48064, 0x7298, 0x43e4,
|
||||
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
|
||||
};
|
||||
|
||||
typedef struct uv_single_fd_set_s {
|
||||
unsigned int fd_count;
|
||||
SOCKET fd_array[1];
|
||||
} uv_single_fd_set_t;
|
||||
|
||||
|
||||
static OVERLAPPED overlapped_dummy_;
|
||||
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
|
||||
|
||||
static AFD_POLL_INFO afd_poll_info_dummy_;
|
||||
|
||||
|
||||
static void uv__init_overlapped_dummy(void) {
|
||||
HANDLE event;
|
||||
|
||||
event = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
if (event == NULL)
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
|
||||
memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
|
||||
overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
|
||||
}
|
||||
|
||||
|
||||
static OVERLAPPED* uv__get_overlapped_dummy() {
|
||||
uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
|
||||
return &overlapped_dummy_;
|
||||
}
|
||||
|
||||
|
||||
static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
|
||||
return &afd_poll_info_dummy_;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
uv_req_t* req;
|
||||
AFD_POLL_INFO* afd_poll_info;
|
||||
DWORD result;
|
||||
|
||||
/* Find a yet unsubmitted req to submit. */
|
||||
if (handle->submitted_events_1 == 0) {
|
||||
req = &handle->poll_req_1;
|
||||
afd_poll_info = &handle->afd_poll_info_1;
|
||||
handle->submitted_events_1 = handle->events;
|
||||
handle->mask_events_1 = 0;
|
||||
handle->mask_events_2 = handle->events;
|
||||
} else if (handle->submitted_events_2 == 0) {
|
||||
req = &handle->poll_req_2;
|
||||
afd_poll_info = &handle->afd_poll_info_2;
|
||||
handle->submitted_events_2 = handle->events;
|
||||
handle->mask_events_1 = handle->events;
|
||||
handle->mask_events_2 = 0;
|
||||
} else {
|
||||
/* Just wait until there's an unsubmitted req. */
|
||||
/* This will happen almost immediately as one of the 2 outstanding */
|
||||
/* requests is about to return. When this happens, */
|
||||
/* uv__fast_poll_process_poll_req will be called, and the pending */
|
||||
/* events, if needed, will be processed in a subsequent request. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setting Exclusive to TRUE makes the other poll request return if there */
|
||||
/* is any. */
|
||||
afd_poll_info->Exclusive = TRUE;
|
||||
afd_poll_info->NumberOfHandles = 1;
|
||||
afd_poll_info->Timeout.QuadPart = INT64_MAX;
|
||||
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
|
||||
afd_poll_info->Handles[0].Status = 0;
|
||||
afd_poll_info->Handles[0].Events = 0;
|
||||
|
||||
if (handle->events & UV_READABLE) {
|
||||
afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
|
||||
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
|
||||
} else {
|
||||
if (handle->events & UV_DISCONNECT) {
|
||||
afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
|
||||
}
|
||||
}
|
||||
if (handle->events & UV_WRITABLE) {
|
||||
afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
|
||||
}
|
||||
|
||||
memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
|
||||
|
||||
result = uv_msafd_poll((SOCKET) handle->peer_socket,
|
||||
afd_poll_info,
|
||||
afd_poll_info,
|
||||
&req->u.io.overlapped);
|
||||
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
|
||||
/* Queue this req, reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
DWORD result;
|
||||
|
||||
afd_poll_info.Exclusive = TRUE;
|
||||
afd_poll_info.NumberOfHandles = 1;
|
||||
afd_poll_info.Timeout.QuadPart = INT64_MAX;
|
||||
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
|
||||
afd_poll_info.Handles[0].Status = 0;
|
||||
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
|
||||
|
||||
result = uv_msafd_poll(handle->socket,
|
||||
&afd_poll_info,
|
||||
uv__get_afd_poll_info_dummy(),
|
||||
uv__get_overlapped_dummy());
|
||||
|
||||
if (result == SOCKET_ERROR) {
|
||||
DWORD error = WSAGetLastError();
|
||||
if (error != WSA_IO_PENDING)
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_req_t* req) {
|
||||
unsigned char mask_events;
|
||||
AFD_POLL_INFO* afd_poll_info;
|
||||
|
||||
if (req == &handle->poll_req_1) {
|
||||
afd_poll_info = &handle->afd_poll_info_1;
|
||||
handle->submitted_events_1 = 0;
|
||||
mask_events = handle->mask_events_1;
|
||||
} else if (req == &handle->poll_req_2) {
|
||||
afd_poll_info = &handle->afd_poll_info_2;
|
||||
handle->submitted_events_2 = 0;
|
||||
mask_events = handle->mask_events_2;
|
||||
} else {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Report an error unless the select was just interrupted. */
|
||||
if (!REQ_SUCCESS(req)) {
|
||||
DWORD error = GET_REQ_SOCK_ERROR(req);
|
||||
if (error != WSAEINTR && handle->events != 0) {
|
||||
handle->events = 0; /* Stop the watcher */
|
||||
handle->poll_cb(handle, uv_translate_sys_error(error), 0);
|
||||
}
|
||||
|
||||
} else if (afd_poll_info->NumberOfHandles >= 1) {
|
||||
unsigned char events = 0;
|
||||
|
||||
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
|
||||
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
|
||||
events |= UV_READABLE;
|
||||
if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
|
||||
events |= UV_DISCONNECT;
|
||||
}
|
||||
}
|
||||
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
|
||||
AFD_POLL_CONNECT_FAIL)) != 0) {
|
||||
events |= UV_WRITABLE;
|
||||
}
|
||||
|
||||
events &= handle->events & ~mask_events;
|
||||
|
||||
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
|
||||
/* Stop polling. */
|
||||
handle->events = 0;
|
||||
if (uv__is_active(handle))
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if (events != 0) {
|
||||
handle->poll_cb(handle, 0, events);
|
||||
}
|
||||
}
|
||||
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
handle->events = 0;
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return 0;
|
||||
} else {
|
||||
/* Cancel outstanding poll requests by executing another, unique poll */
|
||||
/* request that forces the outstanding ones to return. */
|
||||
return uv__fast_poll_cancel_poll_req(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
|
||||
WSAPROTOCOL_INFOW* protocol_info) {
|
||||
SOCKET sock = 0;
|
||||
|
||||
sock = WSASocketW(protocol_info->iAddressFamily,
|
||||
protocol_info->iSocketType,
|
||||
protocol_info->iProtocol,
|
||||
protocol_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
|
||||
goto error;
|
||||
};
|
||||
|
||||
if (CreateIoCompletionPort((HANDLE) sock,
|
||||
iocp,
|
||||
(ULONG_PTR) sock,
|
||||
0) == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
error:
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
|
||||
static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
|
||||
WSAPROTOCOL_INFOW* protocol_info) {
|
||||
int index, i;
|
||||
SOCKET peer_socket;
|
||||
|
||||
index = -1;
|
||||
for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
|
||||
if (memcmp((void*) &protocol_info->ProviderId,
|
||||
(void*) &uv_msafd_provider_ids[i],
|
||||
sizeof protocol_info->ProviderId) == 0) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the protocol uses an msafd socket. */
|
||||
if (index < 0) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* If we didn't (try) to create a peer socket yet, try to make one. Don't */
|
||||
/* try again if the peer socket creation failed earlier for the same */
|
||||
/* protocol. */
|
||||
peer_socket = loop->poll_peer_sockets[index];
|
||||
if (peer_socket == 0) {
|
||||
peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
|
||||
loop->poll_peer_sockets[index] = peer_socket;
|
||||
}
|
||||
|
||||
return peer_socket;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
|
||||
uv_req_t* req = (uv_req_t*) arg;
|
||||
uv_poll_t* handle = (uv_poll_t*) req->data;
|
||||
unsigned char reported_events;
|
||||
int r;
|
||||
uv_single_fd_set_t rfds, wfds, efds;
|
||||
struct timeval timeout;
|
||||
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(req->type == UV_POLL_REQ);
|
||||
|
||||
if (handle->events & UV_READABLE) {
|
||||
rfds.fd_count = 1;
|
||||
rfds.fd_array[0] = handle->socket;
|
||||
} else {
|
||||
rfds.fd_count = 0;
|
||||
}
|
||||
|
||||
if (handle->events & UV_WRITABLE) {
|
||||
wfds.fd_count = 1;
|
||||
wfds.fd_array[0] = handle->socket;
|
||||
efds.fd_count = 1;
|
||||
efds.fd_array[0] = handle->socket;
|
||||
} else {
|
||||
wfds.fd_count = 0;
|
||||
efds.fd_count = 0;
|
||||
}
|
||||
|
||||
/* Make the select() time out after 3 minutes. If select() hangs because */
|
||||
/* the user closed the socket, we will at least not hang indefinitely. */
|
||||
timeout.tv_sec = 3 * 60;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
|
||||
if (r == SOCKET_ERROR) {
|
||||
/* Queue this req, reporting an error. */
|
||||
SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
|
||||
POST_COMPLETION_FOR_REQ(handle->loop, req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
reported_events = 0;
|
||||
|
||||
if (r > 0) {
|
||||
if (rfds.fd_count > 0) {
|
||||
assert(rfds.fd_count == 1);
|
||||
assert(rfds.fd_array[0] == handle->socket);
|
||||
reported_events |= UV_READABLE;
|
||||
}
|
||||
|
||||
if (wfds.fd_count > 0) {
|
||||
assert(wfds.fd_count == 1);
|
||||
assert(wfds.fd_array[0] == handle->socket);
|
||||
reported_events |= UV_WRITABLE;
|
||||
} else if (efds.fd_count > 0) {
|
||||
assert(efds.fd_count == 1);
|
||||
assert(efds.fd_array[0] == handle->socket);
|
||||
reported_events |= UV_WRITABLE;
|
||||
}
|
||||
}
|
||||
|
||||
SET_REQ_SUCCESS(req);
|
||||
req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
|
||||
POST_COMPLETION_FOR_REQ(handle->loop, req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
uv_req_t* req;
|
||||
|
||||
/* Find a yet unsubmitted req to submit. */
|
||||
if (handle->submitted_events_1 == 0) {
|
||||
req = &handle->poll_req_1;
|
||||
handle->submitted_events_1 = handle->events;
|
||||
handle->mask_events_1 = 0;
|
||||
handle->mask_events_2 = handle->events;
|
||||
} else if (handle->submitted_events_2 == 0) {
|
||||
req = &handle->poll_req_2;
|
||||
handle->submitted_events_2 = handle->events;
|
||||
handle->mask_events_1 = handle->events;
|
||||
handle->mask_events_2 = 0;
|
||||
} else {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
|
||||
(void*) req,
|
||||
WT_EXECUTELONGFUNCTION)) {
|
||||
/* Make this req pending, reporting an error. */
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_req_t* req) {
|
||||
unsigned char mask_events;
|
||||
int err;
|
||||
|
||||
if (req == &handle->poll_req_1) {
|
||||
handle->submitted_events_1 = 0;
|
||||
mask_events = handle->mask_events_1;
|
||||
} else if (req == &handle->poll_req_2) {
|
||||
handle->submitted_events_2 = 0;
|
||||
mask_events = handle->mask_events_2;
|
||||
} else {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!REQ_SUCCESS(req)) {
|
||||
/* Error. */
|
||||
if (handle->events != 0) {
|
||||
err = GET_REQ_ERROR(req);
|
||||
handle->events = 0; /* Stop the watcher */
|
||||
handle->poll_cb(handle, uv_translate_sys_error(err), 0);
|
||||
}
|
||||
} else {
|
||||
/* Got some events. */
|
||||
int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
|
||||
if (events != 0) {
|
||||
handle->poll_cb(handle, 0, events);
|
||||
}
|
||||
}
|
||||
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
|
||||
if (handle->events != 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
if ((handle->events &
|
||||
~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(handle->loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
handle->events = 0;
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_os_sock_t socket) {
|
||||
WSAPROTOCOL_INFOW protocol_info;
|
||||
int len;
|
||||
SOCKET peer_socket, base_socket;
|
||||
DWORD bytes;
|
||||
DWORD yes = 1;
|
||||
|
||||
/* Set the socket to nonblocking mode */
|
||||
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
/* Try to obtain a base handle for the socket. This increases this chances */
|
||||
/* that we find an AFD handle and are able to use the fast poll mechanism. */
|
||||
/* This will always fail on windows XP/2k3, since they don't support the */
|
||||
/* SIO_BASE_HANDLE ioctl. */
|
||||
#ifndef NDEBUG
|
||||
base_socket = INVALID_SOCKET;
|
||||
#endif
|
||||
|
||||
if (WSAIoctl(socket,
|
||||
SIO_BASE_HANDLE,
|
||||
NULL,
|
||||
0,
|
||||
&base_socket,
|
||||
sizeof base_socket,
|
||||
&bytes,
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
assert(base_socket != 0 && base_socket != INVALID_SOCKET);
|
||||
socket = base_socket;
|
||||
}
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
|
||||
handle->socket = socket;
|
||||
handle->events = 0;
|
||||
|
||||
/* Obtain protocol information about the socket. */
|
||||
len = sizeof protocol_info;
|
||||
if (getsockopt(socket,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &protocol_info,
|
||||
&len) != 0) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
/* Get the peer socket that is needed to enable fast poll. If the returned */
|
||||
/* value is NULL, the protocol is not implemented by MSAFD and we'll have */
|
||||
/* to use slow mode. */
|
||||
peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
|
||||
|
||||
if (peer_socket != INVALID_SOCKET) {
|
||||
/* Initialize fast poll specific fields. */
|
||||
handle->peer_socket = peer_socket;
|
||||
} else {
|
||||
/* Initialize slow poll specific fields. */
|
||||
handle->flags |= UV_HANDLE_POLL_SLOW;
|
||||
}
|
||||
|
||||
/* Initialize 2 poll reqs. */
|
||||
handle->submitted_events_1 = 0;
|
||||
uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
|
||||
handle->poll_req_1.type = UV_POLL_REQ;
|
||||
handle->poll_req_1.data = handle;
|
||||
|
||||
handle->submitted_events_2 = 0;
|
||||
uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
|
||||
handle->poll_req_2.type = UV_POLL_REQ;
|
||||
handle->poll_req_2.data = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, events);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, events);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
handle->poll_cb = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_stop(uv_poll_t* handle) {
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
err = uv__fast_poll_set(handle->loop, handle, 0);
|
||||
} else {
|
||||
err = uv__slow_poll_set(handle->loop, handle, 0);
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
uv__fast_poll_process_poll_req(loop, handle, req);
|
||||
} else {
|
||||
uv__slow_poll_process_poll_req(loop, handle, req);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
|
||||
return uv__fast_poll_close(loop, handle);
|
||||
} else {
|
||||
return uv__slow_poll_close(loop, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->submitted_events_1 == 0);
|
||||
assert(handle->submitted_events_2 == 0);
|
||||
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
510
Utilities/cmlibuv/src/win/process-stdio.c
Normal file
510
Utilities/cmlibuv/src/win/process-stdio.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
/*
|
||||
* The `child_stdio_buffer` buffer has the following layout:
|
||||
* int number_of_fds
|
||||
* unsigned char crt_flags[number_of_fds]
|
||||
* HANDLE os_handle[number_of_fds]
|
||||
*/
|
||||
#define CHILD_STDIO_SIZE(count) \
|
||||
(sizeof(int) + \
|
||||
sizeof(unsigned char) * (count) + \
|
||||
sizeof(uintptr_t) * (count))
|
||||
|
||||
#define CHILD_STDIO_COUNT(buffer) \
|
||||
*((unsigned int*) (buffer))
|
||||
|
||||
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
|
||||
*((unsigned char*) (buffer) + sizeof(int) + fd)
|
||||
|
||||
#define CHILD_STDIO_HANDLE(buffer, fd) \
|
||||
*((HANDLE*) ((unsigned char*) (buffer) + \
|
||||
sizeof(int) + \
|
||||
sizeof(unsigned char) * \
|
||||
CHILD_STDIO_COUNT((buffer)) + \
|
||||
sizeof(HANDLE) * (fd)))
|
||||
|
||||
|
||||
/* CRT file descriptor mode flags */
|
||||
#define FOPEN 0x01
|
||||
#define FEOFLAG 0x02
|
||||
#define FCRLF 0x04
|
||||
#define FPIPE 0x08
|
||||
#define FNOINHERIT 0x10
|
||||
#define FAPPEND 0x20
|
||||
#define FDEV 0x40
|
||||
#define FTEXT 0x80
|
||||
|
||||
|
||||
/*
|
||||
* Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
|
||||
* the parent process. Don't check for errors - the stdio handles may not be
|
||||
* valid, or may be closed already. There is no guarantee that this function
|
||||
* does a perfect job.
|
||||
*/
|
||||
void uv_disable_stdio_inheritance(void) {
|
||||
HANDLE handle;
|
||||
STARTUPINFOW si;
|
||||
|
||||
/* Make the windows stdio handles non-inheritable. */
|
||||
handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
||||
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
||||
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
||||
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
||||
|
||||
/* Make inherited CRT FDs non-inheritable. */
|
||||
GetStartupInfoW(&si);
|
||||
if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
|
||||
uv__stdio_noinherit(si.lpReserved2);
|
||||
}
|
||||
|
||||
|
||||
static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
|
||||
char pipe_name[64];
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
DWORD server_access = 0;
|
||||
DWORD client_access = 0;
|
||||
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
||||
int err;
|
||||
|
||||
if (flags & UV_READABLE_PIPE) {
|
||||
/* The server needs inbound access too, otherwise CreateNamedPipe() */
|
||||
/* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
|
||||
/* probe the state of the write buffer when we're trying to shutdown */
|
||||
/* the pipe. */
|
||||
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
|
||||
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
||||
}
|
||||
if (flags & UV_WRITABLE_PIPE) {
|
||||
server_access |= PIPE_ACCESS_INBOUND;
|
||||
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
}
|
||||
|
||||
/* Create server pipe handle. */
|
||||
err = uv_stdio_pipe_server(loop,
|
||||
server_pipe,
|
||||
server_access,
|
||||
pipe_name,
|
||||
sizeof(pipe_name));
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Create child pipe handle. */
|
||||
sa.nLength = sizeof sa;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
child_pipe = CreateFileA(pipe_name,
|
||||
client_access,
|
||||
0,
|
||||
&sa,
|
||||
OPEN_EXISTING,
|
||||
server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
|
||||
NULL);
|
||||
if (child_pipe == INVALID_HANDLE_VALUE) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Validate that the pipe was opened in the right mode. */
|
||||
{
|
||||
DWORD mode;
|
||||
BOOL r = GetNamedPipeHandleState(child_pipe,
|
||||
&mode,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
assert(r == TRUE);
|
||||
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do a blocking ConnectNamedPipe. This should not block because we have */
|
||||
/* both ends of the pipe created. */
|
||||
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
|
||||
if (GetLastError() != ERROR_PIPE_CONNECTED) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* The server end is now readable and/or writable. */
|
||||
if (flags & UV_READABLE_PIPE)
|
||||
server_pipe->flags |= UV_HANDLE_WRITABLE;
|
||||
if (flags & UV_WRITABLE_PIPE)
|
||||
server_pipe->flags |= UV_HANDLE_READABLE;
|
||||
|
||||
*child_pipe_ptr = child_pipe;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
|
||||
uv_pipe_cleanup(loop, server_pipe);
|
||||
}
|
||||
|
||||
if (child_pipe != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(child_pipe);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
|
||||
HANDLE current_process;
|
||||
|
||||
|
||||
/* _get_osfhandle will sometimes return -2 in case of an error. This seems */
|
||||
/* to happen when fd <= 2 and the process' corresponding stdio handle is */
|
||||
/* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
|
||||
/* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
|
||||
/* use the duplicate. Therefore we filter out known-invalid handles here. */
|
||||
if (handle == INVALID_HANDLE_VALUE ||
|
||||
handle == NULL ||
|
||||
handle == (HANDLE) -2) {
|
||||
*dup = INVALID_HANDLE_VALUE;
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
current_process = GetCurrentProcess();
|
||||
|
||||
if (!DuplicateHandle(current_process,
|
||||
handle,
|
||||
current_process,
|
||||
dup,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
*dup = INVALID_HANDLE_VALUE;
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
|
||||
HANDLE handle;
|
||||
|
||||
if (fd == -1) {
|
||||
*dup = INVALID_HANDLE_VALUE;
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
handle = uv__get_osfhandle(fd);
|
||||
return uv__duplicate_handle(loop, handle, dup);
|
||||
}
|
||||
|
||||
|
||||
int uv__create_nul_handle(HANDLE* handle_ptr,
|
||||
DWORD access) {
|
||||
HANDLE handle;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
|
||||
sa.nLength = sizeof sa;
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
handle = CreateFileW(L"NUL",
|
||||
access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
&sa,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
*handle_ptr = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__stdio_create(uv_loop_t* loop,
|
||||
const uv_process_options_t* options,
|
||||
BYTE** buffer_ptr) {
|
||||
BYTE* buffer;
|
||||
int count, i;
|
||||
int err;
|
||||
|
||||
count = options->stdio_count;
|
||||
|
||||
if (count < 0 || count > 255) {
|
||||
/* Only support FDs 0-255 */
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
} else if (count < 3) {
|
||||
/* There should always be at least 3 stdio handles. */
|
||||
count = 3;
|
||||
}
|
||||
|
||||
/* Allocate the child stdio buffer */
|
||||
buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
|
||||
if (buffer == NULL) {
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
|
||||
/* clean up on failure. */
|
||||
CHILD_STDIO_COUNT(buffer) = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv_stdio_container_t fdopt;
|
||||
if (i < options->stdio_count) {
|
||||
fdopt = options->stdio[i];
|
||||
} else {
|
||||
fdopt.flags = UV_IGNORE;
|
||||
}
|
||||
|
||||
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
|
||||
UV_INHERIT_STREAM)) {
|
||||
case UV_IGNORE:
|
||||
/* Starting a process with no stdin/stout/stderr can confuse it. */
|
||||
/* So no matter what the user specified, we make sure the first */
|
||||
/* three FDs are always open in their typical modes, e.g. stdin */
|
||||
/* be readable and stdout/err should be writable. For FDs > 2, don't */
|
||||
/* do anything - all handles in the stdio buffer are initialized with */
|
||||
/* INVALID_HANDLE_VALUE, which should be okay. */
|
||||
if (i <= 2) {
|
||||
DWORD access = (i == 0) ? FILE_GENERIC_READ :
|
||||
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
|
||||
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
|
||||
access);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
||||
}
|
||||
break;
|
||||
|
||||
case UV_CREATE_PIPE: {
|
||||
/* Create a pair of two connected pipe ends; one end is turned into */
|
||||
/* an uv_pipe_t for use by the parent. The other one is given to */
|
||||
/* the child. */
|
||||
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
|
||||
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Create a new, connected pipe pair. stdio[i].stream should point */
|
||||
/* to an uninitialized, but not connected pipe handle. */
|
||||
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
|
||||
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
|
||||
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
|
||||
|
||||
err = uv__create_stdio_pipe_pair(loop,
|
||||
parent_pipe,
|
||||
&child_pipe,
|
||||
fdopt.flags);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
||||
break;
|
||||
}
|
||||
|
||||
case UV_INHERIT_FD: {
|
||||
/* Inherit a raw FD. */
|
||||
HANDLE child_handle;
|
||||
|
||||
/* Make an inheritable duplicate of the handle. */
|
||||
err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
|
||||
if (err) {
|
||||
/* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
|
||||
/* error. */
|
||||
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
||||
break;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Figure out what the type is. */
|
||||
switch (GetFileType(child_handle)) {
|
||||
case FILE_TYPE_DISK:
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
|
||||
break;
|
||||
|
||||
case FILE_TYPE_PIPE:
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
||||
|
||||
case FILE_TYPE_CHAR:
|
||||
case FILE_TYPE_REMOTE:
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
||||
break;
|
||||
|
||||
case FILE_TYPE_UNKNOWN:
|
||||
if (GetLastError() != 0) {
|
||||
err = GetLastError();
|
||||
CloseHandle(child_handle);
|
||||
goto error;
|
||||
}
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
||||
break;
|
||||
}
|
||||
|
||||
case UV_INHERIT_STREAM: {
|
||||
/* Use an existing stream as the stdio handle for the child. */
|
||||
HANDLE stream_handle, child_handle;
|
||||
unsigned char crt_flags;
|
||||
uv_stream_t* stream = fdopt.data.stream;
|
||||
|
||||
/* Leech the handle out of the stream. */
|
||||
if (stream->type == UV_TTY) {
|
||||
stream_handle = ((uv_tty_t*) stream)->handle;
|
||||
crt_flags = FOPEN | FDEV;
|
||||
} else if (stream->type == UV_NAMED_PIPE &&
|
||||
stream->flags & UV_HANDLE_CONNECTION) {
|
||||
stream_handle = ((uv_pipe_t*) stream)->handle;
|
||||
crt_flags = FOPEN | FPIPE;
|
||||
} else {
|
||||
stream_handle = INVALID_HANDLE_VALUE;
|
||||
crt_flags = 0;
|
||||
}
|
||||
|
||||
if (stream_handle == NULL ||
|
||||
stream_handle == INVALID_HANDLE_VALUE) {
|
||||
/* The handle is already closed, or not yet created, or the */
|
||||
/* stream type is not supported. */
|
||||
err = ERROR_NOT_SUPPORTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Make an inheritable copy of the handle. */
|
||||
err = uv__duplicate_handle(loop, stream_handle, &child_handle);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer_ptr = buffer;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv__stdio_destroy(buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void uv__stdio_destroy(BYTE* buffer) {
|
||||
int i, count;
|
||||
|
||||
count = CHILD_STDIO_COUNT(buffer);
|
||||
for (i = 0; i < count; i++) {
|
||||
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(buffer);
|
||||
}
|
||||
|
||||
|
||||
void uv__stdio_noinherit(BYTE* buffer) {
|
||||
int i, count;
|
||||
|
||||
count = CHILD_STDIO_COUNT(buffer);
|
||||
for (i = 0; i < count; i++) {
|
||||
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__stdio_verify(BYTE* buffer, WORD size) {
|
||||
unsigned int count;
|
||||
|
||||
/* Check the buffer pointer. */
|
||||
if (buffer == NULL)
|
||||
return 0;
|
||||
|
||||
/* Verify that the buffer is at least big enough to hold the count. */
|
||||
if (size < CHILD_STDIO_SIZE(0))
|
||||
return 0;
|
||||
|
||||
/* Verify if the count is within range. */
|
||||
count = CHILD_STDIO_COUNT(buffer);
|
||||
if (count > 256)
|
||||
return 0;
|
||||
|
||||
/* Verify that the buffer size is big enough to hold info for N FDs. */
|
||||
if (size < CHILD_STDIO_SIZE(count))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
WORD uv__stdio_size(BYTE* buffer) {
|
||||
return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
|
||||
}
|
||||
|
||||
|
||||
HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
|
||||
return CHILD_STDIO_HANDLE(buffer, fd);
|
||||
}
|
||||
1247
Utilities/cmlibuv/src/win/process.c
Normal file
1247
Utilities/cmlibuv/src/win/process.c
Normal file
File diff suppressed because it is too large
Load Diff
224
Utilities/cmlibuv/src/win/req-inl.h
Normal file
224
Utilities/cmlibuv/src/win/req-inl.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_WIN_REQ_INL_H_
|
||||
#define UV_WIN_REQ_INL_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#define SET_REQ_STATUS(req, status) \
|
||||
(req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
|
||||
|
||||
#define SET_REQ_ERROR(req, error) \
|
||||
SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
|
||||
|
||||
#define SET_REQ_SUCCESS(req) \
|
||||
SET_REQ_STATUS((req), STATUS_SUCCESS)
|
||||
|
||||
#define GET_REQ_STATUS(req) \
|
||||
((NTSTATUS) (req)->u.io.overlapped.Internal)
|
||||
|
||||
#define REQ_SUCCESS(req) \
|
||||
(NT_SUCCESS(GET_REQ_STATUS((req))))
|
||||
|
||||
#define GET_REQ_ERROR(req) \
|
||||
(pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
|
||||
|
||||
#define GET_REQ_SOCK_ERROR(req) \
|
||||
(uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
|
||||
|
||||
|
||||
#define REGISTER_HANDLE_REQ(loop, handle, req) \
|
||||
do { \
|
||||
INCREASE_ACTIVE_COUNT((loop), (handle)); \
|
||||
uv__req_register((loop), (req)); \
|
||||
} while (0)
|
||||
|
||||
#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
|
||||
do { \
|
||||
DECREASE_ACTIVE_COUNT((loop), (handle)); \
|
||||
uv__req_unregister((loop), (req)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
|
||||
((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
|
||||
|
||||
#define UV_SUCCEEDED_WITH_IOCP(result) \
|
||||
((result) || (GetLastError() == ERROR_IO_PENDING))
|
||||
|
||||
|
||||
#define POST_COMPLETION_FOR_REQ(loop, req) \
|
||||
if (!PostQueuedCompletionStatus((loop)->iocp, \
|
||||
0, \
|
||||
0, \
|
||||
&((req)->u.io.overlapped))) { \
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
|
||||
}
|
||||
|
||||
|
||||
INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
|
||||
req->type = UV_UNKNOWN_REQ;
|
||||
SET_REQ_SUCCESS(req);
|
||||
}
|
||||
|
||||
|
||||
INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
|
||||
return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
|
||||
}
|
||||
|
||||
|
||||
INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
|
||||
req->next_req = NULL;
|
||||
if (loop->pending_reqs_tail) {
|
||||
#ifdef _DEBUG
|
||||
/* Ensure the request is not already in the queue, or the queue
|
||||
* will get corrupted.
|
||||
*/
|
||||
uv_req_t* current = loop->pending_reqs_tail;
|
||||
do {
|
||||
assert(req != current);
|
||||
current = current->next_req;
|
||||
} while(current != loop->pending_reqs_tail);
|
||||
#endif
|
||||
|
||||
req->next_req = loop->pending_reqs_tail->next_req;
|
||||
loop->pending_reqs_tail->next_req = req;
|
||||
loop->pending_reqs_tail = req;
|
||||
} else {
|
||||
req->next_req = req;
|
||||
loop->pending_reqs_tail = req;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
|
||||
do { \
|
||||
switch (((uv_handle_t*) (req)->handle_at)->type) { \
|
||||
case UV_TCP: \
|
||||
uv_process_tcp_##method##_req(loop, \
|
||||
(uv_tcp_t*) ((req)->handle_at), \
|
||||
req); \
|
||||
break; \
|
||||
\
|
||||
case UV_NAMED_PIPE: \
|
||||
uv_process_pipe_##method##_req(loop, \
|
||||
(uv_pipe_t*) ((req)->handle_at), \
|
||||
req); \
|
||||
break; \
|
||||
\
|
||||
case UV_TTY: \
|
||||
uv_process_tty_##method##_req(loop, \
|
||||
(uv_tty_t*) ((req)->handle_at), \
|
||||
req); \
|
||||
break; \
|
||||
\
|
||||
default: \
|
||||
assert(0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
INLINE static int uv_process_reqs(uv_loop_t* loop) {
|
||||
uv_req_t* req;
|
||||
uv_req_t* first;
|
||||
uv_req_t* next;
|
||||
|
||||
if (loop->pending_reqs_tail == NULL)
|
||||
return 0;
|
||||
|
||||
first = loop->pending_reqs_tail->next_req;
|
||||
next = first;
|
||||
loop->pending_reqs_tail = NULL;
|
||||
|
||||
while (next != NULL) {
|
||||
req = next;
|
||||
next = req->next_req != first ? req->next_req : NULL;
|
||||
|
||||
switch (req->type) {
|
||||
case UV_READ:
|
||||
DELEGATE_STREAM_REQ(loop, req, read, data);
|
||||
break;
|
||||
|
||||
case UV_WRITE:
|
||||
DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
|
||||
break;
|
||||
|
||||
case UV_ACCEPT:
|
||||
DELEGATE_STREAM_REQ(loop, req, accept, data);
|
||||
break;
|
||||
|
||||
case UV_CONNECT:
|
||||
DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
|
||||
break;
|
||||
|
||||
case UV_SHUTDOWN:
|
||||
/* Tcp shutdown requests don't come here. */
|
||||
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
|
||||
uv_process_pipe_shutdown_req(
|
||||
loop,
|
||||
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
|
||||
(uv_shutdown_t*) req);
|
||||
break;
|
||||
|
||||
case UV_UDP_RECV:
|
||||
uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_UDP_SEND:
|
||||
uv_process_udp_send_req(loop,
|
||||
((uv_udp_send_t*) req)->handle,
|
||||
(uv_udp_send_t*) req);
|
||||
break;
|
||||
|
||||
case UV_WAKEUP:
|
||||
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_SIGNAL_REQ:
|
||||
uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_POLL_REQ:
|
||||
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_PROCESS_EXIT:
|
||||
uv_process_proc_exit(loop, (uv_process_t*) req->data);
|
||||
break;
|
||||
|
||||
case UV_FS_EVENT_REQ:
|
||||
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* UV_WIN_REQ_INL_H_ */
|
||||
25
Utilities/cmlibuv/src/win/req.c
Normal file
25
Utilities/cmlibuv/src/win/req.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
356
Utilities/cmlibuv/src/win/signal.c
Normal file
356
Utilities/cmlibuv/src/win/signal.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
RB_HEAD(uv_signal_tree_s, uv_signal_s);
|
||||
|
||||
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
|
||||
static ssize_t volatile uv__signal_control_handler_refs = 0;
|
||||
static CRITICAL_SECTION uv__signal_lock;
|
||||
|
||||
|
||||
void uv_signals_init() {
|
||||
InitializeCriticalSection(&uv__signal_lock);
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
/* Compare signums first so all watchers with the same signnum end up */
|
||||
/* adjacent. */
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Sort by loop pointer, so we can easily look up the first item after */
|
||||
/* { .signum = x, .loop = NULL } */
|
||||
if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
|
||||
if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
|
||||
|
||||
if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
|
||||
if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
|
||||
|
||||
|
||||
/*
|
||||
* Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
|
||||
* Returns 1 if the signal was dispatched to any watcher, or 0 if there were
|
||||
* no active signal watchers observing this signal.
|
||||
*/
|
||||
int uv__signal_dispatch(int signum) {
|
||||
uv_signal_t lookup;
|
||||
uv_signal_t* handle;
|
||||
int dispatched = 0;
|
||||
|
||||
EnterCriticalSection(&uv__signal_lock);
|
||||
|
||||
lookup.signum = signum;
|
||||
lookup.loop = NULL;
|
||||
|
||||
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
|
||||
handle != NULL && handle->signum == signum;
|
||||
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
|
||||
unsigned long previous = InterlockedExchange(
|
||||
(volatile LONG*) &handle->pending_signum, signum);
|
||||
|
||||
if (!previous) {
|
||||
POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
|
||||
}
|
||||
|
||||
dispatched = 1;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
|
||||
static BOOL WINAPI uv__signal_control_handler(DWORD type) {
|
||||
switch (type) {
|
||||
case CTRL_C_EVENT:
|
||||
return uv__signal_dispatch(SIGINT);
|
||||
|
||||
case CTRL_BREAK_EVENT:
|
||||
return uv__signal_dispatch(SIGBREAK);
|
||||
|
||||
case CTRL_CLOSE_EVENT:
|
||||
if (uv__signal_dispatch(SIGHUP)) {
|
||||
/* Windows will terminate the process after the control handler */
|
||||
/* returns. After that it will just terminate our process. Therefore */
|
||||
/* block the signal handler so the main loop has some time to pick */
|
||||
/* up the signal and do something for a few seconds. */
|
||||
Sleep(INFINITE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
/* These signals are only sent to services. Services have their own */
|
||||
/* notification mechanism, so there's no point in handling these. */
|
||||
|
||||
default:
|
||||
/* We don't handle these. */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register_control_handler() {
|
||||
/* When this function is called, the uv__signal_lock must be held. */
|
||||
|
||||
/* If the console control handler has already been hooked, just add a */
|
||||
/* reference. */
|
||||
if (uv__signal_control_handler_refs > 0) {
|
||||
uv__signal_control_handler_refs++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
|
||||
return GetLastError();
|
||||
|
||||
uv__signal_control_handler_refs++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister_control_handler() {
|
||||
/* When this function is called, the uv__signal_lock must be held. */
|
||||
BOOL r;
|
||||
|
||||
/* Don't unregister if the number of console control handlers exceeds one. */
|
||||
/* Just remove a reference in that case. */
|
||||
if (uv__signal_control_handler_refs > 1) {
|
||||
uv__signal_control_handler_refs--;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(uv__signal_control_handler_refs == 1);
|
||||
|
||||
r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
|
||||
/* This should never fail; if it does it is probably a bug in libuv. */
|
||||
assert(r);
|
||||
|
||||
uv__signal_control_handler_refs--;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register(int signum) {
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGBREAK:
|
||||
case SIGHUP:
|
||||
return uv__signal_register_control_handler();
|
||||
|
||||
case SIGWINCH:
|
||||
/* SIGWINCH is generated in tty.c. No need to register anything. */
|
||||
return 0;
|
||||
|
||||
case SIGILL:
|
||||
case SIGABRT_COMPAT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGTERM:
|
||||
case SIGABRT:
|
||||
/* Signal is never raised. */
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/* Invalid signal. */
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister(int signum) {
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGBREAK:
|
||||
case SIGHUP:
|
||||
uv__signal_unregister_control_handler();
|
||||
return;
|
||||
|
||||
case SIGWINCH:
|
||||
/* SIGWINCH is generated in tty.c. No need to unregister anything. */
|
||||
return;
|
||||
|
||||
case SIGILL:
|
||||
case SIGABRT_COMPAT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGTERM:
|
||||
case SIGABRT:
|
||||
/* Nothing is registered for this signal. */
|
||||
return;
|
||||
|
||||
default:
|
||||
/* Libuv bug. */
|
||||
assert(0 && "Invalid signum");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
uv_req_t* req;
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
|
||||
handle->pending_signum = 0;
|
||||
handle->signum = 0;
|
||||
handle->signal_cb = NULL;
|
||||
|
||||
req = &handle->signal_req;
|
||||
uv_req_init(loop, req);
|
||||
req->type = UV_SIGNAL_REQ;
|
||||
req->data = handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_stop(uv_signal_t* handle) {
|
||||
uv_signal_t* removed_handle;
|
||||
|
||||
/* If the watcher wasn't started, this is a no-op. */
|
||||
if (handle->signum == 0)
|
||||
return 0;
|
||||
|
||||
EnterCriticalSection(&uv__signal_lock);
|
||||
|
||||
uv__signal_unregister(handle->signum);
|
||||
|
||||
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
assert(removed_handle == handle);
|
||||
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
|
||||
handle->signum = 0;
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
|
||||
int err;
|
||||
|
||||
/* If the user supplies signum == 0, then return an error already. If the */
|
||||
/* signum is otherwise invalid then uv__signal_register will find out */
|
||||
/* eventually. */
|
||||
if (signum == 0) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
/* Short circuit: if the signal watcher is already watching {signum} don't */
|
||||
/* go through the process of deregistering and registering the handler. */
|
||||
/* Additionally, this avoids pending signals getting lost in the (small) */
|
||||
/* time frame that handle->signum == 0. */
|
||||
if (signum == handle->signum) {
|
||||
handle->signal_cb = signal_cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the signal handler was already active, stop it first. */
|
||||
if (handle->signum != 0) {
|
||||
int r = uv_signal_stop(handle);
|
||||
/* uv_signal_stop is infallible. */
|
||||
assert(r == 0);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&uv__signal_lock);
|
||||
|
||||
err = uv__signal_register(signum);
|
||||
if (err) {
|
||||
/* Uh-oh, didn't work. */
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
handle->signum = signum;
|
||||
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
|
||||
handle->signal_cb = signal_cb;
|
||||
uv__handle_start(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
|
||||
uv_req_t* req) {
|
||||
long dispatched_signum;
|
||||
|
||||
assert(handle->type == UV_SIGNAL);
|
||||
assert(req->type == UV_SIGNAL_REQ);
|
||||
|
||||
dispatched_signum = InterlockedExchange(
|
||||
(volatile LONG*) &handle->pending_signum, 0);
|
||||
assert(dispatched_signum != 0);
|
||||
|
||||
/* Check if the pending signal equals the signum that we are watching for. */
|
||||
/* These can get out of sync when the handler is stopped and restarted */
|
||||
/* while the signal_req is pending. */
|
||||
if (dispatched_signum == handle->signum)
|
||||
handle->signal_cb(handle, dispatched_signum);
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
/* When it is closing, it must be stopped at this point. */
|
||||
assert(handle->signum == 0);
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
uv_signal_stop(handle);
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->pending_signum == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->signum == 0);
|
||||
assert(handle->pending_signum == 0);
|
||||
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
42
Utilities/cmlibuv/src/win/snprintf.c
Normal file
42
Utilities/cmlibuv/src/win/snprintf.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Copyright the libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
|
||||
* on overflow...
|
||||
*/
|
||||
int snprintf(char* buf, size_t len, const char* fmt, ...) {
|
||||
int n;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
n = _vscprintf(fmt, ap);
|
||||
vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user