Merge branch 'master' into self-select-parse-fix

This commit is contained in:
Stan Bondi 2021-11-01 18:16:55 +04:00 committed by GitHub
commit af18c4571e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
401 changed files with 44736 additions and 13908 deletions

View file

@ -1,3 +1,90 @@
# v6.15.3
- [#2614](https://github.com/xmrig/xmrig/pull/2614) OpenCL fixes for non-AMD platforms.
- [#2623](https://github.com/xmrig/xmrig/pull/2623) Fixed compiling without kawpow.
- [#2636](https://github.com/xmrig/xmrig/pull/2636) [#2639](https://github.com/xmrig/xmrig/pull/2639) AstroBWT speedup (up to +35%).
- [#2646](https://github.com/xmrig/xmrig/pull/2646) Fixed MSVC compilation error.
# v6.15.2
- [#2606](https://github.com/xmrig/xmrig/pull/2606) Fixed: AstroBWT auto-config ignored `max-threads-hint`.
- Fixed possible crash on Windows (regression in v6.15.1).
# v6.15.1
- [#2586](https://github.com/xmrig/xmrig/pull/2586) Fixed Windows 7 compatibility.
- [#2594](https://github.com/xmrig/xmrig/pull/2594) Added Windows taskbar icon colors.
# v6.15.0
- [#2548](https://github.com/xmrig/xmrig/pull/2548) Added automatic coin detection for daemon mining.
- [#2563](https://github.com/xmrig/xmrig/pull/2563) Added new algorithm RandomX Graft (`rx/graft`).
- [#2565](https://github.com/xmrig/xmrig/pull/2565) AstroBWT: added AVX2 Salsa20 implementation.
- Added support for new CUDA plugin API (previous API still supported).
# v6.14.1
- [#2532](https://github.com/xmrig/xmrig/pull/2532) Refactoring: stable (persistent) algorithms IDs.
- [#2537](https://github.com/xmrig/xmrig/pull/2537) Fixed Termux build.
# v6.14.0
- [#2484](https://github.com/xmrig/xmrig/pull/2484) Added ZeroMQ support for solo mining.
- [#2476](https://github.com/xmrig/xmrig/issues/2476) Fixed crash in DMI memory reader.
- [#2492](https://github.com/xmrig/xmrig/issues/2492) Added missing `--huge-pages-jit` command line option.
- [#2512](https://github.com/xmrig/xmrig/pull/2512) Added show the number of transactions in pool job.
# v6.13.1
- [#2468](https://github.com/xmrig/xmrig/pull/2468) Fixed regression in previous version: don't send miner signature during regular mining.
# v6.13.0
- [#2445](https://github.com/xmrig/xmrig/pull/2445) Added support for solo mining with miner signatures for the upcoming Wownero fork.
# v6.12.2
- [#2280](https://github.com/xmrig/xmrig/issues/2280) GPU backends are now disabled in benchmark mode.
- [#2322](https://github.com/xmrig/xmrig/pull/2322) Improved MSR compatibility with recent Linux kernels and updated `randomx_boost.sh`.
- [#2340](https://github.com/xmrig/xmrig/pull/2340) Fixed AES detection on FreeBSD on ARM.
- [#2341](https://github.com/xmrig/xmrig/pull/2341) `sse2neon` updated to the latest version.
- [#2351](https://github.com/xmrig/xmrig/issues/2351) Fixed help output for `--cpu-priority` and `--cpu-affinity` option.
- [#2375](https://github.com/xmrig/xmrig/pull/2375) Fixed macOS CUDA backend default loader name.
- [#2378](https://github.com/xmrig/xmrig/pull/2378) Fixed broken light mode mining on x86.
- [#2379](https://github.com/xmrig/xmrig/pull/2379) Fixed CL code for KawPow where it assumes everything is AMD.
- [#2386](https://github.com/xmrig/xmrig/pull/2386) RandomX: enabled `IMUL_RCP` optimization for light mode mining.
- [#2393](https://github.com/xmrig/xmrig/pull/2393) RandomX: added BMI2 version for scratchpad prefetch.
- [#2395](https://github.com/xmrig/xmrig/pull/2395) RandomX: rewrote dataset read code.
- [#2398](https://github.com/xmrig/xmrig/pull/2398) RandomX: optimized ARMv8 dataset read.
- Added `argon2/ninja` alias for `argon2/wrkz` algorithm.
# v6.12.1
- [#2296](https://github.com/xmrig/xmrig/pull/2296) Fixed Zen3 assembly code for `cn/upx2` algorithm.
# v6.12.0
- [#2276](https://github.com/xmrig/xmrig/pull/2276) Added support for Uplexa (`cn/upx2` algorithm).
- [#2261](https://github.com/xmrig/xmrig/pull/2261) Show total hashrate if compiled without OpenCL.
- [#2289](https://github.com/xmrig/xmrig/pull/2289) RandomX: optimized `IMUL_RCP` instruction.
- Added support for `--user` command line option for online benchmark.
# v6.11.2
- [#2207](https://github.com/xmrig/xmrig/issues/2207) Fixed regression in HTTP parser and llhttp updated to v5.1.0.
# v6.11.1
- [#2239](https://github.com/xmrig/xmrig/pull/2239) Fixed broken `coin` setting functionality.
# v6.11.0
- [#2196](https://github.com/xmrig/xmrig/pull/2196) Improved DNS subsystem and added new DNS specific options.
- [#2172](https://github.com/xmrig/xmrig/pull/2172) Fixed build on Alpine 3.13.
- [#2177](https://github.com/xmrig/xmrig/pull/2177) Fixed ARM specific compilation error with GCC 10.2.
- [#2214](https://github.com/xmrig/xmrig/pull/2214) [#2216](https://github.com/xmrig/xmrig/pull/2216) [#2235](https://github.com/xmrig/xmrig/pull/2235) Optimized `cn-heavy` algorithm.
- [#2217](https://github.com/xmrig/xmrig/pull/2217) Fixed mining job creation sequence.
- [#2225](https://github.com/xmrig/xmrig/pull/2225) Fixed build without OpenCL support on some systems.
- [#2229](https://github.com/xmrig/xmrig/pull/2229) Don't use RandomX JIT if `WITH_ASM=OFF`.
- [#2228](https://github.com/xmrig/xmrig/pull/2228) Removed useless code for cryptonight algorithms.
- [#2234](https://github.com/xmrig/xmrig/pull/2234) Fixed build error on gcc 4.8.
# v6.10.0
- [#2122](https://github.com/xmrig/xmrig/pull/2122) Fixed pause logic when both pause on battery and user activity are enabled.
- [#2123](https://github.com/xmrig/xmrig/issues/2123) Fixed compatibility with gcc 4.8.
- [#2147](https://github.com/xmrig/xmrig/pull/2147) Fixed many `new job` messages when solo mining.
- [#2150](https://github.com/xmrig/xmrig/pull/2150) Updated `sse2neon.h` to the latest master, fixes build on ARMv7.
- [#2157](https://github.com/xmrig/xmrig/pull/2157) Fixed crash in `cn-heavy` on Zen3 with manual thread count.
- Fixed possible out of order write to log file.
- [http-parser](https://github.com/nodejs/http-parser) replaced to [llhttp](https://github.com/nodejs/llhttp).
- For official builds: libuv, hwloc and OpenSSL updated to latest versions.
# v6.9.0
- [#2104](https://github.com/xmrig/xmrig/pull/2104) Added [pause-on-active](https://xmrig.com/docs/miner/config/misc#pause-on-active) config option and `--pause-on-active=N` command line option.
- [#2112](https://github.com/xmrig/xmrig/pull/2112) Added support for [Tari merge mining](https://github.com/tari-project/tari/blob/development/README.md#tari-merge-mining).

View file

@ -5,6 +5,7 @@ option(WITH_HWLOC "Enable hwloc support" ON)
option(WITH_CN_LITE "Enable CryptoNight-Lite algorithms family" ON)
option(WITH_CN_HEAVY "Enable CryptoNight-Heavy algorithms family" ON)
option(WITH_CN_PICO "Enable CryptoNight-Pico algorithm" ON)
option(WITH_CN_FEMTO "Enable CryptoNight-UPX2 algorithm" ON)
option(WITH_RANDOMX "Enable RandomX algorithms family" ON)
option(WITH_ARGON2 "Enable Argon2 algorithms family" ON)
option(WITH_ASTROBWT "Enable AstroBWT algorithms family" ON)
@ -17,6 +18,8 @@ option(WITH_MSR "Enable MSR mod & 1st-gen Ryzen fix" ON)
option(WITH_ENV_VARS "Enable environment variables support in config file" ON)
option(WITH_EMBEDDED_CONFIG "Enable internal embedded JSON config" OFF)
option(WITH_OPENCL "Enable OpenCL backend" ON)
set(WITH_OPENCL_VERSION 200 CACHE STRING "Target OpenCL version")
set_property(CACHE WITH_OPENCL_VERSION PROPERTY STRINGS 120 200 210 220)
option(WITH_CUDA "Enable CUDA backend" ON)
option(WITH_NVML "Enable NVML (NVIDIA Management Library) support (only if CUDA backend enabled)" ON)
option(WITH_ADL "Enable ADL (AMD Display Library) or sysfs support (only if OpenCL backend enabled)" ON)
@ -55,6 +58,7 @@ set(HEADERS
src/core/config/usage.h
src/core/Controller.h
src/core/Miner.h
src/core/Taskbar.h
src/net/interfaces/IJobResultListener.h
src/net/JobResult.h
src/net/JobResults.h
@ -103,6 +107,7 @@ set(SOURCES
src/core/config/ConfigTransform.cpp
src/core/Controller.cpp
src/core/Miner.cpp
src/core/Taskbar.cpp
src/net/JobResults.cpp
src/net/Network.cpp
src/net/strategies/DonateStrategy.cpp
@ -196,6 +201,10 @@ if (WITH_CN_PICO)
add_definitions(/DXMRIG_ALGO_CN_PICO)
endif()
if (WITH_CN_FEMTO)
add_definitions(/DXMRIG_ALGO_CN_FEMTO)
endif()
if (WITH_EMBEDDED_CONFIG)
add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG)
endif()

View file

@ -23,6 +23,12 @@ if (WITH_ASTROBWT)
else()
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(/DASTROBWT_AVX2)
list(APPEND SOURCES_CRYPTO src/crypto/astrobwt/xmm6int/salsa20_xmm6int-avx2.c)
if (CMAKE_C_COMPILER_ID MATCHES GNU OR CMAKE_C_COMPILER_ID MATCHES Clang)
set_source_files_properties(src/crypto/astrobwt/xmm6int/salsa20_xmm6int-avx2.c PROPERTIES COMPILE_FLAGS -mavx2)
endif()
if (CMAKE_C_COMPILER_ID MATCHES MSVC)
enable_language(ASM_MASM)
list(APPEND SOURCES_CRYPTO src/crypto/astrobwt/sha3_256_avx2.asm)

View file

@ -1,9 +1,16 @@
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(XMRIG_64_BIT ON)
add_definitions(-DXMRIG_64_BIT)
else()
set(XMRIG_64_BIT OFF)
endif()
if (NOT CMAKE_SYSTEM_PROCESSOR)
message(WARNING "CMAKE_SYSTEM_PROCESSOR not defined")
endif()
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(/DRAPIDJSON_SSE2)
if (XMRIG_64_BIT AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
add_definitions(-DRAPIDJSON_SSE2)
else()
set(WITH_SSE4_1 OFF)
endif()
@ -17,31 +24,25 @@ if (NOT ARM_TARGET)
endif()
if (ARM_TARGET AND ARM_TARGET GREATER 6)
set(XMRIG_ARM ON)
add_definitions(/DXMRIG_ARM)
set(XMRIG_ARM ON)
add_definitions(-DXMRIG_ARM=${ARM_TARGET})
message(STATUS "Use ARM_TARGET=${ARM_TARGET} (${CMAKE_SYSTEM_PROCESSOR})")
include(CheckCXXCompilerFlag)
if (ARM_TARGET EQUAL 8)
set(XMRIG_ARMv8 ON)
add_definitions(/DXMRIG_ARMv8)
CHECK_CXX_COMPILER_FLAG(-march=armv8-a+crypto XMRIG_ARM_CRYPTO)
if (XMRIG_ARM_CRYPTO)
add_definitions(/DXMRIG_ARM_CRYPTO)
add_definitions(-DXMRIG_ARM_CRYPTO)
set(ARM8_CXX_FLAGS "-march=armv8-a+crypto")
else()
set(ARM8_CXX_FLAGS "-march=armv8-a")
endif()
elseif (ARM_TARGET EQUAL 7)
set(XMRIG_ARMv7 ON)
add_definitions(/DXMRIG_ARMv7)
endif()
endif()
if (WITH_SSE4_1)
add_definitions(/DXMRIG_FEATURE_SSE4_1)
add_definitions(-DXMRIG_FEATURE_SSE4_1)
endif()

View file

@ -22,10 +22,10 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexceptions -fno-rtti -Wno-strict-aliasing -Wno-class-memaccess")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -s")
if (XMRIG_ARMv8)
if (ARM_TARGET EQUAL 8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARM8_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARM8_CXX_FLAGS} -flax-vector-conversions")
elseif (XMRIG_ARMv7)
elseif (ARM_TARGET EQUAL 7)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -flax-vector-conversions")
else()
@ -80,10 +80,10 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexceptions -fno-rtti -Wno-missing-braces")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants")
if (XMRIG_ARMv8)
if (ARM_TARGET EQUAL 8)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARM8_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARM8_CXX_FLAGS}")
elseif (XMRIG_ARMv7)
elseif (ARM_TARGET EQUAL 7)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=${CMAKE_SYSTEM_PROCESSOR}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -march=${CMAKE_SYSTEM_PROCESSOR}")
else()

View file

@ -22,32 +22,31 @@ endif()
if (XMRIG_OS_WIN)
add_definitions(/DWIN32)
add_definitions(/DXMRIG_OS_WIN)
add_definitions(-DWIN32 -DXMRIG_OS_WIN)
elseif(XMRIG_OS_APPLE)
add_definitions(/DXMRIG_OS_APPLE)
add_definitions(-DXMRIG_OS_APPLE)
if (XMRIG_OS_IOS)
add_definitions(/DXMRIG_OS_IOS)
add_definitions(-DXMRIG_OS_IOS)
else()
add_definitions(/DXMRIG_OS_MACOS)
add_definitions(-DXMRIG_OS_MACOS)
endif()
if (XMRIG_ARM)
set(WITH_SECURE_JIT ON)
endif()
elseif(XMRIG_OS_UNIX)
add_definitions(/DXMRIG_OS_UNIX)
add_definitions(-DXMRIG_OS_UNIX)
if (XMRIG_OS_ANDROID)
add_definitions(/DXMRIG_OS_ANDROID)
add_definitions(-DXMRIG_OS_ANDROID)
elseif (XMRIG_OS_LINUX)
add_definitions(/DXMRIG_OS_LINUX)
add_definitions(-DXMRIG_OS_LINUX)
elseif (XMRIG_OS_FREEBSD)
add_definitions(/DXMRIG_OS_FREEBSD)
add_definitions(-DXMRIG_OS_FREEBSD)
endif()
endif()
if (WITH_SECURE_JIT)
add_definitions(/DXMRIG_SECURE_JIT)
add_definitions(-DXMRIG_SECURE_JIT)
endif()

View file

@ -42,13 +42,13 @@ if (WITH_RANDOMX)
src/crypto/rx/RxVm.cpp
)
if (CMAKE_C_COMPILER_ID MATCHES MSVC)
if (WITH_ASM AND CMAKE_C_COMPILER_ID MATCHES MSVC)
enable_language(ASM_MASM)
list(APPEND SOURCES_CRYPTO
src/crypto/randomx/jit_compiler_x86_static.asm
src/crypto/randomx/jit_compiler_x86.cpp
)
elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
elseif (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND SOURCES_CRYPTO
src/crypto/randomx/jit_compiler_x86_static.S
src/crypto/randomx/jit_compiler_x86.cpp

View file

@ -91,12 +91,12 @@ RandomX mining mode: `auto`, `fast` (2 GB memory), `light` (256 MB memory).
#### `1gb-pages`
Use 1GB hugepages for RandomX dataset (Linux only). Enabled (`true`) or disabled (`false`). It gives 1-3% speedup.
#### `wrmsr`
[MSR mod](https://xmrig.com/docs/miner/randomx-optimization-guide/msr). Enabled (`true`) or disabled (`false`). It gives up to 15% speedup depending on your system. _(**Note**: Userspace MSR writes are no longer enabled by default; the flag `msr.allow_writes=on` must be set for Linux Kernels 5.9 and after.)_
#### `rdmsr`
Restore MSR register values to their original values on exit. Used together with `wrmsr`. Enabled (`true`) or disabled (`false`).
#### `wrmsr`
[MSR mod](https://xmrig.com/docs/miner/randomx-optimization-guide/msr). Enabled (`true`) or disabled (`false`). It gives up to 15% speedup depending on your system.
#### `cache_qos`
[Cache QoS](https://xmrig.com/docs/miner/randomx-optimization-guide/qos). Enabled (`true`) or disabled (`false`). It's useful when you can't or don't want to mine on all CPU cores to make mining hashrate more stable.
@ -124,7 +124,7 @@ Force enable (`true`) or disable (`false`) hardware AES support. Default value `
Mining threads priority, value from `1` (lowest priority) to `5` (highest possible priority). Default value `null` means miner don't change threads priority at all. Setting priority higher than 2 can make your PC unresponsive.
#### `memory-pool` (since v4.3.0)
Use continuous, persistent memory block for mining threads, useful for preserve huge pages allocation while algorithm swithing. Possible values `false` (feature disabled, by default) or `true` or specific count of 2 MB huge pages. It helps to avoid loosing huge pages for scratchpads when RandomX dataset is updated and mining threads restart after a 2-3 days of mining.
Use continuous, persistent memory block for mining threads, useful for preserve huge pages allocation while algorithm switching. Possible values `false` (feature disabled, by default) or `true` or specific count of 2 MB huge pages. It helps to avoid loosing huge pages for scratchpads when RandomX dataset is updated and mining threads restart after a 2-3 days of mining.
#### `yield` (since v5.1.1)
Prefer system better system response/stability `true` (default value) or maximum hashrate `false`.

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
HWLOC_VERSION="2.4.0"
HWLOC_VERSION="2.5.0"
mkdir -p deps
mkdir -p deps/include
@ -8,7 +8,7 @@ mkdir -p deps/lib
mkdir -p build && cd build
wget https://download.open-mpi.org/release/hwloc/v2.4/hwloc-${HWLOC_VERSION}.tar.gz -O hwloc-${HWLOC_VERSION}.tar.gz
wget https://download.open-mpi.org/release/hwloc/v2.5/hwloc-${HWLOC_VERSION}.tar.gz -O hwloc-${HWLOC_VERSION}.tar.gz
tar -xzf hwloc-${HWLOC_VERSION}.tar.gz
cd hwloc-${HWLOC_VERSION}

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
OPENSSL_VERSION="1.1.1i"
OPENSSL_VERSION="1.1.1l"
mkdir -p deps
mkdir -p deps/include
@ -17,4 +17,4 @@ make -j$(nproc || sysctl -n hw.ncpu || sysctl -n hw.logicalcpu)
cp -fr include ../../deps
cp libcrypto.a ../../deps/lib
cp libssl.a ../../deps/lib
cd ..
cd ..

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
UV_VERSION="1.40.0"
UV_VERSION="1.42.0"
mkdir -p deps
mkdir -p deps/include

View file

@ -51,6 +51,7 @@ function rx()
'randomx_constants_wow.h',
'randomx_constants_arqma.h',
'randomx_constants_keva.h',
'randomx_constants_graft.h',
'aes.cl',
'blake2b.cl',
'randomx_vm.cl',

View file

@ -1,28 +1,34 @@
#!/bin/bash
#!/bin/sh -e
modprobe msr
MSR_FILE=/sys/module/msr/parameters/allow_writes
if cat /proc/cpuinfo | grep "AMD Ryzen" > /dev/null;
if test -e "$MSR_FILE"; then
echo on > $MSR_FILE
else
modprobe msr allow_writes=on
fi
if grep -E 'AMD Ryzen|AMD EPYC' /proc/cpuinfo > /dev/null;
then
if cat /proc/cpuinfo | grep "cpu family[[:space:]]:[[:space:]]25" > /dev/null;
if grep "cpu family[[:space:]]:[[:space:]]25" /proc/cpuinfo > /dev/null;
then
echo "Detected Ryzen (Zen3)"
echo "Detected Zen3 CPU"
wrmsr -a 0xc0011020 0x4480000000000
wrmsr -a 0xc0011021 0x1c000200000040
wrmsr -a 0xc0011022 0xc000000401500000
wrmsr -a 0xc001102b 0x2000cc14
echo "MSR register values for Ryzen (Zen3) applied"
echo "MSR register values for Zen3 applied"
else
echo "Detected Ryzen (Zen1/Zen2)"
echo "Detected Zen1/Zen2 CPU"
wrmsr -a 0xc0011020 0
wrmsr -a 0xc0011021 0x40
wrmsr -a 0xc0011022 0x1510000
wrmsr -a 0xc001102b 0x2000cc16
echo "MSR register values for Ryzen (Zen1/Zen2) applied"
echo "MSR register values for Zen1/Zen2 applied"
fi
elif cat /proc/cpuinfo | grep "Intel" > /dev/null;
elif grep "Intel" /proc/cpuinfo > /dev/null;
then
echo "Detected Intel"
echo "Detected Intel CPU"
wrmsr -a 0x1a4 0xf
echo "MSR register values for Intel applied"
else

25
src/3rdparty/epee/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,25 @@
Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
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 the Andrey N. Sabelnikov 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 Andrey N. Sabelnikov 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.

1
src/3rdparty/epee/README.md vendored Normal file
View file

@ -0,0 +1 @@
epee - is a small library of helpers, wrappers, tools and and so on, used to make my life easier.

176
src/3rdparty/epee/span.h vendored Normal file
View file

@ -0,0 +1,176 @@
// Copyright (c) 2017-2020, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder 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 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.
#pragma once
#include <algorithm>
#include <cstdint>
#include <memory>
#include <string>
#include <type_traits>
namespace epee
{
/*!
\brief Non-owning sequence of data. Does not deep copy
Inspired by `gsl::span` and/or `boost::iterator_range`. This class is
intended to be used as a parameter type for functions that need to take a
writable or read-only sequence of data. Most common cases are `span<char>`
and `span<std::uint8_t>`. Using as a class member is only recommended if
clearly documented as not doing a deep-copy. C-arrays are easily convertible
to this type.
\note Conversion from C string literal to `span<const char>` will include
the NULL-terminator.
\note Never allows derived-to-base pointer conversion; an array of derived
types is not an array of base types.
*/
template<typename T>
class span
{
template<typename U>
static constexpr bool safe_conversion() noexcept
{
// Allow exact matches or `T*` -> `const T*`.
using with_const = typename std::add_const<U>::type;
return std::is_same<T, U>() ||
(std::is_const<T>() && std::is_same<T, with_const>());
}
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
constexpr span() noexcept : ptr(nullptr), len(0) {}
constexpr span(std::nullptr_t) noexcept : span() {}
//! Prevent derived-to-base conversions; invalid in this context.
template<typename U, typename = typename std::enable_if<safe_conversion<U>()>::type>
constexpr span(U* const src_ptr, const std::size_t count) noexcept
: ptr(src_ptr), len(count) {}
//! Conversion from C-array. Prevents common bugs with sizeof + arrays.
template<std::size_t N>
constexpr span(T (&src)[N]) noexcept : span(src, N) {}
constexpr span(const span&) noexcept = default;
span& operator=(const span&) noexcept = default;
/*! Try to remove `amount` elements from beginning of span.
\return Number of elements removed. */
std::size_t remove_prefix(std::size_t amount) noexcept
{
amount = std::min(len, amount);
ptr += amount;
len -= amount;
return amount;
}
constexpr iterator begin() const noexcept { return ptr; }
constexpr const_iterator cbegin() const noexcept { return ptr; }
constexpr iterator end() const noexcept { return begin() + size(); }
constexpr const_iterator cend() const noexcept { return cbegin() + size(); }
constexpr bool empty() const noexcept { return size() == 0; }
constexpr pointer data() const noexcept { return ptr; }
constexpr std::size_t size() const noexcept { return len; }
constexpr std::size_t size_bytes() const noexcept { return size() * sizeof(value_type); }
T &operator[](size_t idx) noexcept { return ptr[idx]; }
const T &operator[](size_t idx) const noexcept { return ptr[idx]; }
private:
T* ptr;
std::size_t len;
};
//! \return `span<const T::value_type>` from a STL compatible `src`.
template<typename T>
constexpr span<const typename T::value_type> to_span(const T& src)
{
// compiler provides diagnostic if size() is not size_t.
return {src.data(), src.size()};
}
//! \return `span<T::value_type>` from a STL compatible `src`.
template<typename T>
constexpr span<typename T::value_type> to_mut_span(T& src)
{
// compiler provides diagnostic if size() is not size_t.
return {src.data(), src.size()};
}
template<typename T>
constexpr bool has_padding() noexcept
{
return !std::is_standard_layout<T>() || alignof(T) != 1;
}
//! \return Cast data from `src` as `span<const std::uint8_t>`.
template<typename T>
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
{
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
}
//! \return `span<const std::uint8_t>` which represents the bytes at `&src`.
template<typename T>
span<const std::uint8_t> as_byte_span(const T& src) noexcept
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
//! \return `span<std::uint8_t>` which represents the bytes at `&src`.
template<typename T>
span<std::uint8_t> as_mut_byte_span(T& src) noexcept
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
//! make a span from a std::string
template<typename T>
span<const T> strspan(const std::string &s) noexcept
{
static_assert(std::is_same<T, char>() || std::is_same<T, unsigned char>() || std::is_same<T, int8_t>() || std::is_same<T, uint8_t>(), "Unexpected type");
return {reinterpret_cast<const T*>(s.data()), s.size()};
}
}

View file

@ -109,11 +109,7 @@ char *optarg; /* argument associated with option */
extern char __declspec(dllimport) *__progname;
#endif
#ifdef __CYGWIN__
static char EMSG[] = "";
#else
#define EMSG ""
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);

View file

@ -1,68 +0,0 @@
# Authors ordered by first contribution.
Ryan Dahl <ry@tinyclouds.org>
Jeremy Hinegardner <jeremy@hinegardner.org>
Sergey Shepelev <temotor@gmail.com>
Joe Damato <ice799@gmail.com>
tomika <tomika_nospam@freemail.hu>
Phoenix Sol <phoenix@burninglabs.com>
Cliff Frey <cliff@meraki.com>
Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
Santiago Gala <sgala@apache.org>
Tim Becker <tim.becker@syngenio.de>
Jeff Terrace <jterrace@gmail.com>
Ben Noordhuis <info@bnoordhuis.nl>
Nathan Rajlich <nathan@tootallnate.net>
Mark Nottingham <mnot@mnot.net>
Aman Gupta <aman@tmm1.net>
Tim Becker <tim.becker@kuriositaet.de>
Sean Cunningham <sean.cunningham@mandiant.com>
Peter Griess <pg@std.in>
Salman Haq <salman.haq@asti-usa.com>
Cliff Frey <clifffrey@gmail.com>
Jon Kolb <jon@b0g.us>
Fouad Mardini <f.mardini@gmail.com>
Paul Querna <pquerna@apache.org>
Felix Geisendörfer <felix@debuggable.com>
koichik <koichik@improvement.jp>
Andre Caron <andre.l.caron@gmail.com>
Ivo Raisr <ivosh@ivosh.net>
James McLaughlin <jamie@lacewing-project.org>
David Gwynne <loki@animata.net>
Thomas LE ROUX <thomas@november-eleven.fr>
Randy Rizun <rrizun@ortivawireless.com>
Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
Simon Zimmermann <simonz05@gmail.com>
Erik Dubbelboer <erik@dubbelboer.com>
Martell Malone <martellmalone@gmail.com>
Bertrand Paquet <bpaquet@octo.com>
BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu>
Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com>
Patrik Stutz <patrik.stutz@gmail.com>
Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com>
David Wragg <david@wragg.org>
Vinnie Falco <vinnie.falco@gmail.com>
Alex Butum <alexbutum@linux.com>
Rex Feng <rexfeng@gmail.com>
Alex Kocharin <alex@kocharin.ru>
Mark Koopman <markmontymark@yahoo.com>
Helge Heß <me@helgehess.eu>
Alexis La Goutte <alexis.lagoutte@gmail.com>
George Miroshnykov <george.miroshnykov@gmail.com>
Maciej Małecki <me@mmalecki.com>
Marc O'Morain <github.com@marcomorain.com>
Jeff Pinner <jpinner@twitter.com>
Timothy J Fontaine <tjfontaine@gmail.com>
Akagi201 <akagi201@gmail.com>
Romain Giraud <giraud.romain@gmail.com>
Jay Satiro <raysatiro@yahoo.com>
Arne Steen <Arne.Steen@gmx.de>
Kjell Schubert <kjell.schubert@gmail.com>
Olivier Mengué <dolmen@cpan.org>

View file

@ -1,19 +0,0 @@
Copyright Joyent, Inc. and other Node 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.

View file

@ -1,246 +0,0 @@
HTTP Parser
===========
[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser)
This is a parser for HTTP messages written in C. It parses both requests and
responses. The parser is designed to be used in performance HTTP
applications. It does not make any syscalls nor allocations, it does not
buffer data, it can be interrupted at anytime. Depending on your
architecture, it only requires about 40 bytes of data per message
stream (in a web server that is per connection).
Features:
* No dependencies
* Handles persistent streams (keep-alive).
* Decodes chunked encoding.
* Upgrade support
* Defends against buffer overflow attacks.
The parser extracts the following information from HTTP messages:
* Header fields and values
* Content-Length
* Request method
* Response status code
* Transfer-Encoding
* HTTP version
* Request URL
* Message body
Usage
-----
One `http_parser` object is used per TCP connection. Initialize the struct
using `http_parser_init()` and set the callbacks. That might look something
like this for a request parser:
```c
http_parser_settings settings;
settings.on_url = my_url_callback;
settings.on_header_field = my_header_field_callback;
/* ... */
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST);
parser->data = my_socket;
```
When data is received on the socket execute the parser and check for errors.
```c
size_t len = 80*1024, nparsed;
char buf[len];
ssize_t recved;
recved = recv(fd, buf, len, 0);
if (recved < 0) {
/* Handle error. */
}
/* Start up / continue the parser.
* Note we pass recved==0 to signal that EOF has been received.
*/
nparsed = http_parser_execute(parser, &settings, buf, recved);
if (parser->upgrade) {
/* handle new protocol */
} else if (nparsed != recved) {
/* Handle error. Usually just close the connection. */
}
```
`http_parser` needs to know where the end of the stream is. For example, sometimes
servers send responses without Content-Length and expect the client to
consume input (for the body) until EOF. To tell `http_parser` about EOF, give
`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
can still be encountered during an EOF, so one must still be prepared
to receive them.
Scalar valued message information such as `status_code`, `method`, and the
HTTP version are stored in the parser structure. This data is only
temporally stored in `http_parser` and gets reset on each new message. If
this information is needed later, copy it out of the structure during the
`headers_complete` callback.
The parser decodes the transfer-encoding for both requests and responses
transparently. That is, a chunked encoding is decoded before being sent to
the on_body callback.
The Special Problem of Upgrade
------------------------------
`http_parser` supports upgrading the connection to a different protocol. An
increasingly common example of this is the WebSocket protocol which sends
a request like
GET /demo HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
WebSocket-Protocol: sample
followed by non-HTTP data.
(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
WebSocket protocol.)
To support this, the parser will treat this as a normal HTTP message without a
body, issuing both on_headers_complete and on_message_complete callbacks. However
http_parser_execute() will stop parsing at the end of the headers and return.
The user is expected to check if `parser->upgrade` has been set to 1 after
`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
offset by the return value of `http_parser_execute()`.
Callbacks
---------
During the `http_parser_execute()` call, the callbacks set in
`http_parser_settings` will be executed. The parser maintains state and
never looks behind, so buffering the data is not necessary. If you need to
save certain data for later usage, you can do that from the callbacks.
There are two types of callbacks:
* notification `typedef int (*http_cb) (http_parser*);`
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
Callbacks: (requests only) on_url,
(common) on_header_field, on_header_value, on_body;
Callbacks must return 0 on success. Returning a non-zero value indicates
error to the parser, making it exit immediately.
For cases where it is necessary to pass local information to/from a callback,
the `http_parser` object's `data` field can be used.
An example of such a case is when using threads to handle a socket connection,
parse a request, and then give a response over that socket. By instantiation
of a thread-local struct containing relevant data (e.g. accepted socket,
allocated memory for callbacks to write into, etc), a parser's callbacks are
able to communicate data between the scope of the thread and the scope of the
callback in a threadsafe manner. This allows `http_parser` to be used in
multi-threaded contexts.
Example:
```c
typedef struct {
socket_t sock;
void* buffer;
int buf_len;
} custom_data_t;
int my_url_callback(http_parser* parser, const char *at, size_t length) {
/* access to thread local custom_data_t struct.
Use this access save parsed data for later use into thread local
buffer, or communicate over socket
*/
parser->data;
...
return 0;
}
...
void http_parser_thread(socket_t sock) {
int nparsed = 0;
/* allocate memory for user data */
custom_data_t *my_data = malloc(sizeof(custom_data_t));
/* some information for use by callbacks.
* achieves thread -> callback information flow */
my_data->sock = sock;
/* instantiate a thread-local parser */
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
/* this custom data reference is accessible through the reference to the
parser supplied to callback functions */
parser->data = my_data;
http_parser_settings settings; /* set up callbacks */
settings.on_url = my_url_callback;
/* execute parser */
nparsed = http_parser_execute(parser, &settings, buf, recved);
...
/* parsed information copied from callback.
can now perform action on data copied into thread-local memory from callbacks.
achieves callback -> thread information flow */
my_data->buffer;
...
}
```
In case you parse HTTP message in chunks (i.e. `read()` request line
from socket, parse, read half headers, parse, etc) your data callbacks
may be called more than once. `http_parser` guarantees that data pointer is only
valid for the lifetime of callback. You can also `read()` into a heap allocated
buffer to avoid copying memory around if this fits your application.
Reading headers may be a tricky task if you read/parse headers partially.
Basically, you need to remember whether last header callback was field or value
and apply the following logic:
(on_header_field and on_header_value shortened to on_h_*)
------------------------ ------------ --------------------------------------------
| State (prev. callback) | Callback | Description/action |
------------------------ ------------ --------------------------------------------
| nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
| | | into it |
------------------------ ------------ --------------------------------------------
| value | on_h_field | New header started. |
| | | Copy current name,value buffers to headers |
| | | list and allocate new buffer for new name |
------------------------ ------------ --------------------------------------------
| field | on_h_field | Previous name continues. Reallocate name |
| | | buffer and append callback data to it |
------------------------ ------------ --------------------------------------------
| field | on_h_value | Value for current header started. Allocate |
| | | new buffer and copy callback data to it |
------------------------ ------------ --------------------------------------------
| value | on_h_value | Value continues. Reallocate value buffer |
| | | and append callback data to it |
------------------------ ------------ --------------------------------------------
Parsing URLs
------------
A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
Users of this library may wish to use it to parse URLs constructed from
consecutive `on_url` callbacks.
See examples of reading in headers:
* [partial example](http://gist.github.com/155877) in C
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript

File diff suppressed because it is too large Load diff

View file

@ -1,442 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 9
#define HTTP_PARSER_VERSION_PATCH 3
#include <stddef.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Status Codes */
#define HTTP_STATUS_MAP(XX) \
XX(100, CONTINUE, Continue) \
XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
XX(102, PROCESSING, Processing) \
XX(200, OK, OK) \
XX(201, CREATED, Created) \
XX(202, ACCEPTED, Accepted) \
XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
XX(204, NO_CONTENT, No Content) \
XX(205, RESET_CONTENT, Reset Content) \
XX(206, PARTIAL_CONTENT, Partial Content) \
XX(207, MULTI_STATUS, Multi-Status) \
XX(208, ALREADY_REPORTED, Already Reported) \
XX(226, IM_USED, IM Used) \
XX(300, MULTIPLE_CHOICES, Multiple Choices) \
XX(301, MOVED_PERMANENTLY, Moved Permanently) \
XX(302, FOUND, Found) \
XX(303, SEE_OTHER, See Other) \
XX(304, NOT_MODIFIED, Not Modified) \
XX(305, USE_PROXY, Use Proxy) \
XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
XX(400, BAD_REQUEST, Bad Request) \
XX(401, UNAUTHORIZED, Unauthorized) \
XX(402, PAYMENT_REQUIRED, Payment Required) \
XX(403, FORBIDDEN, Forbidden) \
XX(404, NOT_FOUND, Not Found) \
XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
XX(406, NOT_ACCEPTABLE, Not Acceptable) \
XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
XX(408, REQUEST_TIMEOUT, Request Timeout) \
XX(409, CONFLICT, Conflict) \
XX(410, GONE, Gone) \
XX(411, LENGTH_REQUIRED, Length Required) \
XX(412, PRECONDITION_FAILED, Precondition Failed) \
XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
XX(414, URI_TOO_LONG, URI Too Long) \
XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
XX(417, EXPECTATION_FAILED, Expectation Failed) \
XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
XX(423, LOCKED, Locked) \
XX(424, FAILED_DEPENDENCY, Failed Dependency) \
XX(426, UPGRADE_REQUIRED, Upgrade Required) \
XX(428, PRECONDITION_REQUIRED, Precondition Required) \
XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
XX(501, NOT_IMPLEMENTED, Not Implemented) \
XX(502, BAD_GATEWAY, Bad Gateway) \
XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
XX(508, LOOP_DETECTED, Loop Detected) \
XX(510, NOT_EXTENDED, Not Extended) \
XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
enum http_status
{
#define XX(num, name, string) HTTP_STATUS_##name = num,
HTTP_STATUS_MAP(XX)
#undef XX
};
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* WebDAV */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
/* upnp */ \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
/* icecast */ \
XX(33, SOURCE, SOURCE) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
, F_TRANSFER_ENCODING = 1 << 8
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_TRANSFER_ENCODING, \
"request has invalid transfer-encoding") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 7; /* index into current matcher */
unsigned int lenient_http_headers : 1;
unsigned int flags : 16; /* F_* values from 'flags' enum; semi-public */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Returns a string version of the HTTP status code. */
const char *http_status_str(enum http_status s);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
/* Change the maximum header size provided at compile time. */
void http_parser_set_max_header_size(uint32_t size);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,5 +1,5 @@
Copyright © 2009 CNRS
Copyright © 2009-2020 Inria. All rights reserved.
Copyright © 2009-2021 Inria. All rights reserved.
Copyright © 2009-2013 Université Bordeaux
Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
Copyright © 2020 Hewlett Packard Enterprise. All rights reserved.
@ -17,6 +17,76 @@ bug fixes (and other actions) for each version of hwloc since version
0.9.
Version 2.5.0
-------------
* API
+ Add hwloc/windows.h to query Windows processor groups.
+ Add hwloc_get_obj_with_same_locality() to convert between objects
with same locality, for instance NUMA nodes and Packages,
or OS devices within a PCI device.
+ Add hwloc_distances_transform() to modify distances structures.
- hwloc-annotate and lstopo have new distances-transform options.
+ hwloc_distances_add() is replaced with _add_create() followed by
_add_values() and _add_commit(). See hwloc/distances.h for details.
+ Add topology flags to mitigate binding modifications during
hwloc discovery, especially on Windows:
- HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING and _MEMBINDING
restrict discovery to PUs and NUMA nodes inside the binding.
- HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING prevents from ever
changing the binding during discovery.
* Backends
+ Add a levelzero backend for oneAPI L0 devices, exposed as OS devices
of subtype "LevelZero" and name such as "ze0".
- Add hwloc/levelzero.h for interoperability between converting
between L0 API devices and hwloc cpusets or OS devices.
+ Expose NEC Vector Engine cards on Linux as OS devices of subtype
"VectorEngine" and name "ve0", etc.
Thanks to Anara Kozhokanova, Tim Cramer and Erich Focht for the help.
+ Add a NVLinkBandwidth distances structure between NVIDIA GPUs
(and POWER processor or NVSwitches) in the NVML backend,
and a XGMIBandwidth distances structure between AMD GPUs
in the RSMI backends.
- See "Topology Attributes: Distances, Memory Attributes and CPU Kinds"
in the documentation for details about these new distances.
+ Add support for NUMA node 0 being offline in Linux, thanks to Jirka Hladky.
* Build
+ Add --with-cuda-version=<version> or look at the CUDA_VERSION
environment variable to find the appropriate CUDA pkg-config files.
Thanks to Stephen Herbein for the suggestion.
- Also add --with-cuda=<dir> to specify the CUDA installation path
manually (and its NVML and OpenCL components).
Thanks to Andrea Bocci for the suggestion.
- See "How do I enable CUDA and select which CUDA version to use?"
in the FAQ for details.
* Tools
+ lstopo now has a --windows-processor-groups option on Windows.
+ hwloc-ps now has a --short-name option to avoid long/truncated
command path.
+ hwloc-ps now has a --single-ancestor option to return a single
(possibly too large) object where a process is bound.
+ hwloc-ps --pid-cmd may now query environment variables,
including MPI-specific variables to find out process ranks.
Version 2.4.1
-------------
* Fix AMD OpenCL device locality when PCI bus or device number >= 128.
Thanks to Edgar Leon for reporting the issue.
+ Applications using any of the following inline functions must
be recompiled to get the fix: hwloc_opencl_get_device_pci_busid()
hwloc_opencl_get_device_cpuset(), hwloc_opencl_get_device_osdev().
* Fix the ranking of cpukinds on non-Windows systems,
thanks to Ivan Kochin for the report.
* Fix the insertion of custom Groups after loading the topology,
thanks to Scott Hicks.
* Add support for CPU0 being offline in Linux, thanks to Garrett Clay.
* Fix missing x86 Package and Core objects FreeBSD/NetBSD.
Thanks to Thibault Payet and Yuri Victorovich for the report.
* Fix the import of very large distances with heterogeneous object types.
* Fix a memory leak in the Linux backend,
thanks to Perceval Anichini.
Version 2.4.0
-------------
* API

View file

@ -8,7 +8,7 @@
# Please update HWLOC_VERSION* in contrib/windows/hwloc_config.h too.
major=2
minor=4
minor=5
release=0
# greek is used for alpha or beta release tags. If it is non-empty,
@ -22,7 +22,7 @@ greek=
# The date when this release was created
date="Nov 26, 2020"
date="Jun 14, 2021"
# If snapshot=1, then use the value from snapshot_version as the
# entire hwloc version (i.e., ignore major, minor, release, and
@ -41,7 +41,7 @@ snapshot_version=${major}.${minor}.${release}${greek}-git
# 2. Version numbers are described in the Libtool current:revision:age
# format.
libhwloc_so_version=19:0:4
libhwloc_so_version=20:0:5
libnetloc_so_version=0:0:0
# Please also update the <TargetName> lines in contrib/windows/libhwloc.vcxproj

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2020 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -93,7 +93,7 @@ extern "C" {
* Two stable releases of the same series usually have the same ::HWLOC_API_VERSION
* even if their HWLOC_VERSION are different.
*/
#define HWLOC_API_VERSION 0x00020400
#define HWLOC_API_VERSION 0x00020500
/** \brief Indicate at runtime which hwloc API version was used at build time.
*
@ -1966,7 +1966,69 @@ enum hwloc_topology_flags_e {
* hwloc and machine support.
*
*/
HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT = (1UL<<3)
HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT = (1UL<<3),
/** \brief Do not consider resources outside of the process CPU binding.
*
* If the binding of the process is limited to a subset of cores,
* ignore the other cores during discovery.
*
* The resulting topology is identical to what a call to hwloc_topology_restrict()
* would generate, but this flag also prevents hwloc from ever touching other
* resources during the discovery.
*
* This flag especially tells the x86 backend to never temporarily
* rebind a thread on any excluded core. This is useful on Windows
* because such temporary rebinding can change the process binding.
* Another use-case is to avoid cores that would not be able to
* perform the hwloc discovery anytime soon because they are busy
* executing some high-priority real-time tasks.
*
* If process CPU binding is not supported,
* the thread CPU binding is considered instead if supported,
* or the flag is ignored.
*
* This flag requires ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM as well
* since binding support is required.
*/
HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING = (1UL<<4),
/** \brief Do not consider resources outside of the process memory binding.
*
* If the binding of the process is limited to a subset of NUMA nodes,
* ignore the other NUMA nodes during discovery.
*
* The resulting topology is identical to what a call to hwloc_topology_restrict()
* would generate, but this flag also prevents hwloc from ever touching other
* resources during the discovery.
*
* This flag is meant to be used together with
* ::HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING when both cores
* and NUMA nodes should be ignored outside of the process binding.
*
* If process memory binding is not supported,
* the thread memory binding is considered instead if supported,
* or the flag is ignored.
*
* This flag requires ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM as well
* since binding support is required.
*/
HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING = (1UL<<5),
/** \brief Do not ever modify the process or thread binding during discovery.
*
* This flag disables all hwloc discovery steps that require a change of
* the process or thread binding. This currently only affects the x86
* backend which gets entirely disabled.
*
* This is useful when hwloc_topology_load() is called while the
* application also creates additional threads or modifies the binding.
*
* This flag is also a strict way to make sure the process binding will
* not change to due thread binding changes on Windows
* (see ::HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING).
*/
HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING = (1UL<<6)
};
/** \brief Set OR'ed flags to non-yet-loaded topology.
@ -2362,22 +2424,9 @@ HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_insert_misc_object(hwloc_topology_t to
/** \brief Allocate a Group object to insert later with hwloc_topology_insert_group_object().
*
* This function returns a new Group object.
* The caller should (at least) initialize its sets before inserting the object.
* See hwloc_topology_insert_group_object().
*
* The \p subtype object attribute may be set to display something else
* than "Group" as the type name for this object in lstopo.
* Custom name/value info pairs may be added with hwloc_obj_add_info() after
* insertion.
*
* The \p kind group attribute should be 0. The \p subkind group attribute may
* be set to identify multiple Groups of the same level.
*
* It is recommended not to set any other object attribute before insertion,
* since the Group may get discarded during insertion.
*
* The object will be destroyed if passed to hwloc_topology_insert_group_object()
* without any set defined.
* The caller should (at least) initialize its sets before inserting
* the object in the topology. See hwloc_topology_insert_group_object().
*/
HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_alloc_group_object(hwloc_topology_t topology);
@ -2388,34 +2437,44 @@ HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_alloc_group_object(hwloc_topology_t to
* the final location of the Group in the topology.
* Then the object can be passed to this function for actual insertion in the topology.
*
* The group \p dont_merge attribute may be set to prevent the core from
* ever merging this object with another object hierarchically-identical.
*
* Either the cpuset or nodeset field (or both, if compatible) must be set
* to a non-empty bitmap. The complete_cpuset or complete_nodeset may be set
* instead if inserting with respect to the complete topology
* (including disallowed, offline or unknown objects).
*
* It grouping several objects, hwloc_obj_add_other_obj_sets() is an easy way
* If grouping several objects, hwloc_obj_add_other_obj_sets() is an easy way
* to build the Group sets iteratively.
*
* These sets cannot be larger than the current topology, or they would get
* restricted silently.
*
* The core will setup the other sets after actual insertion.
*
* The \p subtype object attribute may be defined (to a dynamically
* allocated string) to display something else than "Group" as the
* type name for this object in lstopo.
* Custom name/value info pairs may be added with hwloc_obj_add_info() after
* insertion.
*
* The group \p dont_merge attribute may be set to \c 1 to prevent
* the hwloc core from ever merging this object with another
* hierarchically-identical object.
* This is useful when the Group itself describes an important feature
* that cannot be exposed anywhere else in the hierarchy.
*
* The group \p kind attribute may be set to a high value such
* as \c 0xffffffff to tell hwloc that this new Group should always
* be discarded in favor of any existing Group with the same locality.
*
* \return The inserted object if it was properly inserted.
*
* \return An existing object if the Group was discarded because the topology already
* contained an object at the same location (the Group did not add any locality information).
* Any name/info key pair set before inserting is appended to the existing object.
* \return An existing object if the Group was merged or discarded
* because the topology already contained an object at the same
* location (the Group did not add any hierarchy information).
*
* \return \c NULL if the insertion failed because of conflicting sets in topology tree.
*
* \return \c NULL if Group objects are filtered-out of the topology (::HWLOC_TYPE_FILTER_KEEP_NONE).
*
* \return \c NULL if the object was discarded because no set was initialized in the Group
* before insert, or all of them were empty.
* \return \c NULL if the object was discarded because no set was
* initialized in the Group before insert, or all of them were empty.
*/
HWLOC_DECLSPEC hwloc_obj_t hwloc_topology_insert_group_object(hwloc_topology_t topology, hwloc_obj_t group);

View file

@ -11,9 +11,9 @@
#ifndef HWLOC_CONFIG_H
#define HWLOC_CONFIG_H
#define HWLOC_VERSION "2.4.0"
#define HWLOC_VERSION "2.5.0"
#define HWLOC_VERSION_MAJOR 2
#define HWLOC_VERSION_MINOR 4
#define HWLOC_VERSION_MINOR 5
#define HWLOC_VERSION_RELEASE 0
#define HWLOC_VERSION_GREEK ""

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* Copyright © 2010-2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -75,7 +75,7 @@ hwloc_cuda_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unused
/** \brief Get the CPU set of processors that are physically
* close to device \p cudevice.
*
* Return the CPU set describing the locality of the CUDA device \p cudevice.
* Store in \p set the CPU-set describing the locality of the CUDA device \p cudevice.
*
* Topology \p topology and device \p cudevice must match the local machine.
* I/O devices detection and the CUDA component are not needed in the topology.
@ -120,8 +120,8 @@ hwloc_cuda_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
/** \brief Get the hwloc PCI device object corresponding to the
* CUDA device \p cudevice.
*
* Return the PCI device object describing the CUDA device \p cudevice.
* Return NULL if there is none.
* \return The hwloc PCI device object describing the CUDA device \p cudevice.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p cudevice must match the local machine.
* I/O devices detection must be enabled in topology \p topology.
@ -140,8 +140,8 @@ hwloc_cuda_get_device_pcidev(hwloc_topology_t topology, CUdevice cudevice)
/** \brief Get the hwloc OS device object corresponding to CUDA device \p cudevice.
*
* Return the hwloc OS device object that describes the given
* CUDA device \p cudevice. Return NULL if there is none.
* \return The hwloc OS device object that describes the given CUDA device \p cudevice.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p cudevice must match the local machine.
* I/O devices detection and the CUDA component must be enabled in the topology.
@ -183,8 +183,8 @@ hwloc_cuda_get_device_osdev(hwloc_topology_t topology, CUdevice cudevice)
/** \brief Get the hwloc OS device object corresponding to the
* CUDA device whose index is \p idx.
*
* Return the OS device object describing the CUDA device whose
* index is \p idx. Return NULL if there is none.
* \return The hwloc OS device object describing the CUDA device whose index is \p idx.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* Copyright © 2010-2011 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -72,7 +72,7 @@ hwloc_cudart_get_device_pci_ids(hwloc_topology_t topology __hwloc_attribute_unus
/** \brief Get the CPU set of processors that are physically
* close to device \p idx.
*
* Return the CPU set describing the locality of the CUDA device
* Store in \p set the CPU-set describing the locality of the CUDA device
* whose index is \p idx.
*
* Topology \p topology and device \p idx must match the local machine.
@ -117,8 +117,8 @@ hwloc_cudart_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unuse
/** \brief Get the hwloc PCI device object corresponding to the
* CUDA device whose index is \p idx.
*
* Return the PCI device object describing the CUDA device whose
* index is \p idx. Return NULL if there is none.
* \return The hwloc PCI device object describing the CUDA device whose index is \p idx.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p idx must match the local machine.
* I/O devices detection must be enabled in topology \p topology.
@ -138,8 +138,8 @@ hwloc_cudart_get_device_pcidev(hwloc_topology_t topology, int idx)
/** \brief Get the hwloc OS device object corresponding to the
* CUDA device whose index is \p idx.
*
* Return the OS device object describing the CUDA device whose
* index is \p idx. Return NULL if there is none.
* \return The hwloc OS device object describing the CUDA device whose index is \p idx.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2018 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -30,6 +30,15 @@ extern "C" {
/* backward compat with v1.10 before Node->NUMANode clarification */
#define HWLOC_OBJ_NODE HWLOC_OBJ_NUMANODE
/** \brief Add a distances structure.
*
* Superseded by hwloc_distances_add_create()+hwloc_distances_add_values()+hwloc_distances_add_commit()
* in v2.5.
*/
HWLOC_DECLSPEC int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
unsigned long kind, unsigned long flags) __hwloc_attribute_deprecated;
/** \brief Insert a misc object by parent.
*
* Identical to hwloc_topology_insert_misc_object().

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -35,9 +35,19 @@ extern "C" {
* from a core in another node.
* The corresponding kind is ::HWLOC_DISTANCES_KIND_FROM_OS | ::HWLOC_DISTANCES_KIND_FROM_USER.
* The name of this distances structure is "NUMALatency".
* Others distance structures include and "XGMIBandwidth" and "NVLinkBandwidth".
*
* The matrix may also contain bandwidths between random sets of objects,
* possibly provided by the user, as specified in the \p kind attribute.
*
* Pointers \p objs and \p values should not be replaced, reallocated, freed, etc.
* However callers are allowed to modify \p kind as well as the contents
* of \p objs and \p values arrays.
* For instance, if there is a single NUMA node per Package,
* hwloc_get_obj_with_same_locality() may be used to convert between them
* and replace NUMA nodes in the \p objs array with the corresponding Packages.
* See also hwloc_distances_transform() for applying some transformations
* to the structure.
*/
struct hwloc_distances_s {
unsigned nbobjs; /**< \brief Number of objects described by the distance matrix. */
@ -91,6 +101,8 @@ enum hwloc_distances_kind_e {
HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH = (1UL<<3),
/** \brief This distances structure covers objects of different types.
* This may apply to the "NVLinkBandwidth" structure in presence
* of a NVSwitch or POWER processor NVLink port.
* \hideinitializer
*/
HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES = (1UL<<4)
@ -147,6 +159,7 @@ hwloc_distances_get_by_type(hwloc_topology_t topology, hwloc_obj_type_t type,
* Usually only one distances structure may match a given name.
*
* The name of the most common structure is "NUMALatency".
* Others include "XGMIBandwidth" and "NVLinkBandwidth".
*/
HWLOC_DECLSPEC int
hwloc_distances_get_by_name(hwloc_topology_t topology, const char *name,
@ -168,6 +181,85 @@ hwloc_distances_get_name(hwloc_topology_t topology, struct hwloc_distances_s *di
HWLOC_DECLSPEC void
hwloc_distances_release(hwloc_topology_t topology, struct hwloc_distances_s *distances);
/** \brief Transformations of distances structures. */
enum hwloc_distances_transform_e {
/** \brief Remove \c NULL objects from the distances structure.
*
* Every object that was replaced with \c NULL in the \p objs array
* is removed and the \p values array is updated accordingly.
*
* At least \c 2 objects must remain, otherwise hwloc_distances_transform()
* will return \c -1 with \p errno set to \c EINVAL.
*
* \p kind will be updated with or without ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES
* according to the remaining objects.
*
* \hideinitializer
*/
HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL = 0,
/** \brief Replace bandwidth values with a number of links.
*
* Usually all values will be either \c 0 (no link) or \c 1 (one link).
* However some matrices could get larger values if some pairs of
* peers are connected by different numbers of links.
*
* Values on the diagonal are set to \c 0.
*
* This transformation only applies to bandwidth matrices.
*
* \hideinitializer
*/
HWLOC_DISTANCES_TRANSFORM_LINKS = 1,
/** \brief Merge switches with multiple ports into a single object.
* This currently only applies to NVSwitches where GPUs seem connected to different
* separate switch ports in the NVLinkBandwidth matrix. This transformation will
* replace all of them with the same port connected to all GPUs.
* Other ports are removed by applying ::HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL internally.
* \hideinitializer
*/
HWLOC_DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS = 2,
/** \brief Apply a transitive closure to the matrix to connect objects across switches.
* This currently only applies to GPUs and NVSwitches in the NVLinkBandwidth matrix.
* All pairs of GPUs will be reported as directly connected.
* \hideinitializer
*/
HWLOC_DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE = 3
};
/** \brief Apply a transformation to a distances structure.
*
* Modify a distances structure that was previously obtained with
* hwloc_distances_get() or one of its variants.
*
* This modifies the local copy of the distances structures but does
* not modify the distances information stored inside the topology
* (retrieved by another call to hwloc_distances_get() or exported to XML).
* To do so, one should add a new distances structure with same
* name, kind, objects and values (see \ref hwlocality_distances_add)
* and then remove this old one with hwloc_distances_release_remove().
*
* \p transform must be one of the transformations listed
* in ::hwloc_distances_transform_e.
*
* These transformations may modify the contents of the \p objs or \p values arrays.
*
* \p transform_attr must be \c NULL for now.
*
* \p flags must be \c 0 for now.
*
* \note Objects in distances array \p objs may be directly modified
* in place without using hwloc_distances_transform().
* One may use hwloc_get_obj_with_same_locality() to easily convert
* between similar objects of different types.
*/
HWLOC_DECLSPEC int hwloc_distances_transform(hwloc_topology_t topology, struct hwloc_distances_s *distances,
enum hwloc_distances_transform_e transform,
void *transform_attr,
unsigned long flags);
/** @} */
@ -215,13 +307,84 @@ hwloc_distances_obj_pair_values(struct hwloc_distances_s *distances,
/** \defgroup hwlocality_distances_add Add or remove distances between objects
/** \defgroup hwlocality_distances_add Add distances between objects
*
* The usual way to add distances is:
* \code
* hwloc_distances_add_handle_t handle;
* int err = -1;
* handle = hwloc_distances_add_create(topology, "name", kind, 0);
* if (handle) {
* err = hwloc_distances_add_values(topology, handle, nbobjs, objs, values, 0);
* if (!err)
* err = hwloc_distances_add_commit(topology, handle, flags);
* }
* \endcode
* If \p err is \c 0 at the end, then addition was successful.
*
* @{
*/
/** \brief Handle to a new distances structure during its addition to the topology. */
typedef void * hwloc_distances_add_handle_t;
/** \brief Create a new empty distances structure.
*
* Create an empty distances structure
* to be filled with hwloc_distances_add_values()
* and then committed with hwloc_distances_add_commit().
*
* Parameter \p name is optional, it may be \c NULL.
* Otherwise, it will be copied internally and may later be freed by the caller.
*
* \p kind specifies the kind of distance as a OR'ed set of ::hwloc_distances_kind_e.
* Kind ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES will be automatically set
* according to objects having different types in hwloc_distances_add_values().
*
* \p flags must be \c 0 for now.
*
* \return A hwloc_distances_add_handle_t that should then be passed
* to hwloc_distances_add_values() and hwloc_distances_add_commit().
*
* \return \c NULL on error.
*/
HWLOC_DECLSPEC hwloc_distances_add_handle_t
hwloc_distances_add_create(hwloc_topology_t topology,
const char *name, unsigned long kind,
unsigned long flags);
/** \brief Specify the objects and values in a new empty distances structure.
*
* Specify the objects and values for a new distances structure
* that was returned as a handle by hwloc_distances_add_create().
* The structure must then be committed with hwloc_distances_add_commit().
*
* The number of objects is \p nbobjs and the array of objects is \p objs.
* Distance values are stored as a one-dimension array in \p values.
* The distance from object i to object j is in slot i*nbobjs+j.
*
* \p nbobjs must be at least 2.
*
* Arrays \p objs and \p values will be copied internally,
* they may later be freed by the caller.
*
* On error, the temporary distances structure and its content are destroyed.
*
* \p flags must be \c 0 for now.
*
* \return \c 0 on success.
* \return \c -1 on error.
*/
HWLOC_DECLSPEC int hwloc_distances_add_values(hwloc_topology_t topology,
hwloc_distances_add_handle_t handle,
unsigned nbobjs, hwloc_obj_t *objs,
hwloc_uint64_t *values,
unsigned long flags);
/** \brief Flags for adding a new distances to a topology. */
enum hwloc_distances_add_flag_e {
/** \brief Try to group objects based on the newly provided distance information.
* This is ignored for distances between objects of different types.
* \hideinitializer
*/
HWLOC_DISTANCES_ADD_FLAG_GROUP = (1UL<<0),
@ -233,23 +396,33 @@ enum hwloc_distances_add_flag_e {
HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE = (1UL<<1)
};
/** \brief Provide a new distance matrix.
/** \brief Commit a new distances structure.
*
* Provide the matrix of distances between a set of objects given by \p nbobjs
* and the \p objs array. \p nbobjs must be at least 2.
* The distances are stored as a one-dimension array in \p values.
* The distance from object i to object j is in slot i*nbobjs+j.
* This function finalizes the distances structure and inserts in it the topology.
*
* \p kind specifies the kind of distance as a OR'ed set of ::hwloc_distances_kind_e.
* Kind ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES will be automatically added
* if objects of different types are given.
* Parameter \p handle was previously returned by hwloc_distances_add_create().
* Then objects and values were specified with hwloc_distances_add_values().
*
* \p flags configures the behavior of the function using an optional OR'ed set of
* ::hwloc_distances_add_flag_e.
* It may be used to request the grouping of existing objects based on distances.
*
* On error, the temporary distances structure and its content are destroyed.
*
* \return \c 0 on success.
* \return \c -1 on error.
*/
HWLOC_DECLSPEC int hwloc_distances_add_commit(hwloc_topology_t topology,
hwloc_distances_add_handle_t handle,
unsigned long flags);
/** @} */
/** \defgroup hwlocality_distances_remove Remove distances between objects
* @{
*/
HWLOC_DECLSPEC int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
unsigned long kind, unsigned long flags);
/** \brief Remove all distance matrices from a topology.
*

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2012 Blue Brain Project, EPFL. All rights reserved.
* Copyright © 2012-2013 Inria. All rights reserved.
* Copyright © 2012-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -39,9 +39,9 @@ extern "C" {
/** \brief Get the hwloc OS device object corresponding to the
* OpenGL display given by port and device index.
*
* Return the OS device object describing the OpenGL display
* \return The hwloc OS device object describing the OpenGL display
* whose port (server) is \p port and device (screen) is \p device.
* Return NULL if there is none.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.
@ -70,9 +70,9 @@ hwloc_gl_get_display_osdev_by_port_device(hwloc_topology_t topology,
/** \brief Get the hwloc OS device object corresponding to the
* OpenGL display given by name.
*
* Return the OS device object describing the OpenGL display
* \return The hwloc OS device object describing the OpenGL display
* whose name is \p name, built as ":port.device" such as ":0.0" .
* Return NULL if there is none.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.
@ -99,9 +99,10 @@ hwloc_gl_get_display_osdev_by_name(hwloc_topology_t topology,
/** \brief Get the OpenGL display port and device corresponding
* to the given hwloc OS object.
*
* Return the OpenGL display port (server) in \p port and device (screen)
* Retrieves the OpenGL display port (server) in \p port and device (screen)
* in \p screen that correspond to the given hwloc OS device object.
* Return \c -1 if there is none.
*
* \return \c -1 if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012 Université Bordeaux
* Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -807,6 +807,49 @@ hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_
return obj;
}
/** \brief Return an object of a different type with same locality.
*
* If the source object \p src is a normal or memory type,
* this function returns an object of type \p type with same
* CPU and node sets, either below or above in the hierarchy.
*
* If the source object \p src is a PCI or an OS device within a PCI
* device, the function may either return that PCI device, or another
* OS device in the same PCI parent.
* This may for instance be useful for converting between OS devices
* such as "nvml0" or "rsmi1" used in distance structures into the
* the PCI device, or the CUDA or OpenCL OS device that correspond
* to the same physical card.
*
* If not \c NULL, parameter \p subtype only select objects whose
* subtype attribute exists and is \p subtype (case-insensitively),
* for instance "OpenCL" or "CUDA".
*
* If not \c NULL, parameter \p nameprefix only selects objects whose
* name attribute exists and starts with \p nameprefix (case-insensitively),
* for instance "rsmi" for matching "rsmi0".
*
* If multiple objects match, the first one is returned.
*
* This function will not walk the hierarchy across bridges since
* the PCI locality may become different.
* This function cannot also convert between normal/memory objects
* and I/O or Misc objects.
*
* \p flags must be \c 0 for now.
*
* \return An object with identical locality,
* matching \p subtype and \p nameprefix if any.
*
* \return \c NULL if no matching object could be found,
* or if the source object and target type are incompatible,
* for instance if converting between CPU and I/O objects.
*/
HWLOC_DECLSPEC hwloc_obj_t
hwloc_get_obj_with_same_locality(hwloc_topology_t topology, hwloc_obj_t src,
hwloc_obj_type_t type, const char *subtype, const char *nameprefix,
unsigned long flags);
/** @} */

View file

@ -0,0 +1,157 @@
/*
* Copyright © 2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
/** \file
* \brief Macros to help interaction between hwloc and the oneAPI Level Zero interface.
*
* Applications that use both hwloc and Level Zero may want to
* include this file so as to get topology information for L0 devices.
*/
#ifndef HWLOC_LEVELZERO_H
#define HWLOC_LEVELZERO_H
#include "hwloc.h"
#include "hwloc/autogen/config.h"
#include "hwloc/helper.h"
#ifdef HWLOC_LINUX_SYS
#include "hwloc/linux.h"
#endif
#include <level_zero/ze_api.h>
#include <level_zero/zes_api.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup hwlocality_levelzero Interoperability with the oneAPI Level Zero interface.
*
* This interface offers ways to retrieve topology information about
* devices managed by the Level Zero API.
*
* @{
*/
/** \brief Get the CPU set of logical processors that are physically
* close to the Level Zero device \p device
*
* Store in \p set the CPU-set describing the locality of
* the Level Zero device \p device.
*
* Topology \p topology and device \p device must match the local machine.
* The Level Zero must have been initialized with Sysman enabled
* (ZES_ENABLE_SYSMAN=1 in the environment).
* I/O devices detection and the Level Zero component are not needed in the
* topology.
*
* The function only returns the locality of the device.
* If more information about the device is needed, OS objects should
* be used instead, see hwloc_levelzero_get_device_osdev().
*
* This function is currently only implemented in a meaningful way for
* Linux; other systems will simply get a full cpuset.
*/
static __hwloc_inline int
hwloc_levelzero_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
ze_device_handle_t device, hwloc_cpuset_t set)
{
#ifdef HWLOC_LINUX_SYS
/* If we're on Linux, use the sysfs mechanism to get the local cpus */
#define HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX 128
char path[HWLOC_LEVELZERO_DEVICE_SYSFS_PATH_MAX];
zes_pci_properties_t pci;
zes_device_handle_t sdevice = device;
ze_result_t res;
if (!hwloc_topology_is_thissystem(topology)) {
errno = EINVAL;
return -1;
}
res = zesDevicePciGetProperties(sdevice, &pci);
if (res != ZE_RESULT_SUCCESS) {
errno = EINVAL;
return -1;
}
sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/local_cpus",
pci.address.domain, pci.address.bus, pci.address.device, pci.address.function);
if (hwloc_linux_read_path_as_cpumask(path, set) < 0
|| hwloc_bitmap_iszero(set))
hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
#else
/* Non-Linux systems simply get a full cpuset */
hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
#endif
return 0;
}
/** \brief Get the hwloc OS device object corresponding to Level Zero device
* \p device.
*
* \return The hwloc OS device object that describes the given Level Zero device \p device.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p dv_ind must match the local machine.
* I/O devices detection and the Level Zero component must be enabled in the
* topology. If not, the locality of the object may still be found using
* hwloc_levelzero_get_device_cpuset().
*
* \note The corresponding hwloc PCI device may be found by looking
* at the result parent pointer (unless PCI devices are filtered out).
*/
static __hwloc_inline hwloc_obj_t
hwloc_levelzero_get_device_osdev(hwloc_topology_t topology, ze_device_handle_t device)
{
zes_device_handle_t sdevice = device;
zes_pci_properties_t pci;
ze_result_t res;
hwloc_obj_t osdev;
if (!hwloc_topology_is_thissystem(topology)) {
errno = EINVAL;
return NULL;
}
res = zesDevicePciGetProperties(sdevice, &pci);
if (res != ZE_RESULT_SUCCESS) {
/* L0 was likely initialized without sysman, don't bother */
errno = EINVAL;
return NULL;
}
osdev = NULL;
while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
hwloc_obj_t pcidev = osdev->parent;
if (strncmp(osdev->name, "ze", 2))
continue;
if (pcidev
&& pcidev->type == HWLOC_OBJ_PCI_DEVICE
&& pcidev->attr->pcidev.domain == pci.address.domain
&& pcidev->attr->pcidev.bus == pci.address.bus
&& pcidev->attr->pcidev.dev == pci.address.device
&& pcidev->attr->pcidev.func == pci.address.function)
return osdev;
/* FIXME: when we'll have serialnumber, try it in case PCI is filtered-out */
}
return NULL;
}
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* HWLOC_LEVELZERO_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2012-2020 Inria. All rights reserved.
* Copyright © 2012-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -39,7 +39,7 @@ extern "C" {
/** \brief Get the CPU set of processors that are physically
* close to NVML device \p device.
*
* Return the CPU set describing the locality of the NVML device \p device.
* Store in \p set the CPU-set describing the locality of the NVML device \p device.
*
* Topology \p topology and device \p device must match the local machine.
* I/O devices detection and the NVML component are not needed in the topology.
@ -88,8 +88,8 @@ hwloc_nvml_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
/** \brief Get the hwloc OS device object corresponding to the
* NVML device whose index is \p idx.
*
* Return the OS device object describing the NVML device whose
* index is \p idx. Returns NULL if there is none.
* \return The hwloc OS device object describing the NVML device whose index is \p idx.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.
@ -114,8 +114,8 @@ hwloc_nvml_get_device_osdev_by_index(hwloc_topology_t topology, unsigned idx)
/** \brief Get the hwloc OS device object corresponding to NVML device \p device.
*
* Return the hwloc OS device object that describes the given
* NVML device \p device. Return NULL if there is none.
* \return The hwloc OS device object that describes the given NVML device \p device.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p device must match the local machine.
* I/O devices detection and the NVML component must be enabled in the topology.

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2012-2020 Inria. All rights reserved.
* Copyright © 2012-2021 Inria. All rights reserved.
* Copyright © 2013, 2018 Université Bordeaux. All right reserved.
* See COPYING in top-level directory.
*/
@ -82,9 +82,10 @@ hwloc_opencl_get_device_pci_busid(cl_device_id device,
if (CL_SUCCESS == clret
&& HWLOC_CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD == amdtopo.raw.type) {
*domain = 0; /* can't do anything better */
*bus = (unsigned) amdtopo.pcie.bus;
*dev = (unsigned) amdtopo.pcie.device;
*func = (unsigned) amdtopo.pcie.function;
/* cl_device_topology_amd stores bus ID in cl_char, dont convert those signed char directly to unsigned int */
*bus = (unsigned) (unsigned char) amdtopo.pcie.bus;
*dev = (unsigned) (unsigned char) amdtopo.pcie.device;
*func = (unsigned) (unsigned char) amdtopo.pcie.function;
return 0;
}
@ -112,7 +113,7 @@ hwloc_opencl_get_device_pci_busid(cl_device_id device,
/** \brief Get the CPU set of processors that are physically
* close to OpenCL device \p device.
*
* Return the CPU set describing the locality of the OpenCL device \p device.
* Store in \p set the CPU-set describing the locality of the OpenCL device \p device.
*
* Topology \p topology and device \p device must match the local machine.
* I/O devices detection and the OpenCL component are not needed in the topology.
@ -161,10 +162,10 @@ hwloc_opencl_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unuse
/** \brief Get the hwloc OS device object corresponding to the
* OpenCL device for the given indexes.
*
* Return the OS device object describing the OpenCL device
* \return The hwloc OS device object describing the OpenCL device
* whose platform index is \p platform_index,
* and whose device index within this platform if \p device_index.
* Return NULL if there is none.
* \return \c NULL if there is none.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.
@ -191,8 +192,9 @@ hwloc_opencl_get_device_osdev_by_index(hwloc_topology_t topology,
/** \brief Get the hwloc OS device object corresponding to OpenCL device \p deviceX.
*
* Use OpenCL device attributes to find the corresponding hwloc OS device object.
* Return NULL if there is none or if useful attributes are not available.
* \return The hwloc OS device object corresponding to the given OpenCL device \p device.
* \return \c NULL if none could be found, for instance
* if required OpenCL attributes are not available.
*
* This function currently only works on AMD and NVIDIA OpenCL devices that support
* relevant OpenCL extensions. hwloc_opencl_get_device_osdev_by_index()

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2010 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -44,7 +44,7 @@ extern "C" {
/** \brief Get the CPU set of processors that are physically
* close to device \p ibdev.
*
* Return the CPU set describing the locality of the OpenFabrics
* Store in \p set the CPU-set describing the locality of the OpenFabrics
* device \p ibdev (InfiniBand, etc).
*
* Topology \p topology and device \p ibdev must match the local machine.
@ -88,10 +88,11 @@ hwloc_ibv_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
/** \brief Get the hwloc OS device object corresponding to the OpenFabrics
* device named \p ibname.
*
* Return the OS device object describing the OpenFabrics device
* \return The hwloc OS device object describing the OpenFabrics device
* (InfiniBand, Omni-Path, usNIC, etc) whose name is \p ibname
* (mlx5_0, hfi1_0, usnic_0, qib0, etc).
* Returns NULL if there is none.
* \return \c NULL if none could be found.
*
* The name \p ibname is usually obtained from ibv_get_device_name().
*
* The topology \p topology does not necessarily have to match the current
@ -117,8 +118,9 @@ hwloc_ibv_get_device_osdev_by_name(hwloc_topology_t topology,
/** \brief Get the hwloc OS device object corresponding to the OpenFabrics
* device \p ibdev.
*
* Return the OS device object describing the OpenFabrics device \p ibdev
* (InfiniBand, etc). Returns NULL if there is none.
* \return The hwloc OS device object describing the OpenFabrics
* device \p ibdev (InfiniBand, etc).
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p ibdev must match the local machine.
* I/O devices detection must be enabled in the topology.

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2013-2020 Inria. All rights reserved.
* Copyright © 2013-2021 Inria. All rights reserved.
* Copyright © 2016 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
*/
@ -27,6 +27,9 @@ struct hwloc_backend;
/** \defgroup hwlocality_disc_components Components and Plugins: Discovery components
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
@ -93,6 +96,9 @@ struct hwloc_disc_component {
/** \defgroup hwlocality_disc_backends Components and Plugins: Discovery backends
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
@ -241,6 +247,9 @@ HWLOC_DECLSPEC int hwloc_backend_enable(struct hwloc_backend *backend);
/** \defgroup hwlocality_generic_components Components and Plugins: Generic components
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
@ -310,10 +319,26 @@ struct hwloc_component {
/** \defgroup hwlocality_components_core_funcs Components and Plugins: Core functions to be used by components
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
/** \brief Check whether insertion errors are hidden */
/** \brief Check whether error messages are hidden.
*
* Callers should print critical error messages
* (e.g. invalid hw topo info, invalid config)
* only if this function returns strictly less than 2.
*
* Callers should print non-critical error messages
* (e.g. failure to initialize CUDA)
* if this function returns 0.
*
* This function return 1 by default (show critical only),
* 0 in lstopo (show all),
* or anything set in HWLOC_HIDE_ERRORS in the environment.
*/
HWLOC_DECLSPEC int hwloc_hide_errors(void);
/** \brief Add an object to the topology.
@ -455,6 +480,9 @@ hwloc_plugin_check_namespace(const char *pluginname __hwloc_attribute_unused, co
/** \defgroup hwlocality_components_filtering Components and Plugins: Filtering objects
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
@ -472,6 +500,7 @@ hwloc_filter_check_pcidev_subtype_important(unsigned classid)
|| baseclass == 0x0b /* PCI_BASE_CLASS_PROCESSOR */
|| classid == 0x0c04 /* PCI_CLASS_SERIAL_FIBER */
|| classid == 0x0c06 /* PCI_CLASS_SERIAL_INFINIBAND */
|| baseclass == 0x06 /* PCI_BASE_CLASS_BRIDGE with non-PCI downstream. the core will drop the useless ones later */
|| baseclass == 0x12 /* Processing Accelerators */);
}
@ -527,6 +556,9 @@ hwloc_filter_check_keep_object(hwloc_topology_t topology, hwloc_obj_t obj)
/** \defgroup hwlocality_components_pcidisc Components and Plugins: helpers for PCI discovery
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
@ -578,18 +610,76 @@ HWLOC_DECLSPEC int hwloc_pcidisc_tree_attach(struct hwloc_topology *topology, st
/** \defgroup hwlocality_components_pcifind Components and Plugins: finding PCI objects during other discoveries
*
* \note These structures and functions may change when ::HWLOC_COMPONENT_ABI is modified.
*
* @{
*/
/** \brief Find the normal parent of a PCI bus ID.
/** \brief Find the object or a parent of a PCI bus ID.
*
* Look at PCI affinity to find out where the given PCI bus ID should be attached.
* When attaching a new object (typically an OS device) whose locality
* is specified by PCI bus ID, this function returns the PCI object
* to use as a parent for attaching.
*
* This function should be used to attach an I/O device under the corresponding
* PCI object (if any), or under a normal (non-I/O) object with same locality.
* If the exact PCI device with this bus ID exists, it is returned.
* Otherwise (for instance if it was filtered out), the function returns
* another object with similar locality (for instance a parent bridge,
* or the local CPU Package).
*/
HWLOC_DECLSPEC struct hwloc_obj * hwloc_pci_find_parent_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func);
/** \brief Find the PCI device or bridge matching a PCI bus ID exactly.
*
* This is useful for adding specific information about some objects
* based on their PCI id. When it comes to attaching objects based on
* PCI locality, hwloc_pci_find_parent_by_busid() should be preferred.
*/
HWLOC_DECLSPEC struct hwloc_obj * hwloc_pci_find_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func);
/** \brief Handle to a new distances structure during its addition to the topology. */
typedef void * hwloc_backend_distances_add_handle_t;
/** \brief Create a new empty distances structure.
*
* This is identical to hwloc_distances_add_create()
* but this variant is designed for backend inserting
* distances during topology discovery.
*/
HWLOC_DECLSPEC hwloc_backend_distances_add_handle_t
hwloc_backend_distances_add_create(hwloc_topology_t topology,
const char *name, unsigned long kind,
unsigned long flags);
/** \brief Specify the objects and values in a new empty distances structure.
*
* This is similar to hwloc_distances_add_values()
* but this variant is designed for backend inserting
* distances during topology discovery.
*
* The only semantical difference is that \p objs and \p values
* are not duplicated, but directly attached to the topology.
* On success, these arrays are given to the core and should not
* ever be freed by the caller anymore.
*/
HWLOC_DECLSPEC int
hwloc_backend_distances_add_values(hwloc_topology_t topology,
hwloc_backend_distances_add_handle_t handle,
unsigned nbobjs, hwloc_obj_t *objs,
hwloc_uint64_t *values,
unsigned long flags);
/** \brief Commit a new distances structure.
*
* This is similar to hwloc_distances_add_commit()
* but this variant is designed for backend inserting
* distances during topology discovery.
*/
HWLOC_DECLSPEC int
hwloc_backend_distances_add_commit(hwloc_topology_t topology,
hwloc_backend_distances_add_handle_t handle,
unsigned long flags);
/** @} */

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -120,6 +120,9 @@ extern "C" {
#define HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IS_THISSYSTEM)
#define HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES HWLOC_NAME_CAPS(TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES)
#define HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IMPORT_SUPPORT)
#define HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING)
#define HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING)
#define HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING HWLOC_NAME_CAPS(TOPOLOGY_FLAG_DONT_CHANGE_BINDING)
#define hwloc_topology_set_pid HWLOC_NAME(topology_set_pid)
#define hwloc_topology_set_synthetic HWLOC_NAME(topology_set_synthetic)
@ -356,6 +359,7 @@ extern "C" {
#define hwloc_get_closest_objs HWLOC_NAME(get_closest_objs)
#define hwloc_get_obj_below_by_type HWLOC_NAME(get_obj_below_by_type)
#define hwloc_get_obj_below_array_by_type HWLOC_NAME(get_obj_below_array_by_type)
#define hwloc_get_obj_with_same_locality HWLOC_NAME(get_obj_with_same_locality)
#define hwloc_distrib_flags_e HWLOC_NAME(distrib_flags_e)
#define HWLOC_DISTRIB_FLAG_REVERSE HWLOC_NAME_CAPS(DISTRIB_FLAG_REVERSE)
#define hwloc_distrib HWLOC_NAME(distrib)
@ -454,11 +458,22 @@ extern "C" {
#define hwloc_distances_obj_index HWLOC_NAME(distances_obj_index)
#define hwloc_distances_obj_pair_values HWLOC_NAME(distances_pair_values)
#define hwloc_distances_transform_e HWLOC_NAME(distances_transform_e)
#define HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_REMOVE_NULL)
#define HWLOC_DISTANCES_TRANSFORM_LINKS HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_LINKS)
#define HWLOC_DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS)
#define HWLOC_DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE HWLOC_NAME_CAPS(DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE)
#define hwloc_distances_transform HWLOC_NAME(distances_transform)
#define hwloc_distances_add_flag_e HWLOC_NAME(distances_add_flag_e)
#define HWLOC_DISTANCES_ADD_FLAG_GROUP HWLOC_NAME_CAPS(DISTANCES_ADD_FLAG_GROUP)
#define HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE HWLOC_NAME_CAPS(DISTANCES_ADD_FLAG_GROUP_INACCURATE)
#define hwloc_distances_add HWLOC_NAME(distances_add)
#define hwloc_distances_add_handle_t HWLOC_NAME(distances_add_handle_t)
#define hwloc_distances_add_create HWLOC_NAME(distances_add_create)
#define hwloc_distances_add_values HWLOC_NAME(distances_add_values)
#define hwloc_distances_add_commit HWLOC_NAME(distances_add_commit)
#define hwloc_distances_remove HWLOC_NAME(distances_remove)
#define hwloc_distances_remove_by_depth HWLOC_NAME(distances_remove_by_depth)
#define hwloc_distances_remove_by_type HWLOC_NAME(distances_remove_by_type)
@ -523,6 +538,11 @@ extern "C" {
#define hwloc_linux_get_tid_last_cpu_location HWLOC_NAME(linux_get_tid_last_cpu_location)
#define hwloc_linux_read_path_as_cpumask HWLOC_NAME(linux_read_file_cpumask)
/* windows.h */
#define hwloc_windows_get_nr_processor_groups HWLOC_NAME(windows_get_nr_processor_groups)
#define hwloc_windows_get_processor_group_cpuset HWLOC_NAME(windows_get_processor_group_cpuset)
/* openfabrics-verbs.h */
#define hwloc_ibv_get_device_cpuset HWLOC_NAME(ibv_get_device_cpuset)
@ -564,6 +584,11 @@ extern "C" {
#define hwloc_rsmi_get_device_osdev HWLOC_NAME(rsmi_get_device_osdev)
#define hwloc_rsmi_get_device_osdev_by_index HWLOC_NAME(rsmi_get_device_osdev_by_index)
/* levelzero.h */
#define hwloc_levelzero_get_device_cpuset HWLOC_NAME(levelzero_get_device_cpuset)
#define hwloc_levelzero_get_device_osdev HWLOC_NAME(levelzero_get_device_osdev)
/* gl.h */
#define hwloc_gl_get_display_osdev_by_port_device HWLOC_NAME(gl_get_display_osdev_by_port_device)
@ -620,10 +645,18 @@ extern "C" {
#define hwloc_pcidisc_tree_insert_by_busid HWLOC_NAME(pcidisc_tree_insert_by_busid)
#define hwloc_pcidisc_tree_attach HWLOC_NAME(pcidisc_tree_attach)
#define hwloc_pci_find_by_busid HWLOC_NAME(pcidisc_find_by_busid)
#define hwloc_pci_find_parent_by_busid HWLOC_NAME(pcidisc_find_busid_parent)
#define hwloc_backend_distances_add_handle_t HWLOC_NAME(backend_distances_add_handle_t)
#define hwloc_backend_distances_add_create HWLOC_NAME(backend_distances_add_create)
#define hwloc_backend_distances_add_values HWLOC_NAME(backend_distances_add_values)
#define hwloc_backend_distances_add_commit HWLOC_NAME(backend_distances_add_commit)
/* hwloc/deprecated.h */
#define hwloc_distances_add HWLOC_NAME(distances_add)
#define hwloc_topology_insert_misc_object_by_parent HWLOC_NAME(topology_insert_misc_object_by_parent)
#define hwloc_obj_cpuset_snprintf HWLOC_NAME(obj_cpuset_snprintf)
#define hwloc_obj_type_sscanf HWLOC_NAME(obj_type_sscanf)
@ -733,6 +766,7 @@ extern "C" {
#define hwloc_cuda_component HWLOC_NAME(cuda_component)
#define hwloc_gl_component HWLOC_NAME(gl_component)
#define hwloc_levelzero_component HWLOC_NAME(levelzero_component)
#define hwloc_nvml_component HWLOC_NAME(nvml_component)
#define hwloc_rsmi_component HWLOC_NAME(rsmi_component)
#define hwloc_opencl_component HWLOC_NAME(opencl_component)
@ -772,7 +806,6 @@ extern "C" {
#define hwloc_pci_discovery_init HWLOC_NAME(pci_discovery_init)
#define hwloc_pci_discovery_prepare HWLOC_NAME(pci_discovery_prepare)
#define hwloc_pci_discovery_exit HWLOC_NAME(pci_discovery_exit)
#define hwloc_pci_find_by_busid HWLOC_NAME(pcidisc_find_by_busid)
#define hwloc_find_insert_io_parent_by_complete_cpuset HWLOC_NAME(hwloc_find_insert_io_parent_by_complete_cpuset)
#define hwloc__add_info HWLOC_NAME(_add_info)
@ -816,7 +849,6 @@ extern "C" {
#define hwloc_internal_distances_dup HWLOC_NAME(internal_distances_dup)
#define hwloc_internal_distances_refresh HWLOC_NAME(internal_distances_refresh)
#define hwloc_internal_distances_destroy HWLOC_NAME(internal_distances_destroy)
#define hwloc_internal_distances_add HWLOC_NAME(internal_distances_add)
#define hwloc_internal_distances_add_by_index HWLOC_NAME(internal_distances_add_by_index)
#define hwloc_internal_distances_invalidate_cached_objs HWLOC_NAME(hwloc_internal_distances_invalidate_cached_objs)

203
src/3rdparty/hwloc/include/hwloc/rsmi.h vendored Normal file
View file

@ -0,0 +1,203 @@
/*
* Copyright © 2012-2021 Inria. All rights reserved.
* Copyright (c) 2020, Advanced Micro Devices, Inc. All rights reserved.
* Written by Advanced Micro Devices,
* See COPYING in top-level directory.
*/
/** \file
* \brief Macros to help interaction between hwloc and the ROCm SMI Management Library.
*
* Applications that use both hwloc and the ROCm SMI Management Library may want to
* include this file so as to get topology information for AMD GPU devices.
*/
#ifndef HWLOC_RSMI_H
#define HWLOC_RSMI_H
#include "hwloc.h"
#include "hwloc/autogen/config.h"
#include "hwloc/helper.h"
#ifdef HWLOC_LINUX_SYS
#include "hwloc/linux.h"
#endif
#include <rocm_smi/rocm_smi.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup hwlocality_rsmi Interoperability with the ROCm SMI Management Library
*
* This interface offers ways to retrieve topology information about
* devices managed by the ROCm SMI Management Library.
*
* @{
*/
/** \brief Get the CPU set of logical processors that are physically
* close to AMD GPU device whose index is \p dv_ind.
*
* Store in \p set the CPU-set describing the locality of the AMD GPU device
* whose index is \p dv_ind.
*
* Topology \p topology and device \p dv_ind must match the local machine.
* I/O devices detection and the ROCm SMI component are not needed in the
* topology.
*
* The function only returns the locality of the device.
* If more information about the device is needed, OS objects should
* be used instead, see hwloc_rsmi_get_device_osdev()
* and hwloc_rsmi_get_device_osdev_by_index().
*
* This function is currently only implemented in a meaningful way for
* Linux; other systems will simply get a full cpuset.
*/
static __hwloc_inline int
hwloc_rsmi_get_device_cpuset(hwloc_topology_t topology __hwloc_attribute_unused,
uint32_t dv_ind, hwloc_cpuset_t set)
{
#ifdef HWLOC_LINUX_SYS
/* If we're on Linux, use the sysfs mechanism to get the local cpus */
#define HWLOC_RSMI_DEVICE_SYSFS_PATH_MAX 128
char path[HWLOC_RSMI_DEVICE_SYSFS_PATH_MAX];
rsmi_status_t ret;
uint64_t bdfid = 0;
unsigned domain, device, bus;
if (!hwloc_topology_is_thissystem(topology)) {
errno = EINVAL;
return -1;
}
ret = rsmi_dev_pci_id_get(dv_ind, &bdfid);
if (RSMI_STATUS_SUCCESS != ret) {
errno = EINVAL;
return -1;
}
domain = (bdfid>>32) & 0xffffffff;
bus = ((bdfid & 0xffff)>>8) & 0xff;
device = ((bdfid & 0xff)>>3) & 0x1f;
sprintf(path, "/sys/bus/pci/devices/%04x:%02x:%02x.0/local_cpus", domain, bus, device);
if (hwloc_linux_read_path_as_cpumask(path, set) < 0
|| hwloc_bitmap_iszero(set))
hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
#else
/* Non-Linux systems simply get a full cpuset */
hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology));
#endif
return 0;
}
/** \brief Get the hwloc OS device object corresponding to the
* AMD GPU device whose index is \p dv_ind.
*
* \return The hwloc OS device object describing the AMD GPU device whose
* index is \p dv_ind.
* \return \c NULL if none could be found.
*
* The topology \p topology does not necessarily have to match the current
* machine. For instance the topology may be an XML import of a remote host.
* I/O devices detection and the ROCm SMI component must be enabled in the
* topology.
*
* \note The corresponding PCI device object can be obtained by looking
* at the OS device parent object (unless PCI devices are filtered out).
*/
static __hwloc_inline hwloc_obj_t
hwloc_rsmi_get_device_osdev_by_index(hwloc_topology_t topology, uint32_t dv_ind)
{
hwloc_obj_t osdev = NULL;
while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
if (HWLOC_OBJ_OSDEV_GPU == osdev->attr->osdev.type
&& osdev->name
&& !strncmp("rsmi", osdev->name, 4)
&& atoi(osdev->name + 4) == (int) dv_ind)
return osdev;
}
return NULL;
}
/** \brief Get the hwloc OS device object corresponding to AMD GPU device,
* whose index is \p dv_ind.
*
* \return The hwloc OS device object that describes the given
* AMD GPU, whose index is \p dv_ind.
* \return \c NULL if none could be found.
*
* Topology \p topology and device \p dv_ind must match the local machine.
* I/O devices detection and the ROCm SMI component must be enabled in the
* topology. If not, the locality of the object may still be found using
* hwloc_rsmi_get_device_cpuset().
*
* \note The corresponding hwloc PCI device may be found by looking
* at the result parent pointer (unless PCI devices are filtered out).
*/
static __hwloc_inline hwloc_obj_t
hwloc_rsmi_get_device_osdev(hwloc_topology_t topology, uint32_t dv_ind)
{
hwloc_obj_t osdev;
rsmi_status_t ret;
uint64_t bdfid = 0;
unsigned domain, device, bus, func;
uint64_t id;
char uuid[64];
if (!hwloc_topology_is_thissystem(topology)) {
errno = EINVAL;
return NULL;
}
ret = rsmi_dev_pci_id_get(dv_ind, &bdfid);
if (RSMI_STATUS_SUCCESS != ret) {
errno = EINVAL;
return NULL;
}
domain = (bdfid>>32) & 0xffffffff;
bus = ((bdfid & 0xffff)>>8) & 0xff;
device = ((bdfid & 0xff)>>3) & 0x1f;
func = bdfid & 0x7;
ret = rsmi_dev_unique_id_get(dv_ind, &id);
if (RSMI_STATUS_SUCCESS != ret)
uuid[0] = '\0';
else
sprintf(uuid, "%lx", id);
osdev = NULL;
while ((osdev = hwloc_get_next_osdev(topology, osdev)) != NULL) {
hwloc_obj_t pcidev = osdev->parent;
const char *info;
if (strncmp(osdev->name, "rsmi", 4))
continue;
if (pcidev
&& pcidev->type == HWLOC_OBJ_PCI_DEVICE
&& pcidev->attr->pcidev.domain == domain
&& pcidev->attr->pcidev.bus == bus
&& pcidev->attr->pcidev.dev == device
&& pcidev->attr->pcidev.func == func)
return osdev;
info = hwloc_obj_get_info_by_name(osdev, "AMDUUID");
if (info && !strcmp(info, uuid))
return osdev;
}
return NULL;
}
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* HWLOC_RSMI_H */

View file

@ -0,0 +1,76 @@
/*
* Copyright © 2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
/** \file
* \brief Macros to help interaction between hwloc and Windows.
*
* Applications that use hwloc on Windows may want to include this file
* for Windows specific hwloc features.
*/
#ifndef HWLOC_WINDOWS_H
#define HWLOC_WINDOWS_H
#include "hwloc.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup hwlocality_windows Windows-specific helpers
*
* These functions query Windows processor groups.
* These groups partition the operating system into virtual sets
* of up to 64 neighbor PUs.
* Threads and processes may only be bound inside a single group.
* Although Windows processor groups may be exposed in the hwloc
* hierarchy as hwloc Groups, they are also often merged into
* existing hwloc objects such as NUMA nodes or Packages.
* This API provides explicit information about Windows processor
* groups so that applications know whether binding to a large
* set of PUs may fail because it spans over multiple Windows
* processor groups.
*
* @{
*/
/** \brief Get the number of Windows processor groups
*
* \p flags must be 0 for now.
*
* \return at least \c 1 on success.
* \return -1 on error, for instance if the topology does not match
* the current system (e.g. loaded from another machine through XML).
*/
HWLOC_DECLSPEC int hwloc_windows_get_nr_processor_groups(hwloc_topology_t topology, unsigned long flags);
/** \brief Get the CPU-set of a Windows processor group.
*
* Get the set of PU included in the processor group specified
* by \p pg_index.
* \p pg_index must be between \c 0 and the value returned
* by hwloc_windows_get_nr_processor_groups() minus 1.
*
* \p flags must be 0 for now.
*
* \return \c 0 on success.
* \return \c -1 on error, for instance if \p pg_index is invalid,
* or if the topology does not match the current system (e.g. loaded
* from another machine through XML).
*/
HWLOC_DECLSPEC int hwloc_windows_get_processor_group_cpuset(hwloc_topology_t topology, unsigned pg_index, hwloc_cpuset_t cpuset, unsigned long flags);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* HWLOC_WINDOWS_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2018-2019 Inria. All rights reserved.
* Copyright © 2018-2020 Inria. All rights reserved.
*
* See COPYING in top-level directory.
*/
@ -31,6 +31,7 @@ HWLOC_DECLSPEC extern const struct hwloc_component hwloc_cuda_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_gl_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_nvml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_rsmi_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_levelzero_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_opencl_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_pci_component;

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
*
@ -166,6 +166,7 @@ struct hwloc_topology {
unsigned long kind;
#define HWLOC_INTERNAL_DIST_FLAG_OBJS_VALID (1U<<0) /* if the objs array is valid below */
#define HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED (1U<<1) /* if the distances isn't in the list yet */
unsigned iflags;
/* objects are currently stored in physical_index order */
@ -304,11 +305,6 @@ extern void hwloc_pci_discovery_init(struct hwloc_topology *topology);
extern void hwloc_pci_discovery_prepare(struct hwloc_topology *topology);
extern void hwloc_pci_discovery_exit(struct hwloc_topology *topology);
/* Look for an object matching the given domain/bus/func,
* either exactly or return the smallest container bridge
*/
extern struct hwloc_obj * hwloc_pci_find_by_busid(struct hwloc_topology *topology, unsigned domain, unsigned bus, unsigned dev, unsigned func);
/* Look for an object matching complete cpuset exactly, or insert one.
* Return NULL on failure.
* Return a good fallback (object above) on failure to insert.
@ -408,10 +404,14 @@ extern void hwloc_internal_distances_prepare(hwloc_topology_t topology);
extern void hwloc_internal_distances_destroy(hwloc_topology_t topology);
extern int hwloc_internal_distances_dup(hwloc_topology_t new, hwloc_topology_t old);
extern void hwloc_internal_distances_refresh(hwloc_topology_t topology);
extern int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name, unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values, unsigned long kind, unsigned long flags);
extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags);
extern void hwloc_internal_distances_invalidate_cached_objs(hwloc_topology_t topology);
/* these distances_add() functions are higher-level than those in hwloc/plugins.h
* but they may change in the future, hence they are not exported to plugins.
*/
extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags);
extern int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name, unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values, unsigned long kind, unsigned long flags);
extern void hwloc_internal_memattrs_init(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_prepare(hwloc_topology_t topology);
extern void hwloc_internal_memattrs_destroy(hwloc_topology_t topology);

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2012 Université Bordeaux
* See COPYING in top-level directory.
*/
@ -124,7 +124,7 @@ hwloc_dlforeachfile(const char *_paths,
*colon = '\0';
if (hwloc_plugins_verbose)
fprintf(stderr, " Looking under %s\n", path);
fprintf(stderr, "hwloc: Looking under %s\n", path);
dir = opendir(path);
if (!dir)
@ -198,7 +198,7 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
char *componentsymbolname;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin dlforeach found `%s'\n", filename);
fprintf(stderr, "hwloc: Plugin dlforeach found `%s'\n", filename);
basename = strrchr(filename, '/');
if (!basename)
@ -208,7 +208,7 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
if (hwloc_plugins_blacklist && strstr(hwloc_plugins_blacklist, basename)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin `%s' is blacklisted in the environment\n", basename);
fprintf(stderr, "hwloc: Plugin `%s' is blacklisted in the environment\n", basename);
goto out;
}
@ -216,14 +216,14 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
handle = hwloc_dlopenext(filename);
if (!handle) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to load plugin: %s\n", hwloc_dlerror());
fprintf(stderr, "hwloc: Failed to load plugin: %s\n", hwloc_dlerror());
goto out;
}
componentsymbolname = malloc(strlen(basename)+10+1);
if (!componentsymbolname) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to allocation component `%s' symbol\n",
fprintf(stderr, "hwloc: Failed to allocation component `%s' symbol\n",
basename);
goto out_with_handle;
}
@ -231,38 +231,38 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
component = hwloc_dlsym(handle, componentsymbolname);
if (!component) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to find component symbol `%s'\n",
fprintf(stderr, "hwloc: Failed to find component symbol `%s'\n",
componentsymbolname);
free(componentsymbolname);
goto out_with_handle;
}
if (component->abi != HWLOC_COMPONENT_ABI) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin symbol ABI %u instead of %d\n",
fprintf(stderr, "hwloc: Plugin symbol ABI %u instead of %d\n",
component->abi, HWLOC_COMPONENT_ABI);
free(componentsymbolname);
goto out_with_handle;
}
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin contains expected symbol `%s'\n",
fprintf(stderr, "hwloc: Plugin contains expected symbol `%s'\n",
componentsymbolname);
free(componentsymbolname);
if (HWLOC_COMPONENT_TYPE_DISC == component->type) {
if (strncmp(basename, "hwloc_", 6)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' doesn't match its type DISCOVERY\n", basename);
fprintf(stderr, "hwloc: Plugin name `%s' doesn't match its type DISCOVERY\n", basename);
goto out_with_handle;
}
} else if (HWLOC_COMPONENT_TYPE_XML == component->type) {
if (strncmp(basename, "hwloc_xml_", 10)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' doesn't match its type XML\n", basename);
fprintf(stderr, "hwloc: Plugin name `%s' doesn't match its type XML\n", basename);
goto out_with_handle;
}
} else {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' has invalid type %u\n",
fprintf(stderr, "hwloc: Plugin name `%s' has invalid type %u\n",
basename, (unsigned) component->type);
goto out_with_handle;
}
@ -277,7 +277,7 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
desc->handle = handle;
desc->next = NULL;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin descriptor `%s' ready\n", basename);
fprintf(stderr, "hwloc: Plugin descriptor `%s' ready\n", basename);
/* append to the list */
prevdesc = &hwloc_plugins;
@ -285,7 +285,7 @@ hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
prevdesc = &((*prevdesc)->next);
*prevdesc = desc;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin descriptor `%s' queued\n", basename);
fprintf(stderr, "hwloc: Plugin descriptor `%s' queued\n", basename);
return 0;
out_with_handle:
@ -300,7 +300,7 @@ hwloc_plugins_exit(void)
struct hwloc__plugin_desc *desc, *next;
if (hwloc_plugins_verbose)
fprintf(stderr, "Closing all plugins\n");
fprintf(stderr, "hwloc: Closing all plugins\n");
desc = hwloc_plugins;
while (desc) {
@ -340,7 +340,7 @@ hwloc_plugins_init(void)
hwloc_plugins = NULL;
if (hwloc_plugins_verbose)
fprintf(stderr, "Starting plugin dlforeach in %s\n", path);
fprintf(stderr, "hwloc: Starting plugin dlforeach in %s\n", path);
err = hwloc_dlforeachfile(path, hwloc__dlforeach_cb, NULL);
if (err)
goto out_with_init;
@ -364,14 +364,14 @@ hwloc_disc_component_register(struct hwloc_disc_component *component,
/* check that the component name is valid */
if (!strcmp(component->name, HWLOC_COMPONENT_STOP_NAME)) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot register discovery component with reserved name `" HWLOC_COMPONENT_STOP_NAME "'\n");
fprintf(stderr, "hwloc: Cannot register discovery component with reserved name `" HWLOC_COMPONENT_STOP_NAME "'\n");
return -1;
}
if (strchr(component->name, HWLOC_COMPONENT_EXCLUDE_CHAR)
|| strchr(component->name, HWLOC_COMPONENT_PHASESEP_CHAR)
|| strcspn(component->name, HWLOC_COMPONENT_SEPS) != strlen(component->name)) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot register discovery component with name `%s' containing reserved characters `%c" HWLOC_COMPONENT_SEPS "'\n",
fprintf(stderr, "hwloc: Cannot register discovery component with name `%s' containing reserved characters `%c" HWLOC_COMPONENT_SEPS "'\n",
component->name, HWLOC_COMPONENT_EXCLUDE_CHAR);
return -1;
}
@ -386,8 +386,9 @@ hwloc_disc_component_register(struct hwloc_disc_component *component,
|HWLOC_DISC_PHASE_MISC
|HWLOC_DISC_PHASE_ANNOTATE
|HWLOC_DISC_PHASE_TWEAK))) {
fprintf(stderr, "Cannot register discovery component `%s' with invalid phases 0x%x\n",
component->name, component->phases);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Cannot register discovery component `%s' with invalid phases 0x%x\n",
component->name, component->phases);
return -1;
}
@ -398,13 +399,13 @@ hwloc_disc_component_register(struct hwloc_disc_component *component,
if ((*prev)->priority < component->priority) {
/* drop the existing component */
if (hwloc_components_verbose)
fprintf(stderr, "Dropping previously registered discovery component `%s', priority %u lower than new one %u\n",
fprintf(stderr, "hwloc: Dropping previously registered discovery component `%s', priority %u lower than new one %u\n",
(*prev)->name, (*prev)->priority, component->priority);
*prev = (*prev)->next;
} else {
/* drop the new one */
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring new discovery component `%s', priority %u lower than previously registered one %u\n",
fprintf(stderr, "hwloc: Ignoring new discovery component `%s', priority %u lower than previously registered one %u\n",
component->name, component->priority, (*prev)->priority);
return -1;
}
@ -412,7 +413,7 @@ hwloc_disc_component_register(struct hwloc_disc_component *component,
prev = &((*prev)->next);
}
if (hwloc_components_verbose)
fprintf(stderr, "Registered discovery component `%s' phases 0x%x with priority %u (%s%s)\n",
fprintf(stderr, "hwloc: Registered discovery component `%s' phases 0x%x with priority %u (%s%s)\n",
component->name, component->phases, component->priority,
filename ? "from plugin " : "statically build", filename ? filename : "");
@ -475,15 +476,16 @@ hwloc_components_init(void)
/* hwloc_static_components is created by configure in static-components.h */
for(i=0; NULL != hwloc_static_components[i]; i++) {
if (hwloc_static_components[i]->flags) {
fprintf(stderr, "Ignoring static component with invalid flags %lx\n",
hwloc_static_components[i]->flags);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Ignoring static component with invalid flags %lx\n",
hwloc_static_components[i]->flags);
continue;
}
/* initialize the component */
if (hwloc_static_components[i]->init && hwloc_static_components[i]->init(0) < 0) {
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring static component, failed to initialize\n");
fprintf(stderr, "hwloc: Ignoring static component, failed to initialize\n");
continue;
}
/* queue ->finalize() callback if any */
@ -503,15 +505,16 @@ hwloc_components_init(void)
#ifdef HWLOC_HAVE_PLUGINS
for(desc = hwloc_plugins; NULL != desc; desc = desc->next) {
if (desc->component->flags) {
fprintf(stderr, "Ignoring plugin `%s' component with invalid flags %lx\n",
desc->name, desc->component->flags);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Ignoring plugin `%s' component with invalid flags %lx\n",
desc->name, desc->component->flags);
continue;
}
/* initialize the component */
if (desc->component->init && desc->component->init(0) < 0) {
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring plugin `%s', failed to initialize\n", desc->name);
fprintf(stderr, "hwloc: Ignoring plugin `%s', failed to initialize\n", desc->name);
continue;
}
/* queue ->finalize() callback if any */
@ -608,7 +611,7 @@ hwloc_disc_component_blacklist_one(struct hwloc_topology *topology,
/* replace linuxpci and linuxio with linux (with IO phases)
* for backward compatibility with pre-v2.0 and v2.0 respectively */
if (hwloc_components_verbose)
fprintf(stderr, "Replacing deprecated component `%s' with `linux' IO phases in blacklisting\n", name);
fprintf(stderr, "hwloc: Replacing deprecated component `%s' with `linux' IO phases in blacklisting\n", name);
comp = hwloc_disc_component_find("linux", NULL);
phases = HWLOC_DISC_PHASE_PCI | HWLOC_DISC_PHASE_IO | HWLOC_DISC_PHASE_MISC | HWLOC_DISC_PHASE_ANNOTATE;
@ -624,7 +627,7 @@ hwloc_disc_component_blacklist_one(struct hwloc_topology *topology,
}
if (hwloc_components_verbose)
fprintf(stderr, "Blacklisting component `%s` phases 0x%x\n", comp->name, phases);
fprintf(stderr, "hwloc: Blacklisting component `%s` phases 0x%x\n", comp->name, phases);
for(i=0; i<topology->nr_blacklisted_components; i++) {
if (topology->blacklisted_components[i].component == comp) {
@ -727,7 +730,7 @@ hwloc_disc_component_try_enable(struct hwloc_topology *topology,
if (hwloc_components_verbose)
/* do not warn if envvar_forced since system-wide HWLOC_COMPONENTS must be silently ignored after set_xml() etc.
*/
fprintf(stderr, "Excluding discovery component `%s' phases 0x%x, conflicts with excludes 0x%x\n",
fprintf(stderr, "hwloc: Excluding discovery component `%s' phases 0x%x, conflicts with excludes 0x%x\n",
comp->name, comp->phases, topology->backend_excluded_phases);
return -1;
}
@ -735,8 +738,8 @@ hwloc_disc_component_try_enable(struct hwloc_topology *topology,
backend = comp->instantiate(topology, comp, topology->backend_excluded_phases | blacklisted_phases,
NULL, NULL, NULL);
if (!backend) {
if (hwloc_components_verbose || envvar_forced)
fprintf(stderr, "Failed to instantiate discovery component `%s'\n", comp->name);
if (hwloc_components_verbose || (envvar_forced && hwloc_hide_errors() < 2))
fprintf(stderr, "hwloc: Failed to instantiate discovery component `%s'\n", comp->name);
return -1;
}
@ -817,7 +820,7 @@ hwloc_disc_components_enable_others(struct hwloc_topology *topology)
name = curenv;
if (!strcmp(name, "linuxpci") || !strcmp(name, "linuxio")) {
if (hwloc_components_verbose)
fprintf(stderr, "Replacing deprecated component `%s' with `linux' in envvar forcing\n", name);
fprintf(stderr, "hwloc: Replacing deprecated component `%s' with `linux' in envvar forcing\n", name);
name = "linux";
}
@ -832,7 +835,8 @@ hwloc_disc_components_enable_others(struct hwloc_topology *topology)
if (comp->phases & ~blacklisted_phases)
hwloc_disc_component_try_enable(topology, comp, 1 /* envvar forced */, blacklisted_phases);
} else {
fprintf(stderr, "Cannot find discovery component `%s'\n", name);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Cannot find discovery component `%s'\n", name);
}
/* restore chars (the second loop below needs env to be unmodified) */
@ -864,7 +868,7 @@ hwloc_disc_components_enable_others(struct hwloc_topology *topology)
if (!(comp->phases & ~blacklisted_phases)) {
if (hwloc_components_verbose)
fprintf(stderr, "Excluding blacklisted discovery component `%s' phases 0x%x\n",
fprintf(stderr, "hwloc: Excluding blacklisted discovery component `%s' phases 0x%x\n",
comp->name, comp->phases);
goto nextcomp;
}
@ -879,7 +883,7 @@ nextcomp:
/* print a summary */
int first = 1;
backend = topology->backends;
fprintf(stderr, "Final list of enabled discovery components: ");
fprintf(stderr, "hwloc: Final list of enabled discovery components: ");
while (backend != NULL) {
fprintf(stderr, "%s%s(0x%x)", first ? "" : ",", backend->component->name, backend->phases);
backend = backend->next;
@ -935,7 +939,7 @@ hwloc_backend_alloc(struct hwloc_topology *topology,
/* filter-out component phases that are excluded */
backend->phases = component->phases & ~topology->backend_excluded_phases;
if (backend->phases != component->phases && hwloc_components_verbose)
fprintf(stderr, "Trying discovery component `%s' with phases 0x%x instead of 0x%x\n",
fprintf(stderr, "hwloc: Trying discovery component `%s' with phases 0x%x instead of 0x%x\n",
component->name, backend->phases, component->phases);
backend->flags = 0;
backend->discover = NULL;
@ -963,8 +967,9 @@ hwloc_backend_enable(struct hwloc_backend *backend)
/* check backend flags */
if (backend->flags) {
fprintf(stderr, "Cannot enable discovery component `%s' phases 0x%x with unknown flags %lx\n",
backend->component->name, backend->component->phases, backend->flags);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Cannot enable discovery component `%s' phases 0x%x with unknown flags %lx\n",
backend->component->name, backend->component->phases, backend->flags);
return -1;
}
@ -973,7 +978,7 @@ hwloc_backend_enable(struct hwloc_backend *backend)
while (NULL != *pprev) {
if ((*pprev)->component == backend->component) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot enable discovery component `%s' phases 0x%x twice\n",
fprintf(stderr, "hwloc: Cannot enable discovery component `%s' phases 0x%x twice\n",
backend->component->name, backend->component->phases);
hwloc_backend_disable(backend);
errno = EBUSY;
@ -983,7 +988,7 @@ hwloc_backend_enable(struct hwloc_backend *backend)
}
if (hwloc_components_verbose)
fprintf(stderr, "Enabling discovery component `%s' with phases 0x%x (among 0x%x)\n",
fprintf(stderr, "hwloc: Enabling discovery component `%s' with phases 0x%x (among 0x%x)\n",
backend->component->name, backend->phases, backend->component->phases);
/* enqueue at the end */
@ -1067,7 +1072,7 @@ hwloc_backends_disable_all(struct hwloc_topology *topology)
while (NULL != (backend = topology->backends)) {
struct hwloc_backend *next = backend->next;
if (hwloc_components_verbose)
fprintf(stderr, "Disabling discovery component `%s'\n",
fprintf(stderr, "hwloc: Disabling discovery component `%s'\n",
backend->component->name);
hwloc_backend_disable(backend);
topology->backends = next;

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2020 Inria. All rights reserved.
* Copyright © 2020-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -270,7 +270,7 @@ hwloc__cpukinds_check_duplicate_rankings(struct hwloc_topology *topology)
unsigned i,j;
for(i=0; i<topology->nr_cpukinds; i++)
for(j=i+1; j<topology->nr_cpukinds; j++)
if (topology->cpukinds[i].forced_efficiency == topology->cpukinds[j].forced_efficiency)
if (topology->cpukinds[i].ranking_value == topology->cpukinds[j].ranking_value)
/* if any duplicate, fail */
return -1;
return 0;
@ -343,7 +343,8 @@ enum hwloc_cpukinds_ranking {
HWLOC_CPUKINDS_RANKING_DEFAULT, /* forced + frequency on ARM, forced + coretype_frequency otherwise */
HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY, /* default without forced */
HWLOC_CPUKINDS_RANKING_FORCED_EFFICIENCY,
HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY,
HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY, /* either coretype or frequency or both */
HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY_STRICT, /* both coretype and frequency are required */
HWLOC_CPUKINDS_RANKING_CORETYPE,
HWLOC_CPUKINDS_RANKING_FREQUENCY,
HWLOC_CPUKINDS_RANKING_FREQUENCY_MAX,
@ -358,9 +359,9 @@ hwloc__cpukinds_try_rank_by_info(struct hwloc_topology *topology,
{
unsigned i;
if (HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype+frequency...\n");
/* we need intel_core_type + (base or max freq) for all kinds */
if (HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY_STRICT == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype+frequency_strict...\n");
/* we need intel_core_type AND (base or max freq) for all kinds */
if (!summary->have_intel_core_type
|| (!summary->have_max_freq && !summary->have_base_freq))
return -1;
@ -373,6 +374,21 @@ hwloc__cpukinds_try_rank_by_info(struct hwloc_topology *topology,
kind->ranking_value = (summary->summaries[i].intel_core_type << 20) + summary->summaries[i].max_freq;
}
} else if (HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype+frequency...\n");
/* we need intel_core_type OR (base or max freq) for all kinds */
if (!summary->have_intel_core_type
&& (!summary->have_max_freq && !summary->have_base_freq))
return -1;
/* rank first by coretype (Core>>Atom) then by frequency, base if available, max otherwise */
for(i=0; i<topology->nr_cpukinds; i++) {
struct hwloc_internal_cpukind_s *kind = &topology->cpukinds[i];
if (summary->have_base_freq)
kind->ranking_value = (summary->summaries[i].intel_core_type << 20) + summary->summaries[i].base_freq;
else
kind->ranking_value = (summary->summaries[i].intel_core_type << 20) + summary->summaries[i].max_freq;
}
} else if (HWLOC_CPUKINDS_RANKING_CORETYPE == heuristics) {
hwloc_debug("Trying to rank cpukinds by coretype...\n");
/* we need intel_core_type */
@ -469,6 +485,8 @@ hwloc_internal_cpukinds_rank(struct hwloc_topology *topology)
heuristics = HWLOC_CPUKINDS_RANKING_NONE;
else if (!strcmp(env, "coretype+frequency"))
heuristics = HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY;
else if (!strcmp(env, "coretype+frequency_strict"))
heuristics = HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY_STRICT;
else if (!strcmp(env, "coretype"))
heuristics = HWLOC_CPUKINDS_RANKING_CORETYPE;
else if (!strcmp(env, "frequency"))
@ -481,16 +499,14 @@ hwloc_internal_cpukinds_rank(struct hwloc_topology *topology)
heuristics = HWLOC_CPUKINDS_RANKING_FORCED_EFFICIENCY;
else if (!strcmp(env, "no_forced_efficiency"))
heuristics = HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY;
else if (!hwloc_hide_errors())
fprintf(stderr, "Failed to recognize HWLOC_CPUKINDS_RANKING value %s\n", env);
else if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Failed to recognize HWLOC_CPUKINDS_RANKING value %s\n", env);
}
if (heuristics == HWLOC_CPUKINDS_RANKING_DEFAULT
|| heuristics == HWLOC_CPUKINDS_RANKING_NO_FORCED_EFFICIENCY) {
/* default is forced_efficiency first */
struct hwloc_cpukinds_info_summary summary;
enum hwloc_cpukinds_ranking subheuristics;
const char *arch;
if (heuristics == HWLOC_CPUKINDS_RANKING_DEFAULT)
hwloc_debug("Using default ranking strategy...\n");
@ -508,16 +524,7 @@ hwloc_internal_cpukinds_rank(struct hwloc_topology *topology)
goto failed;
hwloc__cpukinds_summarize_info(topology, &summary);
arch = hwloc_obj_get_info_by_name(topology->levels[0][0], "Architecture");
/* TODO: rather coretype_frequency only on x86/Intel? */
if (arch && (!strncmp(arch, "arm", 3) || !strncmp(arch, "aarch", 5)))
/* then frequency on ARM */
subheuristics = HWLOC_CPUKINDS_RANKING_FREQUENCY;
else
/* or coretype+frequency otherwise */
subheuristics = HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY;
err = hwloc__cpukinds_try_rank_by_info(topology, subheuristics, &summary);
err = hwloc__cpukinds_try_rank_by_info(topology, HWLOC_CPUKINDS_RANKING_CORETYPE_FREQUENCY, &summary);
free(summary.summaries);
if (!err)
goto ready;

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* Copyright © 2011-2012 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -17,6 +17,37 @@
static struct hwloc_internal_distances_s *
hwloc__internal_distances_from_public(hwloc_topology_t topology, struct hwloc_distances_s *distances);
static void
hwloc__groups_by_distances(struct hwloc_topology *topology, unsigned nbobjs, struct hwloc_obj **objs, uint64_t *values, unsigned long kind, unsigned nbaccuracies, float *accuracies, int needcheck);
static void
hwloc_internal_distances_restrict(hwloc_obj_t *objs,
uint64_t *indexes,
hwloc_obj_type_t *different_types,
uint64_t *values,
unsigned nbobjs, unsigned disappeared);
static void
hwloc_internal_distances_print_matrix(struct hwloc_internal_distances_s *dist)
{
unsigned nbobjs = dist->nbobjs;
hwloc_obj_t *objs = dist->objs;
hwloc_uint64_t *values = dist->values;
int gp = !HWLOC_DIST_TYPE_USE_OS_INDEX(dist->unique_type);
unsigned i, j;
fprintf(stderr, "%s", gp ? "gp_index" : "os_index");
for(j=0; j<nbobjs; j++)
fprintf(stderr, " % 5d", (int)(gp ? objs[j]->gp_index : objs[j]->os_index));
fprintf(stderr, "\n");
for(i=0; i<nbobjs; i++) {
fprintf(stderr, " % 5d", (int)(gp ? objs[i]->gp_index : objs[i]->os_index));
for(j=0; j<nbobjs; j++)
fprintf(stderr, " % 5lld", (long long) values[i*nbobjs + j]);
fprintf(stderr, "\n");
}
}
/******************************************************
* Global init, prepare, destroy, dup
*/
@ -244,27 +275,33 @@ int hwloc_distances_release_remove(hwloc_topology_t topology,
return 0;
}
/******************************************************
* Add distances to the topology
/*********************************************************
* Backend functions for adding distances to the topology
*/
/* cancel a distances handle. only needed internally for now */
static void
hwloc__groups_by_distances(struct hwloc_topology *topology, unsigned nbobjs, struct hwloc_obj **objs, uint64_t *values, unsigned long kind, unsigned nbaccuracies, float *accuracies, int needcheck);
hwloc_backend_distances_add__cancel(struct hwloc_internal_distances_s *dist)
{
/* everything is set to NULL in hwloc_backend_distances_add_create() */
free(dist->name);
free(dist->indexes);
free(dist->objs);
free(dist->different_types);
free(dist->values);
free(dist);
}
/* insert a distance matrix in the topology.
* the caller gives us the distances and objs pointers, we'll free them later.
/* prepare a distances handle for later commit in the topology.
* we duplicate the caller's name.
*/
static int
hwloc_internal_distances__add(hwloc_topology_t topology, const char *name,
hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types,
unsigned nbobjs, hwloc_obj_t *objs, uint64_t *indexes, uint64_t *values,
unsigned long kind, unsigned iflags)
hwloc_backend_distances_add_handle_t
hwloc_backend_distances_add_create(hwloc_topology_t topology,
const char *name, unsigned long kind, unsigned long flags)
{
struct hwloc_internal_distances_s *dist;
if (different_types) {
kind |= HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES; /* the user isn't forced to give it */
} else if (kind & HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES) {
if (flags) {
errno = EINVAL;
goto err;
}
@ -273,110 +310,54 @@ hwloc_internal_distances__add(hwloc_topology_t topology, const char *name,
if (!dist)
goto err;
if (name)
if (name) {
dist->name = strdup(name); /* ignore failure */
dist->unique_type = unique_type;
dist->different_types = different_types;
dist->nbobjs = nbobjs;
dist->kind = kind;
dist->iflags = iflags;
assert(!!(iflags & HWLOC_INTERNAL_DIST_FLAG_OBJS_VALID) == !!objs);
if (!objs) {
assert(indexes);
/* we only have indexes, we'll refresh objs from there */
dist->indexes = indexes;
dist->objs = calloc(nbobjs, sizeof(hwloc_obj_t));
if (!dist->objs)
if (!dist->name)
goto err_with_dist;
} else {
unsigned i;
assert(!indexes);
/* we only have objs, generate the indexes arrays so that we can refresh objs later */
dist->objs = objs;
dist->indexes = malloc(nbobjs * sizeof(*dist->indexes));
if (!dist->indexes)
goto err_with_dist;
if (HWLOC_DIST_TYPE_USE_OS_INDEX(dist->unique_type)) {
for(i=0; i<nbobjs; i++)
dist->indexes[i] = objs[i]->os_index;
} else {
for(i=0; i<nbobjs; i++)
dist->indexes[i] = objs[i]->gp_index;
}
}
dist->values = values;
dist->kind = kind;
dist->iflags = HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED;
dist->unique_type = HWLOC_OBJ_TYPE_NONE;
dist->different_types = NULL;
dist->nbobjs = 0;
dist->indexes = NULL;
dist->objs = NULL;
dist->values = NULL;
dist->id = topology->next_dist_id++;
if (topology->last_dist)
topology->last_dist->next = dist;
else
topology->first_dist = dist;
dist->prev = topology->last_dist;
dist->next = NULL;
topology->last_dist = dist;
return 0;
return dist;
err_with_dist:
if (name)
free(dist->name);
free(dist);
hwloc_backend_distances_add__cancel(dist);
err:
free(different_types);
free(objs);
free(indexes);
free(values);
return -1;
return NULL;
}
int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name,
hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values,
unsigned long kind, unsigned long flags)
/* attach objects and values to a distances handle.
* on success, objs and values arrays are attached and will be freed with the distances.
* on failure, the handle is freed.
*/
int
hwloc_backend_distances_add_values(hwloc_topology_t topology __hwloc_attribute_unused,
hwloc_backend_distances_add_handle_t handle,
unsigned nbobjs, hwloc_obj_t *objs,
hwloc_uint64_t *values,
unsigned long flags)
{
unsigned iflags = 0; /* objs not valid */
if (nbobjs < 2) {
errno = EINVAL;
goto err;
}
/* cannot group without objects,
* and we don't group from XML anyway since the hwloc that generated the XML should have grouped already.
*/
if (flags & HWLOC_DISTANCES_ADD_FLAG_GROUP) {
errno = EINVAL;
goto err;
}
return hwloc_internal_distances__add(topology, name, unique_type, different_types, nbobjs, NULL, indexes, values, kind, iflags);
err:
free(indexes);
free(values);
free(different_types);
return -1;
}
static void
hwloc_internal_distances_restrict(hwloc_obj_t *objs,
uint64_t *indexes,
uint64_t *values,
unsigned nbobjs, unsigned disappeared);
int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values,
unsigned long kind, unsigned long flags)
{
hwloc_obj_type_t unique_type, *different_types;
struct hwloc_internal_distances_s *dist = handle;
hwloc_obj_type_t unique_type, *different_types = NULL;
hwloc_uint64_t *indexes = NULL;
unsigned i, disappeared = 0;
unsigned iflags = HWLOC_INTERNAL_DIST_FLAG_OBJS_VALID;
if (nbobjs < 2) {
if (dist->nbobjs || !(dist->iflags & HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED)) {
/* target distances is already set */
errno = EINVAL;
goto err;
}
if (flags || nbobjs < 2 || !objs || !values) {
errno = EINVAL;
goto err;
}
@ -389,15 +370,18 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
/* some objects are NULL */
if (disappeared == nbobjs) {
/* nothing left, drop the matrix */
free(objs);
free(values);
return 0;
errno = ENOENT;
goto err;
}
/* restrict the matrix */
hwloc_internal_distances_restrict(objs, NULL, values, nbobjs, disappeared);
hwloc_internal_distances_restrict(objs, NULL, NULL, values, nbobjs, disappeared);
nbobjs -= disappeared;
}
indexes = malloc(nbobjs * sizeof(*indexes));
if (!indexes)
goto err;
unique_type = objs[0]->type;
for(i=1; i<nbobjs; i++)
if (objs[i]->type != unique_type) {
@ -408,16 +392,108 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
/* heterogeneous types */
different_types = malloc(nbobjs * sizeof(*different_types));
if (!different_types)
goto err;
goto err_with_indexes;
for(i=0; i<nbobjs; i++)
different_types[i] = objs[i]->type;
} else {
/* homogeneous types */
different_types = NULL;
}
if (topology->grouping && (flags & HWLOC_DISTANCES_ADD_FLAG_GROUP) && !different_types) {
dist->nbobjs = nbobjs;
dist->objs = objs;
dist->iflags |= HWLOC_INTERNAL_DIST_FLAG_OBJS_VALID;
dist->indexes = indexes;
dist->unique_type = unique_type;
dist->different_types = different_types;
dist->values = values;
if (different_types)
dist->kind |= HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES;
if (HWLOC_DIST_TYPE_USE_OS_INDEX(dist->unique_type)) {
for(i=0; i<nbobjs; i++)
dist->indexes[i] = objs[i]->os_index;
} else {
for(i=0; i<nbobjs; i++)
dist->indexes[i] = objs[i]->gp_index;
}
return 0;
err_with_indexes:
free(indexes);
err:
hwloc_backend_distances_add__cancel(dist);
return -1;
}
/* attach objects and values to a distance handle.
* on success, objs and values arrays are attached and will be freed with the distances.
* on failure, the handle is freed.
*/
static int
hwloc_backend_distances_add_values_by_index(hwloc_topology_t topology __hwloc_attribute_unused,
hwloc_backend_distances_add_handle_t handle,
unsigned nbobjs, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, hwloc_uint64_t *indexes,
hwloc_uint64_t *values)
{
struct hwloc_internal_distances_s *dist = handle;
hwloc_obj_t *objs;
if (dist->nbobjs || !(dist->iflags & HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED)) {
/* target distances is already set */
errno = EINVAL;
goto err;
}
if (nbobjs < 2 || !indexes || !values || (unique_type == HWLOC_OBJ_TYPE_NONE && !different_types)) {
errno = EINVAL;
goto err;
}
objs = malloc(nbobjs * sizeof(*objs));
if (!objs)
goto err;
dist->nbobjs = nbobjs;
dist->objs = objs;
dist->indexes = indexes;
dist->unique_type = unique_type;
dist->different_types = different_types;
dist->values = values;
if (different_types)
dist->kind |= HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES;
return 0;
err:
hwloc_backend_distances_add__cancel(dist);
return -1;
}
/* commit a distances handle.
* on failure, the handle is freed with its objects and values arrays.
*/
int
hwloc_backend_distances_add_commit(hwloc_topology_t topology,
hwloc_backend_distances_add_handle_t handle,
unsigned long flags)
{
struct hwloc_internal_distances_s *dist = handle;
if (!dist->nbobjs || !(dist->iflags & HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED)) {
/* target distances not ready for commit */
errno = EINVAL;
goto err;
}
if ((flags & HWLOC_DISTANCES_ADD_FLAG_GROUP) && !dist->objs) {
/* cannot group without objects,
* and we don't group from XML anyway since the hwloc that generated the XML should have grouped already.
*/
errno = EINVAL;
goto err;
}
if (topology->grouping && (flags & HWLOC_DISTANCES_ADD_FLAG_GROUP) && !dist->different_types) {
float full_accuracy = 0.f;
float *accuracies;
unsigned nbaccuracies;
@ -431,26 +507,94 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
}
if (topology->grouping_verbose) {
unsigned j;
int gp = !HWLOC_DIST_TYPE_USE_OS_INDEX(unique_type);
fprintf(stderr, "Trying to group objects using distance matrix:\n");
fprintf(stderr, "%s", gp ? "gp_index" : "os_index");
for(j=0; j<nbobjs; j++)
fprintf(stderr, " % 5d", (int)(gp ? objs[j]->gp_index : objs[j]->os_index));
fprintf(stderr, "\n");
for(i=0; i<nbobjs; i++) {
fprintf(stderr, " % 5d", (int)(gp ? objs[i]->gp_index : objs[i]->os_index));
for(j=0; j<nbobjs; j++)
fprintf(stderr, " % 5lld", (long long) values[i*nbobjs + j]);
fprintf(stderr, "\n");
}
hwloc_internal_distances_print_matrix(dist);
}
hwloc__groups_by_distances(topology, nbobjs, objs, values,
kind, nbaccuracies, accuracies, 1 /* check the first matrice */);
hwloc__groups_by_distances(topology, dist->nbobjs, dist->objs, dist->values,
dist->kind, nbaccuracies, accuracies, 1 /* check the first matrix */);
}
return hwloc_internal_distances__add(topology, name, unique_type, different_types, nbobjs, objs, NULL, values, kind, iflags);
if (topology->last_dist)
topology->last_dist->next = dist;
else
topology->first_dist = dist;
dist->prev = topology->last_dist;
dist->next = NULL;
topology->last_dist = dist;
dist->iflags &= ~HWLOC_INTERNAL_DIST_FLAG_NOT_COMMITTED;
return 0;
err:
hwloc_backend_distances_add__cancel(dist);
return -1;
}
/* all-in-one backend function not exported to plugins, only used by XML for now */
int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name,
hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values,
unsigned long kind, unsigned long flags)
{
hwloc_backend_distances_add_handle_t handle;
int err;
handle = hwloc_backend_distances_add_create(topology, name, kind, 0);
if (!handle)
goto err;
err = hwloc_backend_distances_add_values_by_index(topology, handle,
nbobjs, unique_type, different_types, indexes,
values);
if (err < 0)
goto err;
/* arrays are now attached to the handle */
indexes = NULL;
different_types = NULL;
values = NULL;
err = hwloc_backend_distances_add_commit(topology, handle, flags);
if (err < 0)
goto err;
return 0;
err:
free(indexes);
free(different_types);
free(values);
return -1;
}
/* all-in-one backend function not exported to plugins, used by OS backends */
int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values,
unsigned long kind, unsigned long flags)
{
hwloc_backend_distances_add_handle_t handle;
int err;
handle = hwloc_backend_distances_add_create(topology, name, kind, 0);
if (!handle)
goto err;
err = hwloc_backend_distances_add_values(topology, handle,
nbobjs, objs,
values,
0);
if (err < 0)
goto err;
/* arrays are now attached to the handle */
objs = NULL;
values = NULL;
err = hwloc_backend_distances_add_commit(topology, handle, flags);
if (err < 0)
goto err;
return 0;
err:
free(objs);
@ -458,44 +602,54 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
return -1;
}
/********************************
* User API for adding distances
*/
#define HWLOC_DISTANCES_KIND_FROM_ALL (HWLOC_DISTANCES_KIND_FROM_OS|HWLOC_DISTANCES_KIND_FROM_USER)
#define HWLOC_DISTANCES_KIND_MEANS_ALL (HWLOC_DISTANCES_KIND_MEANS_LATENCY|HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH)
#define HWLOC_DISTANCES_KIND_ALL (HWLOC_DISTANCES_KIND_FROM_ALL|HWLOC_DISTANCES_KIND_MEANS_ALL)
#define HWLOC_DISTANCES_KIND_ALL (HWLOC_DISTANCES_KIND_FROM_ALL|HWLOC_DISTANCES_KIND_MEANS_ALL|HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES)
#define HWLOC_DISTANCES_ADD_FLAG_ALL (HWLOC_DISTANCES_ADD_FLAG_GROUP|HWLOC_DISTANCES_ADD_FLAG_GROUP_INACCURATE)
/* The actual function exported to the user
*/
int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
unsigned long kind, unsigned long flags)
void * hwloc_distances_add_create(hwloc_topology_t topology,
const char *name, unsigned long kind,
unsigned long flags)
{
if (!topology->is_loaded) {
errno = EINVAL;
return NULL;
}
if (topology->adopted_shmem_addr) {
errno = EPERM;
return NULL;
}
if ((kind & ~HWLOC_DISTANCES_KIND_ALL)
|| hwloc_weight_long(kind & HWLOC_DISTANCES_KIND_FROM_ALL) != 1
|| hwloc_weight_long(kind & HWLOC_DISTANCES_KIND_MEANS_ALL) != 1) {
errno = EINVAL;
return NULL;
}
return hwloc_backend_distances_add_create(topology, name, kind, flags);
}
int hwloc_distances_add_values(hwloc_topology_t topology,
void *handle,
unsigned nbobjs, hwloc_obj_t *objs,
hwloc_uint64_t *values,
unsigned long flags)
{
unsigned i;
uint64_t *_values;
hwloc_obj_t *_objs;
int err;
if (nbobjs < 2 || !objs || !values || !topology->is_loaded) {
errno = EINVAL;
return -1;
}
if (topology->adopted_shmem_addr) {
errno = EPERM;
return -1;
}
if ((kind & ~HWLOC_DISTANCES_KIND_ALL)
|| hwloc_weight_long(kind & HWLOC_DISTANCES_KIND_FROM_ALL) != 1
|| hwloc_weight_long(kind & HWLOC_DISTANCES_KIND_MEANS_ALL) != 1
|| (flags & ~HWLOC_DISTANCES_ADD_FLAG_ALL)) {
errno = EINVAL;
return -1;
}
/* no strict need to check for duplicates, things shouldn't break */
for(i=1; i<nbobjs; i++)
if (!objs[i]) {
errno = EINVAL;
return -1;
goto out;
}
/* copy the input arrays and give them to the topology */
@ -506,22 +660,78 @@ int hwloc_distances_add(hwloc_topology_t topology,
memcpy(_objs, objs, nbobjs*sizeof(hwloc_obj_t));
memcpy(_values, values, nbobjs*nbobjs*sizeof(*_values));
err = hwloc_internal_distances_add(topology, NULL, nbobjs, _objs, _values, kind, flags);
if (err < 0)
goto out; /* _objs and _values freed in hwloc_internal_distances_add() */
err = hwloc_backend_distances_add_values(topology, handle, nbobjs, _objs, _values, flags);
if (err < 0) {
/* handle was canceled inside hwloc_backend_distances_add_values */
handle = NULL;
goto out_with_arrays;
}
return 0;
out_with_arrays:
free(_objs);
free(_values);
out:
if (handle)
hwloc_backend_distances_add__cancel(handle);
return -1;
}
int
hwloc_distances_add_commit(hwloc_topology_t topology,
void *handle,
unsigned long flags)
{
int err;
if (flags & ~HWLOC_DISTANCES_ADD_FLAG_ALL) {
errno = EINVAL;
goto out;
}
err = hwloc_backend_distances_add_commit(topology, handle, flags);
if (err < 0) {
/* handle was canceled inside hwloc_backend_distances_add_commit */
handle = NULL;
goto out;
}
/* in case we added some groups, see if we need to reconnect */
hwloc_topology_reconnect(topology, 0);
return 0;
out_with_arrays:
free(_values);
free(_objs);
out:
if (handle)
hwloc_backend_distances_add__cancel(handle);
return -1;
}
/* deprecated all-in-one user function */
int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
unsigned long kind, unsigned long flags)
{
void *handle;
int err;
handle = hwloc_distances_add_create(topology, NULL, kind, 0);
if (!handle)
return -1;
err = hwloc_distances_add_values(topology, handle, nbobjs, objs, values, 0);
if (err < 0)
return -1;
err = hwloc_distances_add_commit(topology, handle, flags);
if (err < 0)
return -1;
return 0;
}
/******************************************************
* Refresh objects in distances
*/
@ -529,6 +739,7 @@ int hwloc_distances_add(hwloc_topology_t topology,
static void
hwloc_internal_distances_restrict(hwloc_obj_t *objs,
uint64_t *indexes,
hwloc_obj_type_t *different_types,
uint64_t *values,
unsigned nbobjs, unsigned disappeared)
{
@ -550,6 +761,8 @@ hwloc_internal_distances_restrict(hwloc_obj_t *objs,
objs[newi] = objs[i];
if (indexes)
indexes[newi] = indexes[i];
if (different_types)
different_types[newi] = different_types[i];
newi++;
}
}
@ -594,7 +807,7 @@ hwloc_internal_distances_refresh_one(hwloc_topology_t topology,
return -1;
if (disappeared) {
hwloc_internal_distances_restrict(objs, dist->indexes, dist->values, nbobjs, disappeared);
hwloc_internal_distances_restrict(objs, dist->indexes, dist->different_types, dist->values, nbobjs, disappeared);
dist->nbobjs -= disappeared;
}
@ -1087,3 +1300,210 @@ hwloc__groups_by_distances(struct hwloc_topology *topology,
out_with_groupids:
free(groupids);
}
static int
hwloc__distances_transform_remove_null(struct hwloc_distances_s *distances)
{
hwloc_uint64_t *values = distances->values;
hwloc_obj_t *objs = distances->objs;
unsigned i, nb, nbobjs = distances->nbobjs;
hwloc_obj_type_t unique_type;
for(i=0, nb=0; i<nbobjs; i++)
if (objs[i])
nb++;
if (nb < 2) {
errno = EINVAL;
return -1;
}
if (nb == nbobjs)
return 0;
hwloc_internal_distances_restrict(objs, NULL, NULL, values, nbobjs, nbobjs-nb);
distances->nbobjs = nb;
/* update HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES for convenience */
unique_type = objs[0]->type;
for(i=1; i<nb; i++)
if (objs[i]->type != unique_type) {
unique_type = HWLOC_OBJ_TYPE_NONE;
break;
}
if (unique_type == HWLOC_OBJ_TYPE_NONE)
distances->kind |= HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES;
else
distances->kind &= ~HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES;
return 0;
}
static int
hwloc__distances_transform_links(struct hwloc_distances_s *distances)
{
/* FIXME: we should look for the greatest common denominator
* but we just use the smallest positive value, that's enough for current use-cases.
* We'll return -1 in other cases.
*/
hwloc_uint64_t divider, *values = distances->values;
unsigned i, nbobjs = distances->nbobjs;
if (!(distances->kind & HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH)) {
errno = EINVAL;
return -1;
}
for(i=0; i<nbobjs; i++)
values[i*nbobjs+i] = 0;
/* find the smallest positive value */
divider = 0;
for(i=0; i<nbobjs*nbobjs; i++)
if (values[i] && (!divider || values[i] < divider))
divider = values[i];
if (!divider)
/* only zeroes? do nothing */
return 0;
/* check it divides all values */
for(i=0; i<nbobjs*nbobjs; i++)
if (values[i]%divider) {
errno = ENOENT;
return -1;
}
/* ok, now divide for real */
for(i=0; i<nbobjs*nbobjs; i++)
values[i] /= divider;
return 0;
}
static __hwloc_inline int is_nvswitch(hwloc_obj_t obj)
{
return obj && obj->subtype && !strcmp(obj->subtype, "NVSwitch");
}
static int
hwloc__distances_transform_merge_switch_ports(hwloc_topology_t topology,
struct hwloc_distances_s *distances)
{
struct hwloc_internal_distances_s *dist = hwloc__internal_distances_from_public(topology, distances);
hwloc_obj_t *objs = distances->objs;
hwloc_uint64_t *values = distances->values;
unsigned first, i, j, nbobjs = distances->nbobjs;
if (strcmp(dist->name, "NVLinkBandwidth")) {
errno = EINVAL;
return -1;
}
/* find the first port */
first = (unsigned) -1;
for(i=0; i<nbobjs; i++)
if (is_nvswitch(objs[i])) {
first = i;
break;
}
if (first == (unsigned)-1) {
errno = ENOENT;
return -1;
}
for(j=i+1; j<nbobjs; j++) {
if (is_nvswitch(objs[j])) {
/* another port, merge it */
unsigned k;
for(k=0; k<nbobjs; k++) {
if (k==i || k==j)
continue;
values[k*nbobjs+i] += values[k*nbobjs+j];
values[k*nbobjs+j] = 0;
values[i*nbobjs+k] += values[j*nbobjs+k];
values[j*nbobjs+k] = 0;
}
values[i*nbobjs+i] += values[j*nbobjs+j];
values[j*nbobjs+j] = 0;
}
/* the caller will also call REMOVE_NULL to remove other ports */
objs[j] = NULL;
}
return 0;
}
static int
hwloc__distances_transform_transitive_closure(hwloc_topology_t topology,
struct hwloc_distances_s *distances)
{
struct hwloc_internal_distances_s *dist = hwloc__internal_distances_from_public(topology, distances);
hwloc_obj_t *objs = distances->objs;
hwloc_uint64_t *values = distances->values;
unsigned nbobjs = distances->nbobjs;
unsigned i, j, k;
if (strcmp(dist->name, "NVLinkBandwidth")) {
errno = EINVAL;
return -1;
}
for(i=0; i<nbobjs; i++) {
hwloc_uint64_t bw_i2sw = 0;
if (is_nvswitch(objs[i]))
continue;
/* count our BW to the switch */
for(k=0; k<nbobjs; k++)
if (is_nvswitch(objs[k]))
bw_i2sw += values[i*nbobjs+k];
for(j=0; j<nbobjs; j++) {
hwloc_uint64_t bw_sw2j = 0;
if (i == j || is_nvswitch(objs[j]))
continue;
/* count our BW from the switch */
for(k=0; k<nbobjs; k++)
if (is_nvswitch(objs[k]))
bw_sw2j += values[k*nbobjs+j];
/* bandwidth from i to j is now min(i2sw,sw2j) */
values[i*nbobjs+j] = bw_i2sw > bw_sw2j ? bw_sw2j : bw_i2sw;
}
}
return 0;
}
int
hwloc_distances_transform(hwloc_topology_t topology,
struct hwloc_distances_s *distances,
enum hwloc_distances_transform_e transform,
void *transform_attr,
unsigned long flags)
{
if (flags || transform_attr) {
errno = EINVAL;
return -1;
}
switch (transform) {
case HWLOC_DISTANCES_TRANSFORM_REMOVE_NULL:
return hwloc__distances_transform_remove_null(distances);
case HWLOC_DISTANCES_TRANSFORM_LINKS:
return hwloc__distances_transform_links(distances);
case HWLOC_DISTANCES_TRANSFORM_MERGE_SWITCH_PORTS:
{
int err;
err = hwloc__distances_transform_merge_switch_ports(topology, distances);
if (!err)
err = hwloc__distances_transform_remove_null(distances);
return err;
}
case HWLOC_DISTANCES_TRANSFORM_TRANSITIVE_CLOSURE:
return hwloc__distances_transform_transitive_closure(topology, distances);
default:
errno = EINVAL;
return -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
@ -146,8 +146,9 @@ hwloc_pci_discovery_prepare(struct hwloc_topology *topology)
}
free(buffer);
} else {
fprintf(stderr, "Ignoring HWLOC_PCI_LOCALITY file `%s' too large (%lu bytes)\n",
env, (unsigned long) st.st_size);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc/pci: Ignoring HWLOC_PCI_LOCALITY file `%s' too large (%lu bytes)\n",
env, (unsigned long) st.st_size);
}
}
close(fd);
@ -206,8 +207,11 @@ hwloc_pci_traverse_print_cb(void * cbdata __hwloc_attribute_unused,
else
hwloc_debug("%s Bridge [%04x:%04x]", busid,
pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id);
hwloc_debug(" to %04x:[%02x:%02x]\n",
pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus);
if (pcidev->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI)
hwloc_debug(" to %04x:[%02x:%02x]\n",
pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus);
else
assert(0);
} else
hwloc_debug("%s Device [%04x:%04x (%04x:%04x) rev=%02x class=%04x]\n", busid,
pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id,
@ -251,11 +255,11 @@ hwloc_pci_compare_busids(struct hwloc_obj *a, struct hwloc_obj *b)
if (a->attr->pcidev.domain > b->attr->pcidev.domain)
return HWLOC_PCI_BUSID_HIGHER;
if (a->type == HWLOC_OBJ_BRIDGE
if (a->type == HWLOC_OBJ_BRIDGE && a->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
&& b->attr->pcidev.bus >= a->attr->bridge.downstream.pci.secondary_bus
&& b->attr->pcidev.bus <= a->attr->bridge.downstream.pci.subordinate_bus)
return HWLOC_PCI_BUSID_SUPERSET;
if (b->type == HWLOC_OBJ_BRIDGE
if (b->type == HWLOC_OBJ_BRIDGE && b->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
&& a->attr->pcidev.bus >= b->attr->bridge.downstream.pci.secondary_bus
&& a->attr->pcidev.bus <= b->attr->bridge.downstream.pci.subordinate_bus)
return HWLOC_PCI_BUSID_INCLUDED;
@ -302,7 +306,7 @@ hwloc_pci_add_object(struct hwloc_obj *parent, struct hwloc_obj **parent_io_firs
new->next_sibling = *curp;
*curp = new;
new->parent = parent;
if (new->type == HWLOC_OBJ_BRIDGE) {
if (new->type == HWLOC_OBJ_BRIDGE && new->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) {
/* look at remaining siblings and move some below new */
childp = &new->io_first_child;
curp = &new->next_sibling;
@ -329,7 +333,7 @@ hwloc_pci_add_object(struct hwloc_obj *parent, struct hwloc_obj **parent_io_firs
}
case HWLOC_PCI_BUSID_EQUAL: {
static int reported = 0;
if (!reported && !hwloc_hide_errors()) {
if (!reported && hwloc_hide_errors() < 2) {
fprintf(stderr, "*********************************************************\n");
fprintf(stderr, "* hwloc %s received invalid PCI information.\n", HWLOC_VERSION);
fprintf(stderr, "*\n");
@ -411,7 +415,7 @@ hwloc_pcidisc_add_hostbridges(struct hwloc_topology *topology,
dstnextp = &child->next_sibling;
/* compute hostbridge secondary/subordinate buses */
if (child->type == HWLOC_OBJ_BRIDGE
if (child->type == HWLOC_OBJ_BRIDGE && child->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
&& child->attr->bridge.downstream.pci.subordinate_bus > current_subordinate)
current_subordinate = child->attr->bridge.downstream.pci.subordinate_bus;
@ -486,7 +490,8 @@ hwloc__pci_find_busid_parent(struct hwloc_topology *topology, struct hwloc_pcide
if (env) {
static int reported = 0;
if (!topology->pci_has_forced_locality && !reported) {
fprintf(stderr, "Environment variable %s is deprecated, please use HWLOC_PCI_LOCALITY instead.\n", env);
if (!hwloc_hide_errors())
fprintf(stderr, "hwloc/pci: Environment variable %s is deprecated, please use HWLOC_PCI_LOCALITY instead.\n", env);
reported = 1;
}
if (*env) {
@ -565,7 +570,7 @@ hwloc_pcidisc_tree_attach(struct hwloc_topology *topology, struct hwloc_obj *tre
assert(pciobj->type == HWLOC_OBJ_PCI_DEVICE
|| (pciobj->type == HWLOC_OBJ_BRIDGE && pciobj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI));
if (obj->type == HWLOC_OBJ_BRIDGE) {
if (obj->type == HWLOC_OBJ_BRIDGE && obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) {
domain = obj->attr->bridge.downstream.pci.domain;
bus_min = obj->attr->bridge.downstream.pci.secondary_bus;
bus_max = obj->attr->bridge.downstream.pci.subordinate_bus;

View file

@ -1,4 +1,9 @@
#include <private/internal-components.h>
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_noos_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_synthetic_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_xml_nolibxml_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_windows_component;
HWLOC_DECLSPEC extern const struct hwloc_component hwloc_x86_component;
static const struct hwloc_component * hwloc_static_components[] = {
&hwloc_noos_component,
&hwloc_xml_component,

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012, 2020 Université Bordeaux
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -11,6 +11,7 @@
#include "private/autogen/config.h"
#include "hwloc.h"
#include "hwloc/windows.h"
#include "private/private.h"
#include "private/debug.h"
@ -190,9 +191,6 @@ typedef struct _PROCESSOR_NUMBER {
typedef WORD (WINAPI *PFN_GETACTIVEPROCESSORGROUPCOUNT)(void);
static PFN_GETACTIVEPROCESSORGROUPCOUNT GetActiveProcessorGroupCountProc;
static unsigned long nr_processor_groups = 1;
static unsigned long max_numanode_index = 0;
typedef WORD (WINAPI *PFN_GETACTIVEPROCESSORCOUNT)(WORD);
static PFN_GETACTIVEPROCESSORCOUNT GetActiveProcessorCountProc;
@ -270,9 +268,6 @@ static void hwloc_win_get_function_ptrs(void)
(PFN_VIRTUALFREEEX) GetProcAddress(kernel32, "VirtualFreeEx");
}
if (GetActiveProcessorGroupCountProc)
nr_processor_groups = GetActiveProcessorGroupCountProc();
if (!QueryWorkingSetExProc) {
HMODULE psapi = LoadLibrary("psapi.dll");
if (psapi)
@ -363,6 +358,171 @@ static int hwloc_bitmap_to_single_ULONG_PTR(hwloc_const_bitmap_t set, unsigned *
return 0;
}
/**********************
* Processor Groups
*/
static unsigned long max_numanode_index = 0;
static unsigned long nr_processor_groups = 1;
static hwloc_cpuset_t * processor_group_cpusets = NULL;
static void
hwloc_win_get_processor_groups(void)
{
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX procInfoTotal, tmpprocInfoTotal, procInfo;
DWORD length;
unsigned i;
hwloc_debug("querying windows processor groups\n");
if (!GetActiveProcessorGroupCountProc || !GetLogicalProcessorInformationExProc)
goto error;
nr_processor_groups = GetActiveProcessorGroupCountProc();
if (!nr_processor_groups)
goto error;
hwloc_debug("found %lu windows processor groups\n", nr_processor_groups);
if (nr_processor_groups > 1 && SIZEOF_VOID_P == 4) {
if (!hwloc_hide_errors())
fprintf(stderr, "hwloc: multiple processor groups found on 32bits Windows, topology may be invalid/incomplete.\n");
}
length = 0;
procInfoTotal = NULL;
while (1) {
if (GetLogicalProcessorInformationExProc(RelationGroup, procInfoTotal, &length))
break;
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto error;
tmpprocInfoTotal = realloc(procInfoTotal, length);
if (!tmpprocInfoTotal)
goto error_with_procinfo;
procInfoTotal = tmpprocInfoTotal;
}
processor_group_cpusets = calloc(nr_processor_groups, sizeof(*processor_group_cpusets));
if (!processor_group_cpusets)
goto error_with_procinfo;
for (procInfo = procInfoTotal;
(void*) procInfo < (void*) ((uintptr_t) procInfoTotal + length);
procInfo = (void*) ((uintptr_t) procInfo + procInfo->Size)) {
unsigned id;
assert(procInfo->Relationship == RelationGroup);
for (id = 0; id < procInfo->Group.ActiveGroupCount; id++) {
KAFFINITY mask;
hwloc_bitmap_t set;
set = hwloc_bitmap_alloc();
if (!set)
goto error_with_cpusets;
mask = procInfo->Group.GroupInfo[id].ActiveProcessorMask;
hwloc_debug("group %u %d cpus mask %lx\n", id,
procInfo->Group.GroupInfo[id].ActiveProcessorCount, mask);
/* KAFFINITY is ULONG_PTR */
hwloc_bitmap_set_ith_ULONG_PTR(set, id, mask);
/* FIXME: what if running 32bits on a 64bits windows with 64-processor groups?
* ULONG_PTR is 32bits, so half the group is invisible?
* maybe scale id to id*8/sizeof(ULONG_PTR) so that groups are 64-PU aligned?
*/
hwloc_debug_2args_bitmap("group %u %d bitmap %s\n", id, procInfo->Group.GroupInfo[id].ActiveProcessorCount, set);
processor_group_cpusets[id] = set;
}
}
free(procInfoTotal);
return;
error_with_cpusets:
for(i=0; i<nr_processor_groups; i++) {
if (processor_group_cpusets[i])
hwloc_bitmap_free(processor_group_cpusets[i]);
}
free(processor_group_cpusets);
processor_group_cpusets = NULL;
error_with_procinfo:
free(procInfoTotal);
error:
/* on error set nr to 1 and keep cpusets NULL. We'll use the topology cpuset whenever needed */
nr_processor_groups = 1;
}
static void
hwloc_win_free_processor_groups(void)
{
unsigned i;
for(i=0; i<nr_processor_groups; i++) {
if (processor_group_cpusets[i])
hwloc_bitmap_free(processor_group_cpusets[i]);
}
free(processor_group_cpusets);
processor_group_cpusets = NULL;
nr_processor_groups = 1;
}
int
hwloc_windows_get_nr_processor_groups(hwloc_topology_t topology, unsigned long flags)
{
if (!topology->is_loaded || !topology->is_thissystem) {
errno = EINVAL;
return -1;
}
if (flags) {
errno = EINVAL;
return -1;
}
return nr_processor_groups;
}
int
hwloc_windows_get_processor_group_cpuset(hwloc_topology_t topology, unsigned pg_index, hwloc_cpuset_t cpuset, unsigned long flags)
{
if (!topology->is_loaded || !topology->is_thissystem) {
errno = EINVAL;
return -1;
}
if (!cpuset) {
errno = EINVAL;
return -1;
}
if (flags) {
errno = EINVAL;
return -1;
}
if (pg_index >= nr_processor_groups) {
errno = ENOENT;
return -1;
}
if (!processor_group_cpusets) {
assert(nr_processor_groups == 1);
/* we found no processor groups, return the entire topology as a single one */
hwloc_bitmap_copy(cpuset, topology->levels[0][0]->cpuset);
return 0;
}
if (!processor_group_cpusets[pg_index]) {
errno = ENOENT;
return -1;
}
hwloc_bitmap_copy(cpuset, processor_group_cpusets[pg_index]);
return 0;
}
/**************************************************************
* hwloc PU numbering with respect to Windows processor groups
*
@ -1328,11 +1488,13 @@ hwloc_set_windows_hooks(struct hwloc_binding_hooks *hooks,
static int hwloc_windows_component_init(unsigned long flags __hwloc_attribute_unused)
{
hwloc_win_get_function_ptrs();
hwloc_win_get_processor_groups();
return 0;
}
static void hwloc_windows_component_finalize(unsigned long flags __hwloc_attribute_unused)
{
hwloc_win_free_processor_groups();
}
static struct hwloc_backend *

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2010-2020 Inria. All rights reserved.
* Copyright © 2010-2021 Inria. All rights reserved.
* Copyright © 2010-2013 Université Bordeaux
* Copyright © 2010-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -7,11 +7,14 @@
*
* This backend is only used when the operating system does not export
* the necessary hardware topology information to user-space applications.
* Currently, only the FreeBSD backend relies on this x86 backend.
* Currently, FreeBSD and NetBSD only add PUs and then fallback to this
* backend for CPU/Cache discovery.
*
* Other backends such as Linux have their own way to retrieve various
* pieces of hardware topology information from the operating system
* on various architectures, without having to use this x86-specific code.
* But this backend is still used after them to annotate some objects with
* additional details (CPU info in Package, Inclusiveness in Caches).
*/
#include "private/autogen/config.h"
@ -908,6 +911,16 @@ static void summarize(struct hwloc_backend *backend, struct procinfo *infos, uns
int gotnuma = 0;
int fulldiscovery = (flags & HWLOC_X86_DISC_FLAG_FULL);
#ifdef HWLOC_DEBUG
hwloc_debug("\nSummary of x86 CPUID topology:\n");
for(i=0; i<nbprocs; i++) {
hwloc_debug("PU %u present=%u apicid=%u on PKG %d CORE %d DIE %d NODE %d\n",
i, infos[i].present, infos[i].apicid,
infos[i].ids[PKG], infos[i].ids[CORE], infos[i].ids[DIE], infos[i].ids[NODE]);
}
hwloc_debug("\n");
#endif
for (i = 0; i < nbprocs; i++)
if (infos[i].present) {
hwloc_bitmap_set(complete_cpuset, i);
@ -1247,7 +1260,8 @@ static int
look_procs(struct hwloc_backend *backend, struct procinfo *infos, unsigned long flags,
unsigned highest_cpuid, unsigned highest_ext_cpuid, unsigned *features, enum cpuid_type cpuid_type,
int (*get_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags),
int (*set_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags))
int (*set_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags),
hwloc_bitmap_t restrict_set)
{
struct hwloc_x86_backend_data_s *data = backend->private_data;
struct hwloc_topology *topology = backend->topology;
@ -1267,6 +1281,12 @@ look_procs(struct hwloc_backend *backend, struct procinfo *infos, unsigned long
for (i = 0; i < nbprocs; i++) {
struct cpuiddump *src_cpuiddump = NULL;
if (restrict_set && !hwloc_bitmap_isset(restrict_set, i)) {
/* skip this CPU outside of the binding mask */
continue;
}
if (data->src_cpuiddump_path) {
src_cpuiddump = cpuiddump_read(data->src_cpuiddump_path, i);
if (!src_cpuiddump)
@ -1400,6 +1420,7 @@ static
int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
{
struct hwloc_x86_backend_data_s *data = backend->private_data;
struct hwloc_topology *topology = backend->topology;
unsigned nbprocs = data->nbprocs;
unsigned eax, ebx, ecx = 0, edx;
unsigned i;
@ -1415,9 +1436,21 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
struct hwloc_topology_membind_support memsupport __hwloc_attribute_unused;
int (*get_cpubind)(hwloc_topology_t topology, hwloc_cpuset_t set, int flags) = NULL;
int (*set_cpubind)(hwloc_topology_t topology, hwloc_const_cpuset_t set, int flags) = NULL;
hwloc_bitmap_t restrict_set = NULL;
struct cpuiddump *src_cpuiddump = NULL;
int ret = -1;
/* check if binding works */
memset(&hooks, 0, sizeof(hooks));
support.membind = &memsupport;
/* We could just copy the main hooks (except in some corner cases),
* but the current overhead is negligible, so just always reget them.
*/
hwloc_set_native_binding_hooks(&hooks, &support);
/* in theory, those are only needed if !data->src_cpuiddump_path || HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_BINDING
* but that's the vast majority of cases anyway, and the overhead is very small.
*/
if (data->src_cpuiddump_path) {
/* Just read cpuid from the dump (implies !topology->is_thissystem by default) */
src_cpuiddump = cpuiddump_read(data->src_cpuiddump_path, 0);
@ -1430,13 +1463,6 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
* we may still force use this backend when debugging with !thissystem.
*/
/* check if binding works */
memset(&hooks, 0, sizeof(hooks));
support.membind = &memsupport;
/* We could just copy the main hooks (except in some corner cases),
* but the current overhead is negligible, so just always reget them.
*/
hwloc_set_native_binding_hooks(&hooks, &support);
if (hooks.get_thisthread_cpubind && hooks.set_thisthread_cpubind) {
get_cpubind = hooks.get_thisthread_cpubind;
set_cpubind = hooks.set_thisthread_cpubind;
@ -1456,6 +1482,20 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
}
}
if (topology->flags & HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING) {
restrict_set = hwloc_bitmap_alloc();
if (!restrict_set)
goto out;
if (hooks.get_thisproc_cpubind)
hooks.get_thisproc_cpubind(topology, restrict_set, 0);
else if (hooks.get_thisthread_cpubind)
hooks.get_thisthread_cpubind(topology, restrict_set, 0);
if (hwloc_bitmap_iszero(restrict_set)) {
hwloc_bitmap_free(restrict_set);
restrict_set = NULL;
}
}
if (!src_cpuiddump && !hwloc_have_x86_cpuid())
goto out;
@ -1520,7 +1560,7 @@ int hwloc_look_x86(struct hwloc_backend *backend, unsigned long flags)
ret = look_procs(backend, infos, flags,
highest_cpuid, highest_ext_cpuid, features, cpuid_type,
get_cpubind, set_cpubind);
get_cpubind, set_cpubind, restrict_set);
if (!ret)
/* success, we're done */
goto out_with_os_state;
@ -1545,6 +1585,7 @@ out_with_infos:
}
out:
hwloc_bitmap_free(restrict_set);
if (src_cpuiddump)
cpuiddump_free(src_cpuiddump);
return ret;
@ -1561,6 +1602,11 @@ hwloc_x86_discover(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
assert(dstatus->phase == HWLOC_DISC_PHASE_CPU);
if (topology->flags & HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING) {
/* TODO: Things would work if there's a single PU, no need to rebind */
return 0;
}
if (getenv("HWLOC_X86_TOPOEXT_NUMANODES")) {
flags |= HWLOC_X86_DISC_FLAG_TOPOEXT_NUMANODES;
}
@ -1587,7 +1633,8 @@ hwloc_x86_discover(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
}
if (topology->levels[0][0]->cpuset) {
/* somebody else discovered things */
/* somebody else discovered things, reconnect levels so that we can look at them */
hwloc_topology_reconnect(topology, 0);
if (topology->nb_levels == 2 && topology->level_nbobjects[1] == data->nbprocs) {
/* only PUs were discovered, as much as we would, complete the topology with everything else */
alreadypus = 1;
@ -1595,7 +1642,6 @@ hwloc_x86_discover(struct hwloc_backend *backend, struct hwloc_disc_status *dsta
}
/* several object types were added, we can't easily complete, just do partial discovery */
hwloc_topology_reconnect(topology, 0);
ret = hwloc_look_x86(backend, flags);
if (ret)
hwloc_obj_add_info(topology->levels[0][0], "Backend", "x86");

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2011, 2020 Université Bordeaux
* Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -192,8 +192,9 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
|| lvalue == HWLOC_OBJ_CACHE_INSTRUCTION)
obj->attr->cache.type = (hwloc_obj_cache_type_t) lvalue;
else
fprintf(stderr, "%s: ignoring invalid cache_type attribute %lu\n",
state->global->msgprefix, lvalue);
if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring invalid cache_type attribute %lu\n",
state->global->msgprefix, lvalue);
} else if (hwloc__xml_verbose())
fprintf(stderr, "%s: ignoring cache_type attribute for non-cache object type\n",
state->global->msgprefix);
@ -262,8 +263,8 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
#ifndef HWLOC_HAVE_32BITS_PCI_DOMAIN
} else if (domain > 0xffff) {
static int warned = 0;
if (!warned && !hwloc_hide_errors())
fprintf(stderr, "Ignoring PCI device with non-16bit domain.\nPass --enable-32bits-pci-domain to configure to support such devices\n(warning: it would break the library ABI, don't enable unless really needed).\n");
if (!warned && hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc/xml: Ignoring PCI device with non-16bit domain.\nPass --enable-32bits-pci-domain to configure to support such devices\n(warning: it would break the library ABI, don't enable unless really needed).\n");
warned = 1;
*ignore = 1;
#endif
@ -337,6 +338,7 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
} else {
obj->attr->bridge.upstream_type = (hwloc_obj_bridge_type_t) upstream_type;
obj->attr->bridge.downstream_type = (hwloc_obj_bridge_type_t) downstream_type;
/* FIXME verify that upstream/downstream type is valid */
};
break;
}
@ -361,12 +363,13 @@ hwloc__xml_import_object_attr(struct hwloc_topology *topology,
#ifndef HWLOC_HAVE_32BITS_PCI_DOMAIN
} else if (domain > 0xffff) {
static int warned = 0;
if (!warned && !hwloc_hide_errors())
fprintf(stderr, "Ignoring bridge to PCI with non-16bit domain.\nPass --enable-32bits-pci-domain to configure to support such devices\n(warning: it would break the library ABI, don't enable unless really needed).\n");
if (!warned && hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc/xml: Ignoring bridge to PCI with non-16bit domain.\nPass --enable-32bits-pci-domain to configure to support such devices\n(warning: it would break the library ABI, don't enable unless really needed).\n");
warned = 1;
*ignore = 1;
#endif
} else {
/* FIXME verify that downstream type vs pci info are valid */
obj->attr->bridge.downstream.pci.domain = domain;
obj->attr->bridge.downstream.pci.secondary_bus = secbus;
obj->attr->bridge.downstream.pci.subordinate_bus = subbus;
@ -1232,7 +1235,7 @@ hwloc__xml_import_object(hwloc_topology_t topology,
/* next should be before cur */
if (!childrengotignored) {
static int reported = 0;
if (!reported && !hwloc_hide_errors()) {
if (!reported && hwloc_hide_errors() < 2) {
hwloc__xml_import_report_outoforder(topology, next, cur);
reported = 1;
}
@ -1462,6 +1465,9 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
unsigned long long u;
if (heterotypes) {
hwloc_obj_type_t t = HWLOC_OBJ_TYPE_NONE;
if (!*tmp)
/* reached the end of this indexes attribute */
break;
if (hwloc_type_sscanf(tmp, &t, NULL, 0) < 0) {
if (hwloc__xml_verbose())
fprintf(stderr, "%s: %s with unrecognized heterogeneous type %s\n",
@ -1562,7 +1568,7 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
}
}
hwloc_internal_distances_add_by_index(topology, name, unique_type, different_types, nbobjs, indexes, u64values, kind, 0);
hwloc_internal_distances_add_by_index(topology, name, unique_type, different_types, nbobjs, indexes, u64values, kind, 0 /* assume grouping was applied when this matrix was discovered before exporting to XML */);
/* prevent freeing below */
indexes = NULL;
@ -2644,7 +2650,8 @@ hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topolo
logical_to_v2array = malloc(nbobjs * sizeof(*logical_to_v2array));
if (!logical_to_v2array) {
fprintf(stderr, "xml/export/v1: failed to allocated logical_to_v2array\n");
if (!hwloc_hide_errors())
fprintf(stderr, "hwloc/xml/export/v1: failed to allocated logical_to_v2array\n");
continue;
}

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2012, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -52,6 +52,42 @@
#include <windows.h>
#endif
/*
* Define ZES_ENABLE_SYSMAN=1 early so that the LevelZero backend gets Sysman enabled.
* Use the constructor if supported and/or the Windows DllMain callback.
* Do it in the main hwloc library instead of the levelzero component because
* the latter could be loaded later as a plugin.
*
* L0 seems to be using getenv() to check this variable on Windows
* (at least in the Intel Compute-Runtime of March 2021),
* so use putenv() to set the variable.
*
* For the record, Get/SetEnvironmentVariable() is not exactly the same as getenv/putenv():
* - getenv() doesn't see what was set with SetEnvironmentVariable()
* - GetEnvironmentVariable() doesn't see putenv() in cygwin (while it does in MSVC and MinGW).
* Hence, if L0 ever switches from getenv() to GetEnvironmentVariable(),
* it will break in cygwin, we'll have to use both putenv() and SetEnvironmentVariable().
* Hopefully L0 will be provide a way to enable Sysman without env vars before it happens.
*/
#ifdef HWLOC_HAVE_ATTRIBUTE_CONSTRUCTOR
static void hwloc_constructor(void) __attribute__((constructor));
static void hwloc_constructor(void)
{
if (!getenv("ZES_ENABLE_SYSMAN"))
putenv((char *) "ZES_ENABLE_SYSMAN=1");
}
#endif
#ifdef HWLOC_WIN_SYS
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH) {
if (!getenv("ZES_ENABLE_SYSMAN"))
putenv((char *) "ZES_ENABLE_SYSMAN=1");
}
return TRUE;
}
#endif
unsigned hwloc_get_api_version(void)
{
return HWLOC_API_VERSION;
@ -64,7 +100,7 @@ int hwloc_topology_abi_check(hwloc_topology_t topology)
int hwloc_hide_errors(void)
{
static int hide = 0;
static int hide = 1; /* only show critical errors by default. lstopo will show others */
static int checked = 0;
if (!checked) {
const char *envvar = getenv("HWLOC_HIDE_ERRORS");
@ -106,7 +142,7 @@ static void report_insert_error(hwloc_obj_t new, hwloc_obj_t old, const char *ms
{
static int reported = 0;
if (reason && !reported && !hwloc_hide_errors()) {
if (reason && !reported && hwloc_hide_errors() < 2) {
char newstr[512];
char oldstr[512];
report_insert_error_format_obj(newstr, sizeof(newstr), new);
@ -567,8 +603,9 @@ hwloc_free_unlinked_object(hwloc_obj_t obj)
}
/* Replace old with contents of new object, and make new freeable by the caller.
* Only updates next_sibling/first_child pointers,
* so may only be used during early discovery.
* Requires reconnect (for siblings pointers and group depth),
* fixup of sets (only the main cpuset was likely compared before merging),
* and update of total_memory and group depth.
*/
static void
hwloc_replace_linked_object(hwloc_obj_t old, hwloc_obj_t new)
@ -1348,7 +1385,7 @@ merge_insert_equal(hwloc_obj_t new, hwloc_obj_t old)
/* returns the result of merge, or NULL if not merged */
static __hwloc_inline hwloc_obj_t
hwloc__insert_try_merge_group(hwloc_obj_t old, hwloc_obj_t new)
hwloc__insert_try_merge_group(hwloc_topology_t topology, hwloc_obj_t old, hwloc_obj_t new)
{
if (new->type == HWLOC_OBJ_GROUP && old->type == HWLOC_OBJ_GROUP) {
/* which group do we keep? */
@ -1359,6 +1396,7 @@ hwloc__insert_try_merge_group(hwloc_obj_t old, hwloc_obj_t new)
/* keep the new one, it doesn't want to be merged */
hwloc_replace_linked_object(old, new);
topology->modified = 1;
return new;
} else {
@ -1366,9 +1404,12 @@ hwloc__insert_try_merge_group(hwloc_obj_t old, hwloc_obj_t new)
/* keep the old one, it doesn't want to be merged */
return old;
/* compare subkinds to decice who to keep */
if (new->attr->group.kind < old->attr->group.kind)
/* compare subkinds to decide which group to keep */
if (new->attr->group.kind < old->attr->group.kind) {
/* keep smaller kind */
hwloc_replace_linked_object(old, new);
topology->modified = 1;
}
return old;
}
}
@ -1394,6 +1435,7 @@ hwloc__insert_try_merge_group(hwloc_obj_t old, hwloc_obj_t new)
* and let the caller free the new object
*/
hwloc_replace_linked_object(old, new);
topology->modified = 1;
return old;
} else {
@ -1435,7 +1477,7 @@ hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur
int setres = res;
if (res == HWLOC_OBJ_EQUAL) {
hwloc_obj_t merged = hwloc__insert_try_merge_group(child, obj);
hwloc_obj_t merged = hwloc__insert_try_merge_group(topology, child, obj);
if (merged)
return merged;
/* otherwise compare actual types to decide of the inclusion */
@ -1931,12 +1973,24 @@ hwloc_topology_insert_group_object(struct hwloc_topology *topology, hwloc_obj_t
if (!res)
return NULL;
if (res != obj)
/* merged */
if (res != obj && res->type != HWLOC_OBJ_GROUP)
/* merged, not into a Group, nothing to update */
return res;
/* res == obj means that the object was inserted.
* We need to reconnect levels, fill all its cpu/node sets,
* compute its total memory, group depth, etc.
*
* res != obj usually means that our new group was merged into an
* existing object, no need to recompute anything.
* However, if merging with an existing group, depending on their kinds,
* the contents of obj may overwrite the contents of the old group.
* This requires reconnecting levels, filling sets, recomputing total memory, etc.
*/
/* properly inserted */
hwloc_obj_add_children_sets(obj);
hwloc_obj_add_children_sets(res);
if (hwloc_topology_reconnect(topology, 0) < 0)
return NULL;
@ -1948,7 +2002,7 @@ hwloc_topology_insert_group_object(struct hwloc_topology *topology, hwloc_obj_t
#endif
hwloc_topology_check(topology);
return obj;
return res;
}
hwloc_obj_t
@ -2289,9 +2343,15 @@ hwloc__filter_bridges(hwloc_topology_t topology, hwloc_obj_t root, unsigned dept
child->attr->bridge.depth = depth;
if (child->type == HWLOC_OBJ_BRIDGE
&& filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT
&& !child->io_first_child) {
/* remove bridges that have no child,
* and pci-to-non-pci bridges (pcidev) that no child either.
* keep NVSwitch since they may be used in NVLink matrices.
*/
if (filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT
&& !child->io_first_child
&& (child->type == HWLOC_OBJ_BRIDGE
|| (child->type == HWLOC_OBJ_PCI_DEVICE && (child->attr->pcidev.class_id >> 8) == 0x06
&& (!child->subtype || strcmp(child->subtype, "NVSwitch"))))) {
unlink_and_free_single_object(pchild);
topology->modified = 1;
}
@ -3070,7 +3130,8 @@ hwloc_connect_levels(hwloc_topology_t topology)
tmpnbobjs = realloc(topology->level_nbobjects,
2 * topology->nb_levels_allocated * sizeof(*topology->level_nbobjects));
if (!tmplevels || !tmpnbobjs) {
fprintf(stderr, "hwloc failed to realloc level arrays to %u\n", topology->nb_levels_allocated * 2);
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: failed to realloc level arrays to %u\n", topology->nb_levels_allocated * 2);
/* if one realloc succeeded, make sure the caller will free the new buffer */
if (tmplevels)
@ -3452,15 +3513,18 @@ hwloc_discover(struct hwloc_topology *topology,
hwloc_debug("%s", "\nRemoving empty objects\n");
remove_empty(topology, &topology->levels[0][0]);
if (!topology->levels[0][0]) {
fprintf(stderr, "Topology became empty, aborting!\n");
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Topology became empty, aborting!\n");
return -1;
}
if (hwloc_bitmap_iszero(topology->levels[0][0]->cpuset)) {
fprintf(stderr, "Topology does not contain any PU, aborting!\n");
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Topology does not contain any PU, aborting!\n");
return -1;
}
if (hwloc_bitmap_iszero(topology->levels[0][0]->nodeset)) {
fprintf(stderr, "Topology does not contain any NUMA node, aborting!\n");
if (hwloc_hide_errors() < 2)
fprintf(stderr, "hwloc: Topology does not contain any NUMA node, aborting!\n");
return -1;
}
hwloc_debug_print_objects(0, topology->levels[0][0]);
@ -3698,7 +3762,18 @@ hwloc_topology_set_flags (struct hwloc_topology *topology, unsigned long flags)
return -1;
}
if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES|HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)) {
if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES|HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT|HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING|HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING|HWLOC_TOPOLOGY_FLAG_DONT_CHANGE_BINDING)) {
errno = EINVAL;
return -1;
}
if ((flags & (HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) == HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING) {
/* RESTRICT_TO_CPUBINDING requires THISSYSTEM for binding */
errno = EINVAL;
return -1;
}
if ((flags & (HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) == HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING) {
/* RESTRICT_TO_MEMBINDING requires THISSYSTEM for binding */
errno = EINVAL;
return -1;
}
@ -3985,6 +4060,31 @@ hwloc_topology_load (struct hwloc_topology *topology)
topology->is_loaded = 1;
if (topology->flags & HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_CPUBINDING) {
/* FIXME: filter directly in backends during the discovery.
* Only x86 does it because binding may cause issues on Windows.
*/
hwloc_bitmap_t set = hwloc_bitmap_alloc();
if (set) {
err = hwloc_get_cpubind(topology, set, HWLOC_CPUBIND_STRICT);
if (!err)
hwloc_topology_restrict(topology, set, 0);
hwloc_bitmap_free(set);
}
}
if (topology->flags & HWLOC_TOPOLOGY_FLAG_RESTRICT_TO_MEMBINDING) {
/* FIXME: filter directly in backends during the discovery.
*/
hwloc_bitmap_t set = hwloc_bitmap_alloc();
hwloc_membind_policy_t policy;
if (set) {
err = hwloc_get_membind(topology, set, &policy, HWLOC_MEMBIND_STRICT | HWLOC_MEMBIND_BYNODESET);
if (!err)
hwloc_topology_restrict(topology, set, HWLOC_RESTRICT_FLAG_BYNODESET);
hwloc_bitmap_free(set);
}
}
if (topology->backend_phases & HWLOC_DISC_PHASE_TWEAK) {
dstatus.phase = HWLOC_DISC_PHASE_TWEAK;
hwloc_discover_by_phase(topology, &dstatus, "TWEAK");
@ -4658,6 +4758,9 @@ hwloc__check_misc_children(hwloc_topology_t topology, hwloc_bitmap_t gp_indexes,
static void
hwloc__check_object(hwloc_topology_t topology, hwloc_bitmap_t gp_indexes, hwloc_obj_t obj)
{
hwloc_uint64_t total_memory;
hwloc_obj_t child;
assert(!hwloc_bitmap_isset(gp_indexes, obj->gp_index));
hwloc_bitmap_set(gp_indexes, obj->gp_index);
@ -4715,6 +4818,18 @@ hwloc__check_object(hwloc_topology_t topology, hwloc_bitmap_t gp_indexes, hwloc_
assert(hwloc_cache_type_by_depth_type(obj->attr->cache.depth, obj->attr->cache.type) == obj->type);
}
/* check total memory */
total_memory = 0;
if (obj->type == HWLOC_OBJ_NUMANODE)
total_memory += obj->attr->numanode.local_memory;
for_each_child(child, obj) {
total_memory += child->total_memory;
}
for_each_memory_child(child, obj) {
total_memory += child->total_memory;
}
assert(total_memory == obj->total_memory);
/* check children */
hwloc__check_normal_children(topology, gp_indexes, obj);
hwloc__check_memory_children(topology, gp_indexes, obj);

View file

@ -1,6 +1,6 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2009-2021 Inria. All rights reserved.
* Copyright © 2009-2010, 2020 Université Bordeaux
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
* See COPYING in top-level directory.
@ -395,6 +395,8 @@ hwloc_type_sscanf(const char *string, hwloc_obj_type_t *typep,
} else if (hwloc__type_match(string, "pcibridge", 5)) {
type = HWLOC_OBJ_BRIDGE;
ubtype = HWLOC_OBJ_BRIDGE_PCI;
/* if downstream_type can ever be non-PCI, we'll have to make strings more precise,
* or relax the hwloc_type_sscanf test */
} else if (hwloc__type_match(string, "pcidev", 3)) {
type = HWLOC_OBJ_PCI_DEVICE;
@ -448,7 +450,9 @@ hwloc_type_sscanf(const char *string, hwloc_obj_type_t *typep,
attrp->group.depth = depthattr;
} else if (type == HWLOC_OBJ_BRIDGE && attrsize >= sizeof(attrp->bridge)) {
attrp->bridge.upstream_type = ubtype;
attrp->bridge.downstream_type = HWLOC_OBJ_BRIDGE_PCI; /* nothing else so far */
attrp->bridge.downstream_type = HWLOC_OBJ_BRIDGE_PCI;
/* if downstream_type can ever be non-PCI, we'll have to make strings more precise,
* or relax the hwloc_type_sscanf test */
} else if (type == HWLOC_OBJ_OS_DEVICE && attrsize >= sizeof(attrp->osdev)) {
attrp->osdev.type = ostype;
}
@ -531,6 +535,9 @@ hwloc_obj_type_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t
else
return hwloc_snprintf(string, size, "%s", hwloc_obj_type_string(type));
case HWLOC_OBJ_BRIDGE:
/* if downstream_type can ever be non-PCI, we'll have to make strings more precise,
* or relax the hwloc_type_sscanf test */
assert(obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI);
return hwloc_snprintf(string, size, obj->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_PCI ? "PCIBridge" : "HostBridge");
case HWLOC_OBJ_PCI_DEVICE:
return hwloc_snprintf(string, size, "PCI");
@ -648,8 +655,11 @@ hwloc_obj_attr_snprintf(char * __hwloc_restrict string, size_t size, hwloc_obj_t
} else
*up = '\0';
/* downstream is_PCI */
snprintf(down, sizeof(down), "buses=%04x:[%02x-%02x]",
obj->attr->bridge.downstream.pci.domain, obj->attr->bridge.downstream.pci.secondary_bus, obj->attr->bridge.downstream.pci.subordinate_bus);
if (obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) {
snprintf(down, sizeof(down), "buses=%04x:[%02x-%02x]",
obj->attr->bridge.downstream.pci.domain, obj->attr->bridge.downstream.pci.secondary_bus, obj->attr->bridge.downstream.pci.subordinate_bus);
} else
assert(0);
if (*up)
res = hwloc_snprintf(string, size, "%s%s%s", up, separator, down);
else
@ -736,3 +746,92 @@ int hwloc_bitmap_singlify_per_core(hwloc_topology_t topology, hwloc_bitmap_t cpu
}
return 0;
}
hwloc_obj_t
hwloc_get_obj_with_same_locality(hwloc_topology_t topology, hwloc_obj_t src,
hwloc_obj_type_t type, const char *subtype, const char *nameprefix,
unsigned long flags)
{
if (flags) {
errno = EINVAL;
return NULL;
}
if (hwloc_obj_type_is_normal(src->type) || hwloc_obj_type_is_memory(src->type)) {
/* normal/memory type, look for normal/memory type with same sets */
hwloc_obj_t obj;
if (!hwloc_obj_type_is_normal(type) && !hwloc_obj_type_is_memory(type)) {
errno = EINVAL;
return NULL;
}
obj = NULL;
while ((obj = hwloc_get_next_obj_by_type(topology, type, obj)) != NULL) {
if (!hwloc_bitmap_isequal(src->cpuset, obj->cpuset)
|| !hwloc_bitmap_isequal(src->nodeset, obj->nodeset))
continue;
if (subtype && (!obj->subtype || strcasecmp(subtype, obj->subtype)))
continue;
if (nameprefix && (!obj->name || hwloc_strncasecmp(nameprefix, obj->name, strlen(nameprefix))))
continue;
return obj;
}
errno = ENOENT;
return NULL;
} else if (hwloc_obj_type_is_io(src->type)) {
/* I/O device, look for PCI/OS in same PCI */
hwloc_obj_t pci;
if ((src->type != HWLOC_OBJ_OS_DEVICE && src->type != HWLOC_OBJ_PCI_DEVICE)
|| (type != HWLOC_OBJ_OS_DEVICE && type != HWLOC_OBJ_PCI_DEVICE)) {
errno = EINVAL;
return NULL;
}
/* walk up to find the container */
pci = src;
while (pci->type == HWLOC_OBJ_OS_DEVICE)
pci = pci->parent;
if (type == HWLOC_OBJ_PCI_DEVICE) {
if (pci->type != HWLOC_OBJ_PCI_DEVICE) {
errno = ENOENT;
return NULL;
}
if (subtype && (!pci->subtype || strcasecmp(subtype, pci->subtype))) {
errno = ENOENT;
return NULL;
}
if (nameprefix && (!pci->name || hwloc_strncasecmp(nameprefix, pci->name, strlen(nameprefix)))) {
errno = ENOENT;
return NULL;
}
return pci;
} else {
/* find a matching osdev child */
assert(type == HWLOC_OBJ_OS_DEVICE);
/* FIXME: won't work if we ever store osdevs in osdevs */
hwloc_obj_t child;
for(child = pci->io_first_child; child; child = child->next_sibling) {
if (child->type != HWLOC_OBJ_OS_DEVICE)
/* FIXME: should never occur currently */
continue;
if (subtype && (!child->subtype || strcasecmp(subtype, child->subtype)))
continue;
if (nameprefix && (!child->name || hwloc_strncasecmp(nameprefix, child->name, strlen(nameprefix))))
continue;
return child;
}
}
errno = ENOENT;
return NULL;
} else {
/* nothing for Misc */
errno = EINVAL;
return NULL;
}
}

22
src/3rdparty/llhttp/LICENSE-MIT vendored Normal file
View file

@ -0,0 +1,22 @@
This software is licensed under the MIT License.
Copyright Fedor Indutny, 2018.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

135
src/3rdparty/llhttp/README.md vendored Normal file
View file

@ -0,0 +1,135 @@
# llhttp
[![CI](https://github.com/nodejs/llhttp/workflows/CI/badge.svg)](https://github.com/nodejs/llhttp/actions?query=workflow%3ACI)
Port of [http_parser][0] to [llparse][1].
## Why?
Let's face it, [http_parser][0] is practically unmaintainable. Even
introduction of a single new method results in a significant code churn.
This project aims to:
* Make it maintainable
* Verifiable
* Improving benchmarks where possible
More details in [Fedor Indutny's talk at JSConf EU 2019](https://youtu.be/x3k_5Mi66sY)
## How?
Over time, different approaches for improving [http_parser][0]'s code base
were tried. However, all of them failed due to resulting significant performance
degradation.
This project is a port of [http_parser][0] to TypeScript. [llparse][1] is used
to generate the output C source file, which could be compiled and
linked with the embedder's program (like [Node.js][7]).
## Performance
So far llhttp outperforms http_parser:
| | input size | bandwidth | reqs/sec | time |
|:----------------|-----------:|-------------:|-----------:|--------:|
| **llhttp** | 8192.00 mb | 1777.24 mb/s | 3583799.39 req/sec | 4.61 s |
| **http_parser** | 8192.00 mb | 694.66 mb/s | 1406180.33 req/sec | 11.79 s |
llhttp is faster by approximately **156%**.
## Maintenance
llhttp project has about 1400 lines of TypeScript code describing the parser
itself and around 450 lines of C code and headers providing the helper methods.
The whole [http_parser][0] is implemented in approximately 2500 lines of C, and
436 lines of headers.
All optimizations and multi-character matching in llhttp are generated
automatically, and thus doesn't add any extra maintenance cost. On the contrary,
most of http_parser's code is hand-optimized and unrolled. Instead describing
"how" it should parse the HTTP requests/responses, a maintainer should
implement the new features in [http_parser][0] cautiously, considering
possible performance degradation and manually optimizing the new code.
## Verification
The state machine graph is encoded explicitly in llhttp. The [llparse][1]
automatically checks the graph for absence of loops and correct reporting of the
input ranges (spans) like header names and values. In the future, additional
checks could be performed to get even stricter verification of the llhttp.
## Usage
```C
#include "llhttp.h"
llhttp_t parser;
llhttp_settings_t settings;
/* Initialize user callbacks and settings */
llhttp_settings_init(&settings);
/* Set user callback */
settings.on_message_complete = handle_on_message_complete;
/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between
* HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first
* input.
*/
llhttp_init(&parser, HTTP_BOTH, &settings);
/* Parse request! */
const char* request = "GET / HTTP/1.1\r\n\r\n";
int request_len = strlen(request);
enum llhttp_errno err = llhttp_execute(&parser, request, request_len);
if (err == HPE_OK) {
/* Successfully parsed! */
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err),
parser.reason);
}
```
---
### Bindings to other languages
* Python: [pallas/pyllhttp][8]
* Ruby: [metabahn/llhttp][9]
#### LICENSE
This software is licensed under the MIT License.
Copyright Fedor Indutny, 2018.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
[0]: https://github.com/nodejs/http-parser
[1]: https://github.com/nodejs/llparse
[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling
[3]: https://en.wikipedia.org/wiki/Tail_call
[4]: https://llvm.org/docs/LangRef.html
[5]: https://llvm.org/docs/LangRef.html#call-instruction
[6]: https://clang.llvm.org/
[7]: https://github.com/nodejs/node
[8]: https://github.com/pallas/pyllhttp
[9]: https://github.com/metabahn/llhttp

348
src/3rdparty/llhttp/api.c vendored Normal file
View file

@ -0,0 +1,348 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "llhttp.h"
#define CALLBACK_MAYBE(PARSER, NAME, ...) \
do { \
const llhttp_settings_t* settings; \
settings = (const llhttp_settings_t*) (PARSER)->settings; \
if (settings == NULL || settings->NAME == NULL) { \
err = 0; \
break; \
} \
err = settings->NAME(__VA_ARGS__); \
} while (0)
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings) {
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
}
#if defined(__wasm__)
extern int wasm_on_message_begin(llhttp_t * p);
extern int wasm_on_url(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_status(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_headers_complete(llhttp_t * p);
extern int wasm_on_body(llhttp_t* p, const char* at, size_t length);
extern int wasm_on_message_complete(llhttp_t * p);
const llhttp_settings_t wasm_settings = {
wasm_on_message_begin,
wasm_on_url,
wasm_on_status,
wasm_on_header_field,
wasm_on_header_value,
wasm_on_headers_complete,
wasm_on_body,
wasm_on_message_complete,
NULL,
NULL,
};
llhttp_t* llhttp_alloc(llhttp_type_t type) {
llhttp_t* parser = malloc(sizeof(llhttp_t));
llhttp_init(parser, type, &wasm_settings);
return parser;
}
void llhttp_free(llhttp_t* parser) {
free(parser);
}
/* Some getters required to get stuff from the parser */
uint8_t llhttp_get_type(llhttp_t* parser) {
return parser->type;
}
uint8_t llhttp_get_http_major(llhttp_t* parser) {
return parser->http_major;
}
uint8_t llhttp_get_http_minor(llhttp_t* parser) {
return parser->http_minor;
}
uint8_t llhttp_get_method(llhttp_t* parser) {
return parser->method;
}
int llhttp_get_status_code(llhttp_t* parser) {
return parser->status_code;
}
uint8_t llhttp_get_upgrade(llhttp_t* parser) {
return parser->upgrade;
}
#endif // defined(__wasm__)
void llhttp_reset(llhttp_t* parser) {
llhttp_type_t type = parser->type;
const llhttp_settings_t* settings = parser->settings;
void* data = parser->data;
uint8_t lenient_flags = parser->lenient_flags;
llhttp__internal_init(parser);
parser->type = type;
parser->settings = (void*) settings;
parser->data = data;
parser->lenient_flags = lenient_flags;
}
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {
return llhttp__internal_execute(parser, data, data + len);
}
void llhttp_settings_init(llhttp_settings_t* settings) {
memset(settings, 0, sizeof(*settings));
}
llhttp_errno_t llhttp_finish(llhttp_t* parser) {
int err;
/* We're in an error state. Don't bother doing anything. */
if (parser->error != 0) {
return 0;
}
switch (parser->finish) {
case HTTP_FINISH_SAFE_WITH_CB:
CALLBACK_MAYBE(parser, on_message_complete, parser);
if (err != HPE_OK) return err;
/* FALLTHROUGH */
case HTTP_FINISH_SAFE:
return HPE_OK;
case HTTP_FINISH_UNSAFE:
parser->reason = "Invalid EOF state";
return HPE_INVALID_EOF_STATE;
default:
abort();
}
}
void llhttp_pause(llhttp_t* parser) {
if (parser->error != HPE_OK) {
return;
}
parser->error = HPE_PAUSED;
parser->reason = "Paused";
}
void llhttp_resume(llhttp_t* parser) {
if (parser->error != HPE_PAUSED) {
return;
}
parser->error = 0;
}
void llhttp_resume_after_upgrade(llhttp_t* parser) {
if (parser->error != HPE_PAUSED_UPGRADE) {
return;
}
parser->error = 0;
}
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {
return parser->error;
}
const char* llhttp_get_error_reason(const llhttp_t* parser) {
return parser->reason;
}
void llhttp_set_error_reason(llhttp_t* parser, const char* reason) {
parser->reason = reason;
}
const char* llhttp_get_error_pos(const llhttp_t* parser) {
return parser->error_pos;
}
const char* llhttp_errno_name(llhttp_errno_t err) {
#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME;
switch (err) {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
default: abort();
}
#undef HTTP_ERRNO_GEN
}
const char* llhttp_method_name(llhttp_method_t method) {
#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;
switch (method) {
HTTP_METHOD_MAP(HTTP_METHOD_GEN)
default: abort();
}
#undef HTTP_METHOD_GEN
}
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_HEADERS;
} else {
parser->lenient_flags &= ~LENIENT_HEADERS;
}
}
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_CHUNKED_LENGTH;
} else {
parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH;
}
}
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) {
if (enabled) {
parser->lenient_flags |= LENIENT_KEEP_ALIVE;
} else {
parser->lenient_flags &= ~LENIENT_KEEP_ALIVE;
}
}
/* Callbacks */
int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_begin, s);
return err;
}
int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_url, s, p, endp - p);
return err;
}
int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_url_complete, s);
return err;
}
int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_status, s, p, endp - p);
return err;
}
int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_status_complete, s);
return err;
}
int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_field, s, p, endp - p);
return err;
}
int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_field_complete, s);
return err;
}
int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_value, s, p, endp - p);
return err;
}
int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_header_value_complete, s);
return err;
}
int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_headers_complete, s);
return err;
}
int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_message_complete, s);
return err;
}
int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_body, s, p, endp - p);
return err;
}
int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_header, s);
return err;
}
int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {
int err;
CALLBACK_MAYBE(s, on_chunk_complete, s);
return err;
}
/* Private */
void llhttp__debug(llhttp_t* s, const char* p, const char* endp,
const char* msg) {
if (p == endp) {
fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type,
s->flags, msg);
} else {
fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s,
s->type, s->flags, *p, msg);
}
}

253
src/3rdparty/llhttp/api.h vendored Normal file
View file

@ -0,0 +1,253 @@
#ifndef INCLUDE_LLHTTP_API_H_
#define INCLUDE_LLHTTP_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#if defined(__wasm__)
#define LLHTTP_EXPORT __attribute__((visibility("default")))
#else
#define LLHTTP_EXPORT
#endif
typedef llhttp__internal_t llhttp_t;
typedef struct llhttp_settings_s llhttp_settings_t;
typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);
typedef int (*llhttp_cb)(llhttp_t*);
struct llhttp_settings_s {
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_begin;
llhttp_data_cb on_url;
llhttp_data_cb on_status;
llhttp_data_cb on_header_field;
llhttp_data_cb on_header_value;
/* Possible return values:
* 0 - Proceed normally
* 1 - Assume that request/response has no body, and proceed to parsing the
* next message
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return
* `HPE_PAUSED_UPGRADE`
* -1 - Error
* `HPE_PAUSED`
*/
llhttp_cb on_headers_complete;
llhttp_data_cb on_body;
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
llhttp_cb on_chunk_header;
llhttp_cb on_chunk_complete;
llhttp_cb on_url_complete;
llhttp_cb on_status_complete;
llhttp_cb on_header_field_complete;
llhttp_cb on_header_value_complete;
};
/* Initialize the parser with specific type and user settings.
*
* NOTE: lifetime of `settings` has to be at least the same as the lifetime of
* the `parser` here. In practice, `settings` has to be either a static
* variable or be allocated with `malloc`, `new`, etc.
*/
LLHTTP_EXPORT
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings);
#if defined(__wasm__)
LLHTTP_EXPORT
llhttp_t* llhttp_alloc(llhttp_type_t type);
LLHTTP_EXPORT
void llhttp_free(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_type(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_major(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_minor(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_method(llhttp_t* parser);
LLHTTP_EXPORT
int llhttp_get_status_code(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_upgrade(llhttp_t* parser);
#endif // defined(__wasm__)
/* Reset an already initialized parser back to the start state, preserving the
* existing parser type, callback settings, user data, and lenient flags.
*/
LLHTTP_EXPORT
void llhttp_reset(llhttp_t* parser);
/* Initialize the settings object */
LLHTTP_EXPORT
void llhttp_settings_init(llhttp_settings_t* settings);
/* Parse full or partial request/response, invoking user callbacks along the
* way.
*
* If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing
* interrupts, and such errno is returned from `llhttp_execute()`. If
* `HPE_PAUSED` was used as a errno, the execution can be resumed with
* `llhttp_resume()` call.
*
* In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`
* is returned after fully parsing the request/response. If the user wishes to
* continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.
*
* NOTE: if this function ever returns a non-pause type error, it will continue
* to return the same error upon each successive call up until `llhttp_init()`
* is called.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
/* This method should be called when the other side has no further bytes to
* send (e.g. shutdown of readable side of the TCP connection.)
*
* Requests without `Content-Length` and other messages might require treating
* all incoming bytes as the part of the body, up to the last byte of the
* connection. This method will invoke `on_message_complete()` callback if the
* request was terminated safely. Otherwise a error code would be returned.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_finish(llhttp_t* parser);
/* Returns `1` if the incoming message is parsed until the last byte, and has
* to be completed by calling `llhttp_finish()` on EOF
*/
LLHTTP_EXPORT
int llhttp_message_needs_eof(const llhttp_t* parser);
/* Returns `1` if there might be any other messages following the last that was
* successfully parsed.
*/
LLHTTP_EXPORT
int llhttp_should_keep_alive(const llhttp_t* parser);
/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
* appropriate error reason.
*
* Important: do not call this from user callbacks! User callbacks must return
* `HPE_PAUSED` if pausing is required.
*/
LLHTTP_EXPORT
void llhttp_pause(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
*/
LLHTTP_EXPORT
void llhttp_resume(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
*/
LLHTTP_EXPORT
void llhttp_resume_after_upgrade(llhttp_t* parser);
/* Returns the latest return error */
LLHTTP_EXPORT
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
/* Returns the verbal explanation of the latest returned error.
*
* Note: User callback should set error reason when returning the error. See
* `llhttp_set_error_reason()` for details.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_reason(const llhttp_t* parser);
/* Assign verbal description to the returned error. Must be called in user
* callbacks right before returning the errno.
*
* Note: `HPE_USER` error code might be useful in user callbacks.
*/
LLHTTP_EXPORT
void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
/* Returns the pointer to the last parsed byte before the returned error. The
* pointer is relative to the `data` argument of `llhttp_execute()`.
*
* Note: this method might be useful for counting the number of parsed bytes.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_pos(const llhttp_t* parser);
/* Returns textual name of error code */
LLHTTP_EXPORT
const char* llhttp_errno_name(llhttp_errno_t err);
/* Returns textual name of HTTP method */
LLHTTP_EXPORT
const char* llhttp_method_name(llhttp_method_t method);
/* Enables/disables lenient header value parsing (disabled by default).
*
* Lenient parsing disables header value token checks, extending llhttp's
* protocol support to highly non-compliant clients/server. No
* `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
* lenient parsing is "on".
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and
* `Content-Length` headers (disabled by default).
*
* Normally `llhttp` would error when `Transfer-Encoding` is present in
* conjunction with `Content-Length`. This error is important to prevent HTTP
* request smuggling, but may be less desirable for small number of cases
* involving legacy servers.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0
* requests responses.
*
* Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
* the HTTP request/response after the request/response with `Connection: close`
* and `Content-Length`. This is important to prevent cache poisoning attacks,
* but might interact badly with outdated and insecure clients. With this flag
* the extra request/response will be parsed normally.
*
* **(USE AT YOUR OWN RISK)**
*/
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_API_H_ */

149
src/3rdparty/llhttp/http.c vendored Normal file
View file

@ -0,0 +1,149 @@
#include <stdio.h>
#ifndef LLHTTP__TEST
# include "llhttp.h"
#else
# define llhttp_t llparse_t
#endif /* */
int llhttp_message_needs_eof(const llhttp_t* parser);
int llhttp_should_keep_alive(const llhttp_t* parser);
int llhttp__before_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
/* Set this here so that on_headers_complete() callbacks can see it */
if ((parser->flags & F_UPGRADE) &&
(parser->flags & F_CONNECTION_UPGRADE)) {
/* For responses, "Upgrade: foo" and "Connection: upgrade" are
* mandatory only when it is a 101 Switching Protocols response,
* otherwise it is purely informational, to announce support.
*/
parser->upgrade =
(parser->type == HTTP_REQUEST || parser->status_code == 101);
} else {
parser->upgrade = (parser->method == HTTP_CONNECT);
}
return 0;
}
/* Return values:
* 0 - No body, `restart`, message_complete
* 1 - CONNECT request, `restart`, message_complete, and pause
* 2 - chunk_size_start
* 3 - body_identity
* 4 - body_identity_eof
* 5 - invalid transfer-encoding for request
*/
int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
const char* endp) {
int hasBody;
hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;
if (parser->upgrade && (parser->method == HTTP_CONNECT ||
(parser->flags & F_SKIPBODY) || !hasBody)) {
/* Exit, the rest of the message is in a different protocol. */
return 1;
}
if (parser->flags & F_SKIPBODY) {
return 0;
} else if (parser->flags & F_CHUNKED) {
/* chunked encoding - ignore Content-Length header, prepare for a chunk */
return 2;
} else if (parser->flags & F_TRANSFER_ENCODING) {
if (parser->type == HTTP_REQUEST &&
(parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0) {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field
* is present in a request and the chunked transfer coding is not
* the final encoding, the message body length cannot be determined
* reliably; the server MUST respond with the 400 (Bad Request)
* status code and then close the connection.
*/
return 5;
} else {
/* RFC 7230 3.3.3 */
/* If a Transfer-Encoding header field is present in a response and
* the chunked transfer coding is not the final encoding, the
* message body length is determined by reading the connection until
* it is closed by the server.
*/
return 4;
}
} else {
if (!(parser->flags & F_CONTENT_LENGTH)) {
if (!llhttp_message_needs_eof(parser)) {
/* Assume content-length 0 - read the next */
return 0;
} else {
/* Read body until EOF */
return 4;
}
} else if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
return 0;
} else {
/* Content-Length header given and non-zero */
return 3;
}
}
}
int llhttp__after_message_complete(llhttp_t* parser, const char* p,
const char* endp) {
int should_keep_alive;
should_keep_alive = llhttp_should_keep_alive(parser);
parser->finish = HTTP_FINISH_SAFE;
parser->flags = 0;
/* NOTE: this is ignored in loose parsing mode */
return should_keep_alive;
}
int llhttp_message_needs_eof(const llhttp_t* parser) {
if (parser->type == HTTP_REQUEST) {
return 0;
}
/* See RFC 2616 section 4.4 */
if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
parser->status_code == 204 || /* No Content */
parser->status_code == 304 || /* Not Modified */
(parser->flags & F_SKIPBODY)) { /* response to a HEAD request */
return 0;
}
/* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
if ((parser->flags & F_TRANSFER_ENCODING) &&
(parser->flags & F_CHUNKED) == 0) {
return 1;
}
if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
return 0;
}
return 1;
}
int llhttp_should_keep_alive(const llhttp_t* parser) {
if (parser->http_major > 0 && parser->http_minor > 0) {
/* HTTP/1.1 */
if (parser->flags & F_CONNECTION_CLOSE) {
return 0;
}
} else {
/* HTTP/1.0 or earlier */
if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
return 0;
}
}
return !llhttp_message_needs_eof(parser);
}

14926
src/3rdparty/llhttp/llhttp.c vendored Normal file

File diff suppressed because it is too large Load diff

508
src/3rdparty/llhttp/llhttp.h vendored Normal file
View file

@ -0,0 +1,508 @@
#ifndef INCLUDE_LLHTTP_H_
#define INCLUDE_LLHTTP_H_
#define LLHTTP_VERSION_MAJOR 5
#define LLHTTP_VERSION_MINOR 1
#define LLHTTP_VERSION_PATCH 0
#ifndef LLHTTP_STRICT_MODE
# define LLHTTP_STRICT_MODE 0
#endif
#ifndef INCLUDE_LLHTTP_ITSELF_H_
#define INCLUDE_LLHTTP_ITSELF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef struct llhttp__internal_s llhttp__internal_t;
struct llhttp__internal_s {
int32_t _index;
void* _span_pos0;
void* _span_cb0;
int32_t error;
const char* reason;
const char* error_pos;
void* data;
void* _current;
uint64_t content_length;
uint8_t type;
uint8_t method;
uint8_t http_major;
uint8_t http_minor;
uint8_t header_state;
uint8_t lenient_flags;
uint8_t upgrade;
uint8_t finish;
uint16_t flags;
uint16_t status_code;
void* settings;
};
int llhttp__internal_init(llhttp__internal_t* s);
int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_ITSELF_H_ */
#ifndef LLLLHTTP_C_HEADERS_
#define LLLLHTTP_C_HEADERS_
#ifdef __cplusplus
extern "C" {
#endif
enum llhttp_errno {
HPE_OK = 0,
HPE_INTERNAL = 1,
HPE_STRICT = 2,
HPE_LF_EXPECTED = 3,
HPE_UNEXPECTED_CONTENT_LENGTH = 4,
HPE_CLOSED_CONNECTION = 5,
HPE_INVALID_METHOD = 6,
HPE_INVALID_URL = 7,
HPE_INVALID_CONSTANT = 8,
HPE_INVALID_VERSION = 9,
HPE_INVALID_HEADER_TOKEN = 10,
HPE_INVALID_CONTENT_LENGTH = 11,
HPE_INVALID_CHUNK_SIZE = 12,
HPE_INVALID_STATUS = 13,
HPE_INVALID_EOF_STATE = 14,
HPE_INVALID_TRANSFER_ENCODING = 15,
HPE_CB_MESSAGE_BEGIN = 16,
HPE_CB_HEADERS_COMPLETE = 17,
HPE_CB_MESSAGE_COMPLETE = 18,
HPE_CB_CHUNK_HEADER = 19,
HPE_CB_CHUNK_COMPLETE = 20,
HPE_PAUSED = 21,
HPE_PAUSED_UPGRADE = 22,
HPE_PAUSED_H2_UPGRADE = 23,
HPE_USER = 24
};
typedef enum llhttp_errno llhttp_errno_t;
enum llhttp_flags {
F_CONNECTION_KEEP_ALIVE = 0x1,
F_CONNECTION_CLOSE = 0x2,
F_CONNECTION_UPGRADE = 0x4,
F_CHUNKED = 0x8,
F_UPGRADE = 0x10,
F_CONTENT_LENGTH = 0x20,
F_SKIPBODY = 0x40,
F_TRAILING = 0x80,
F_TRANSFER_ENCODING = 0x200
};
typedef enum llhttp_flags llhttp_flags_t;
enum llhttp_lenient_flags {
LENIENT_HEADERS = 0x1,
LENIENT_CHUNKED_LENGTH = 0x2,
LENIENT_KEEP_ALIVE = 0x4
};
typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;
enum llhttp_type {
HTTP_BOTH = 0,
HTTP_REQUEST = 1,
HTTP_RESPONSE = 2
};
typedef enum llhttp_type llhttp_type_t;
enum llhttp_finish {
HTTP_FINISH_SAFE = 0,
HTTP_FINISH_SAFE_WITH_CB = 1,
HTTP_FINISH_UNSAFE = 2
};
typedef enum llhttp_finish llhttp_finish_t;
enum llhttp_method {
HTTP_DELETE = 0,
HTTP_GET = 1,
HTTP_HEAD = 2,
HTTP_POST = 3,
HTTP_PUT = 4,
HTTP_CONNECT = 5,
HTTP_OPTIONS = 6,
HTTP_TRACE = 7,
HTTP_COPY = 8,
HTTP_LOCK = 9,
HTTP_MKCOL = 10,
HTTP_MOVE = 11,
HTTP_PROPFIND = 12,
HTTP_PROPPATCH = 13,
HTTP_SEARCH = 14,
HTTP_UNLOCK = 15,
HTTP_BIND = 16,
HTTP_REBIND = 17,
HTTP_UNBIND = 18,
HTTP_ACL = 19,
HTTP_REPORT = 20,
HTTP_MKACTIVITY = 21,
HTTP_CHECKOUT = 22,
HTTP_MERGE = 23,
HTTP_MSEARCH = 24,
HTTP_NOTIFY = 25,
HTTP_SUBSCRIBE = 26,
HTTP_UNSUBSCRIBE = 27,
HTTP_PATCH = 28,
HTTP_PURGE = 29,
HTTP_MKCALENDAR = 30,
HTTP_LINK = 31,
HTTP_UNLINK = 32,
HTTP_SOURCE = 33,
HTTP_PRI = 34,
HTTP_DESCRIBE = 35,
HTTP_ANNOUNCE = 36,
HTTP_SETUP = 37,
HTTP_PLAY = 38,
HTTP_PAUSE = 39,
HTTP_TEARDOWN = 40,
HTTP_GET_PARAMETER = 41,
HTTP_SET_PARAMETER = 42,
HTTP_REDIRECT = 43,
HTTP_RECORD = 44,
HTTP_FLUSH = 45
};
typedef enum llhttp_method llhttp_method_t;
#define HTTP_ERRNO_MAP(XX) \
XX(0, OK, OK) \
XX(1, INTERNAL, INTERNAL) \
XX(2, STRICT, STRICT) \
XX(3, LF_EXPECTED, LF_EXPECTED) \
XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \
XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \
XX(6, INVALID_METHOD, INVALID_METHOD) \
XX(7, INVALID_URL, INVALID_URL) \
XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \
XX(9, INVALID_VERSION, INVALID_VERSION) \
XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \
XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \
XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
XX(13, INVALID_STATUS, INVALID_STATUS) \
XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \
XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \
XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
XX(21, PAUSED, PAUSED) \
XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \
XX(24, USER, USER) \
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
XX(30, MKCALENDAR, MKCALENDAR) \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
XX(33, SOURCE, SOURCE) \
XX(34, PRI, PRI) \
XX(35, DESCRIBE, DESCRIBE) \
XX(36, ANNOUNCE, ANNOUNCE) \
XX(37, SETUP, SETUP) \
XX(38, PLAY, PLAY) \
XX(39, PAUSE, PAUSE) \
XX(40, TEARDOWN, TEARDOWN) \
XX(41, GET_PARAMETER, GET_PARAMETER) \
XX(42, SET_PARAMETER, SET_PARAMETER) \
XX(43, REDIRECT, REDIRECT) \
XX(44, RECORD, RECORD) \
XX(45, FLUSH, FLUSH) \
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LLLLHTTP_C_HEADERS_ */
#ifndef INCLUDE_LLHTTP_API_H_
#define INCLUDE_LLHTTP_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#if defined(__wasm__)
#define LLHTTP_EXPORT __attribute__((visibility("default")))
#else
#define LLHTTP_EXPORT
#endif
typedef llhttp__internal_t llhttp_t;
typedef struct llhttp_settings_s llhttp_settings_t;
typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length);
typedef int (*llhttp_cb)(llhttp_t*);
struct llhttp_settings_s {
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_begin;
llhttp_data_cb on_url;
llhttp_data_cb on_status;
llhttp_data_cb on_header_field;
llhttp_data_cb on_header_value;
/* Possible return values:
* 0 - Proceed normally
* 1 - Assume that request/response has no body, and proceed to parsing the
* next message
* 2 - Assume absence of body (as above) and make `llhttp_execute()` return
* `HPE_PAUSED_UPGRADE`
* -1 - Error
* `HPE_PAUSED`
*/
llhttp_cb on_headers_complete;
llhttp_data_cb on_body;
/* Possible return values 0, -1, `HPE_PAUSED` */
llhttp_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
* Possible return values 0, -1, `HPE_PAUSED`
*/
llhttp_cb on_chunk_header;
llhttp_cb on_chunk_complete;
llhttp_cb on_url_complete;
llhttp_cb on_status_complete;
llhttp_cb on_header_field_complete;
llhttp_cb on_header_value_complete;
};
/* Initialize the parser with specific type and user settings.
*
* NOTE: lifetime of `settings` has to be at least the same as the lifetime of
* the `parser` here. In practice, `settings` has to be either a static
* variable or be allocated with `malloc`, `new`, etc.
*/
LLHTTP_EXPORT
void llhttp_init(llhttp_t* parser, llhttp_type_t type,
const llhttp_settings_t* settings);
#if defined(__wasm__)
LLHTTP_EXPORT
llhttp_t* llhttp_alloc(llhttp_type_t type);
LLHTTP_EXPORT
void llhttp_free(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_type(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_major(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_http_minor(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_method(llhttp_t* parser);
LLHTTP_EXPORT
int llhttp_get_status_code(llhttp_t* parser);
LLHTTP_EXPORT
uint8_t llhttp_get_upgrade(llhttp_t* parser);
#endif // defined(__wasm__)
/* Reset an already initialized parser back to the start state, preserving the
* existing parser type, callback settings, user data, and lenient flags.
*/
LLHTTP_EXPORT
void llhttp_reset(llhttp_t* parser);
/* Initialize the settings object */
LLHTTP_EXPORT
void llhttp_settings_init(llhttp_settings_t* settings);
/* Parse full or partial request/response, invoking user callbacks along the
* way.
*
* If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing
* interrupts, and such errno is returned from `llhttp_execute()`. If
* `HPE_PAUSED` was used as a errno, the execution can be resumed with
* `llhttp_resume()` call.
*
* In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`
* is returned after fully parsing the request/response. If the user wishes to
* continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.
*
* NOTE: if this function ever returns a non-pause type error, it will continue
* to return the same error upon each successive call up until `llhttp_init()`
* is called.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);
/* This method should be called when the other side has no further bytes to
* send (e.g. shutdown of readable side of the TCP connection.)
*
* Requests without `Content-Length` and other messages might require treating
* all incoming bytes as the part of the body, up to the last byte of the
* connection. This method will invoke `on_message_complete()` callback if the
* request was terminated safely. Otherwise a error code would be returned.
*/
LLHTTP_EXPORT
llhttp_errno_t llhttp_finish(llhttp_t* parser);
/* Returns `1` if the incoming message is parsed until the last byte, and has
* to be completed by calling `llhttp_finish()` on EOF
*/
LLHTTP_EXPORT
int llhttp_message_needs_eof(const llhttp_t* parser);
/* Returns `1` if there might be any other messages following the last that was
* successfully parsed.
*/
LLHTTP_EXPORT
int llhttp_should_keep_alive(const llhttp_t* parser);
/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set
* appropriate error reason.
*
* Important: do not call this from user callbacks! User callbacks must return
* `HPE_PAUSED` if pausing is required.
*/
LLHTTP_EXPORT
void llhttp_pause(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED`.
*/
LLHTTP_EXPORT
void llhttp_resume(llhttp_t* parser);
/* Might be called to resume the execution after the pause in user's callback.
* See `llhttp_execute()` above for details.
*
* Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`
*/
LLHTTP_EXPORT
void llhttp_resume_after_upgrade(llhttp_t* parser);
/* Returns the latest return error */
LLHTTP_EXPORT
llhttp_errno_t llhttp_get_errno(const llhttp_t* parser);
/* Returns the verbal explanation of the latest returned error.
*
* Note: User callback should set error reason when returning the error. See
* `llhttp_set_error_reason()` for details.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_reason(const llhttp_t* parser);
/* Assign verbal description to the returned error. Must be called in user
* callbacks right before returning the errno.
*
* Note: `HPE_USER` error code might be useful in user callbacks.
*/
LLHTTP_EXPORT
void llhttp_set_error_reason(llhttp_t* parser, const char* reason);
/* Returns the pointer to the last parsed byte before the returned error. The
* pointer is relative to the `data` argument of `llhttp_execute()`.
*
* Note: this method might be useful for counting the number of parsed bytes.
*/
LLHTTP_EXPORT
const char* llhttp_get_error_pos(const llhttp_t* parser);
/* Returns textual name of error code */
LLHTTP_EXPORT
const char* llhttp_errno_name(llhttp_errno_t err);
/* Returns textual name of HTTP method */
LLHTTP_EXPORT
const char* llhttp_method_name(llhttp_method_t method);
/* Enables/disables lenient header value parsing (disabled by default).
*
* Lenient parsing disables header value token checks, extending llhttp's
* protocol support to highly non-compliant clients/server. No
* `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
* lenient parsing is "on".
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of conflicting `Transfer-Encoding` and
* `Content-Length` headers (disabled by default).
*
* Normally `llhttp` would error when `Transfer-Encoding` is present in
* conjunction with `Content-Length`. This error is important to prevent HTTP
* request smuggling, but may be less desirable for small number of cases
* involving legacy servers.
*
* **(USE AT YOUR OWN RISK)**
*/
LLHTTP_EXPORT
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
/* Enables/disables lenient handling of `Connection: close` and HTTP/1.0
* requests responses.
*
* Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
* the HTTP request/response after the request/response with `Connection: close`
* and `Content-Length`. This is important to prevent cache poisoning attacks,
* but might interact badly with outdated and insecure clients. With this flag
* the extra request/response will be parsed normally.
*
* **(USE AT YOUR OWN RISK)**
*/
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INCLUDE_LLHTTP_API_H_ */
#endif /* INCLUDE_LLHTTP_H_ */

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -16,6 +16,13 @@
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
#include "internal/meta.h"
#include <memory>
#if RAPIDJSON_HAS_CXX11
#include <type_traits>
#endif
RAPIDJSON_NAMESPACE_BEGIN
@ -77,19 +84,26 @@ public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
return RAPIDJSON_MALLOC(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
std::free(originalPtr);
RAPIDJSON_FREE(originalPtr);
return NULL;
}
return std::realloc(originalPtr, newSize);
return RAPIDJSON_REALLOC(originalPtr, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return true;
}
bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return false;
}
static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
@ -113,16 +127,64 @@ public:
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
struct SharedData {
ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
size_t refcount;
bool ownBuffer;
};
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
static inline ChunkHeader *GetChunkHead(SharedData *shared)
{
return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
}
static inline uint8_t *GetChunkBuffer(SharedData *shared)
{
return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
}
static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
explicit
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
RAPIDJSON_ASSERT(baseAllocator_ != 0);
RAPIDJSON_ASSERT(shared_ != 0);
if (baseAllocator) {
shared_->ownBaseAllocator = 0;
}
else {
shared_->ownBaseAllocator = baseAllocator_;
}
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = 0;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBuffer = true;
shared_->refcount = 1;
}
//! Constructor with user-supplied buffer.
@ -136,41 +198,101 @@ public:
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
chunk_capacity_(chunkSize),
baseAllocator_(baseAllocator),
shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
{
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0;
chunkHead_->next = 0;
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
shared_->chunkHead->size = 0;
shared_->chunkHead->next = 0;
shared_->ownBaseAllocator = 0;
shared_->ownBuffer = false;
shared_->refcount = 1;
}
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
++shared_->refcount;
}
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
++rhs.shared_->refcount;
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
return *this;
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
chunk_capacity_(rhs.chunk_capacity_),
baseAllocator_(rhs.baseAllocator_),
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
rhs.shared_ = 0;
}
MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_;
chunk_capacity_ = rhs.chunk_capacity_;
shared_ = rhs.shared_;
rhs.shared_ = 0;
return *this;
}
#endif
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() {
~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
if (!shared_) {
// do nothing if moved
return;
}
if (shared_->refcount > 1) {
--shared_->refcount;
return;
}
Clear();
RAPIDJSON_DELETE(ownBaseAllocator_);
BaseAllocator *a = shared_->ownBaseAllocator;
if (shared_->ownBuffer) {
baseAllocator_->Free(shared_);
}
RAPIDJSON_DELETE(a);
}
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() {
while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_);
chunkHead_ = next;
//! Deallocates all memory chunks, excluding the first/user one.
void Clear() RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
for (;;) {
ChunkHeader* c = shared_->chunkHead;
if (!c->next) {
break;
}
shared_->chunkHead = c->next;
baseAllocator_->Free(c);
}
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
shared_->chunkHead->size = 0;
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const {
size_t Capacity() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t capacity = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
@ -178,25 +300,35 @@ public:
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const {
size_t Size() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t size = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
size += c->size;
return size;
}
//! Whether the allocator is shared.
/*! \return true or false.
*/
bool Shared() const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
return shared_->refcount > 1;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size;
void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
shared_->chunkHead->size += size;
return buffer;
}
@ -205,6 +337,7 @@ public:
if (originalPtr == 0)
return Malloc(newSize);
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (newSize == 0)
return NULL;
@ -216,10 +349,10 @@ public:
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
if (chunkHead_->size + increment <= chunkHead_->capacity) {
chunkHead_->size += increment;
if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
shared_->chunkHead->size += increment;
return originalPtr;
}
}
@ -235,50 +368,325 @@ public:
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) { (void)ptr; } // Do nothing
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
//! Compare (equality) with another MemoryPoolAllocator
bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
return shared_ == rhs.shared_;
}
//! Compare (inequality) with another MemoryPoolAllocator
bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
return !operator==(rhs);
}
private:
//! Copy constructor is not permitted.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
//! Copy assignment operator is not permitted.
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = chunkHead_;
chunkHead_ = chunk;
chunk->next = shared_->chunkHead;
shared_->chunkHead = chunk;
return true;
}
else
return false;
}
static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
static inline void* AlignBuffer(void* buf, size_t &size)
{
RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
const uintptr_t mask = sizeof(void*) - 1;
const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
const uintptr_t abuf = (ubuf + mask) & ~mask;
RAPIDJSON_ASSERT(size >= abuf - ubuf);
buf = reinterpret_cast<void*>(abuf);
size -= abuf - ubuf;
}
return buf;
}
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
SharedData *shared_; //!< The shared data of the allocator
};
namespace internal {
template<typename, typename = void>
struct IsRefCounted :
public FalseType
{ };
template<typename T>
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
public TrueType
{ };
}
template<typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
{
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
}
template<typename T, typename A>
inline T *Malloc(A& a, size_t n = 1)
{
return Realloc<T, A>(a, NULL, 0, n);
}
template<typename T, typename A>
inline void Free(A& a, T *p, size_t n = 1)
{
static_cast<void>(Realloc<T, A>(a, p, n, 0));
}
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
#endif
template <typename T, typename BaseAllocator = CrtAllocator>
class StdAllocator :
public std::allocator<T>
{
typedef std::allocator<T> allocator_type;
#if RAPIDJSON_HAS_CXX11
typedef std::allocator_traits<allocator_type> traits_type;
#else
typedef allocator_type traits_type;
#endif
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(std::move(rhs)),
baseAllocator_(std::move(rhs.baseAllocator_))
{ }
#endif
#if RAPIDJSON_HAS_CXX11
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
#endif
/* implicit */
StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(allocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
typedef typename traits_type::size_type size_type;
typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer;
typedef typename traits_type::const_pointer const_pointer;
#if RAPIDJSON_HAS_CXX11
typedef typename std::add_lvalue_reference<value_type>::type &reference;
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return std::addressof(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return traits_type::max_size(*this);
}
template <typename ...Args>
void construct(pointer p, Args&&... args)
{
traits_type::construct(*this, p, std::forward<Args>(args)...);
}
void destroy(pointer p)
{
traits_type::destroy(*this, p);
}
#else // !RAPIDJSON_HAS_CXX11
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
{
return allocator_type::address(r);
}
size_type max_size() const RAPIDJSON_NOEXCEPT
{
return allocator_type::max_size();
}
void construct(pointer p, const_reference r)
{
allocator_type::construct(p, r);
}
void destroy(pointer p)
{
allocator_type::destroy(p);
}
#endif // !RAPIDJSON_HAS_CXX11
template <typename U>
U* allocate(size_type n = 1, const void* = 0)
{
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
}
template <typename U>
void deallocate(U* p, size_type n = 1)
{
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
}
pointer allocate(size_type n = 1, const void* = 0)
{
return allocate<value_type>(n);
}
void deallocate(pointer p, size_type n = 1)
{
deallocate<value_type>(p, n);
}
#if RAPIDJSON_HAS_CXX11
using is_always_equal = std::is_empty<BaseAllocator>;
#endif
template<typename U>
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return baseAllocator_ == rhs.baseAllocator_;
}
template<typename U>
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
{
return !operator==(rhs);
}
//! rapidjson Allocator concept
static const bool kNeedFree = BaseAllocator::kNeedFree;
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
void* Malloc(size_t size)
{
return baseAllocator_.Malloc(size);
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
{
return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
}
static void Free(void *ptr) RAPIDJSON_NOEXCEPT
{
BaseAllocator::Free(ptr);
}
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> :
public std::allocator<void>
{
typedef std::allocator<void> allocator_type;
public:
typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
allocator_type(rhs),
baseAllocator_(rhs.baseAllocator_)
{ }
/* implicit */
StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
allocator_type(),
baseAllocator_(baseAllocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT
{ }
template<typename U>
struct rebind {
typedef StdAllocator<U, BaseAllocator> other;
};
typedef typename allocator_type::value_type value_type;
private:
template <typename, typename>
friend class StdAllocator; // access to StdAllocator<!T>.*
BaseAllocator baseAllocator_;
};
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -24,6 +24,9 @@
#include "encodedstream.h"
#include <new> // placement new
#include <limits>
#ifdef __cpp_lib_three_way_comparison
#include <compare>
#endif
RAPIDJSON_DIAG_PUSH
#ifdef __clang__
@ -39,12 +42,21 @@ RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible lo
RAPIDJSON_DIAG_OFF(effc++)
#endif // __GNUC__
#ifdef GetObject
// see https://github.com/Tencent/rapidjson/issues/1448
// a former included windows.h might have defined a macro called GetObject, which affects
// GetObject defined here. This ensures the macro does not get applied
#pragma push_macro("GetObject")
#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#undef GetObject
#endif
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include <iterator> // std::random_access_iterator_tag
#endif
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#if RAPIDJSON_USE_MEMBERSMAP
#include <map> // std::multimap
#endif
RAPIDJSON_NAMESPACE_BEGIN
@ -56,6 +68,48 @@ class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
/*! \def RAPIDJSON_DEFAULT_ALLOCATOR
\ingroup RAPIDJSON_CONFIG
\brief Allows to choose default allocator.
User can define this to use CrtAllocator or MemoryPoolAllocator.
*/
#ifndef RAPIDJSON_DEFAULT_ALLOCATOR
#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator>
#endif
/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
\ingroup RAPIDJSON_CONFIG
\brief Allows to choose default stack allocator for Document.
User can define this to use CrtAllocator or MemoryPoolAllocator.
*/
#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator
#endif
/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User defined kDefaultObjectCapacity value.
User can define this as any natural number.
*/
#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
// number of objects that rapidjson::Value allocates memory for by default
#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16
#endif
/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
\ingroup RAPIDJSON_CONFIG
\brief User defined kDefaultArrayCapacity value.
User can define this as any natural number.
*/
#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
// number of array elements that rapidjson::Value allocates memory for by default
#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16
#endif
//! Name-value pair in a JSON object value.
/*!
This class was internal to GenericValue. It used to be a inner struct.
@ -63,15 +117,45 @@ class GenericDocument;
https://code.google.com/p/rapidjson/issues/detail?id=64
*/
template <typename Encoding, typename Allocator>
struct GenericMember {
class GenericMember {
public:
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
GenericValue<Encoding, Allocator> value; //!< value of member.
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT
: name(std::move(rhs.name)),
value(std::move(rhs.value))
{
}
//! Move assignment in C++11
GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT {
return *this = static_cast<GenericMember&>(rhs);
}
#endif
//! Assignment with move semantics.
/*! \param rhs Source of the assignment. Its name and value will become a null value after assignment.
*/
GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT {
if (RAPIDJSON_LIKELY(this != &rhs)) {
name = rhs.name;
value = rhs.value;
}
return *this;
}
// swap() for std::sort() and other potential use in STL.
friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {
a.name.Swap(b.name);
a.value.Swap(b.value);
}
private:
//! Copy constructor is not permitted.
GenericMember(const GenericMember& rhs);
};
///////////////////////////////////////////////////////////////////////////////
@ -175,12 +259,16 @@ public:
//! @name relations
//@{
bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
template <bool Const_> bool operator==(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ == that.ptr_; }
template <bool Const_> bool operator!=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ != that.ptr_; }
template <bool Const_> bool operator<=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <= that.ptr_; }
template <bool Const_> bool operator>=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ >= that.ptr_; }
template <bool Const_> bool operator< (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ < that.ptr_; }
template <bool Const_> bool operator> (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ > that.ptr_; }
#ifdef __cpp_lib_three_way_comparison
template <bool Const_> std::strong_ordering operator<=>(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <=> that.ptr_; }
#endif
//@}
//! @name dereference
@ -210,12 +298,14 @@ class GenericMemberIterator;
//! non-const GenericMemberIterator
template <typename Encoding, typename Allocator>
class GenericMemberIterator<false,Encoding,Allocator> {
public:
//! use plain pointer as iterator type
typedef GenericMember<Encoding,Allocator>* Iterator;
};
//! const GenericMemberIterator
template <typename Encoding, typename Allocator>
class GenericMemberIterator<true,Encoding,Allocator> {
public:
//! use plain const pointer as iterator type
typedef const GenericMember<Encoding,Allocator>* Iterator;
};
@ -574,7 +664,7 @@ template <bool, typename> class GenericObject;
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
\tparam Allocator Allocator type for allocating memory of object, array and string.
*/
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR >
class GenericValue {
public:
//! Name-value pair in an object.
@ -651,18 +741,8 @@ public:
template <typename SourceAllocator>
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
switch (rhs.GetType()) {
case kObjectType: {
SizeType count = rhs.data_.o.size;
Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
for (SizeType i = 0; i < count; i++) {
new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
}
data_.f.flags = kObjectFlag;
data_.o.size = data_.o.capacity = count;
SetMembersPointer(lm);
}
case kObjectType:
DoCopyMembers(rhs, allocator, copyConstStrings);
break;
case kArrayType: {
SizeType count = rhs.data_.a.size;
@ -798,25 +878,30 @@ public:
/*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() {
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
// With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
// their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
internal::IsRefCounted<Allocator>::Value)) {
switch(data_.f.flags) {
case kArrayFlag:
{
GenericValue* e = GetElementsPointer();
for (GenericValue* v = e; v != e + data_.a.size; ++v)
v->~GenericValue();
Allocator::Free(e);
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Allocator::Free(e);
}
}
break;
case kObjectFlag:
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
Allocator::Free(GetMembersPointer());
DoFreeMembers();
break;
case kCopyStringFlag:
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Allocator::Free(const_cast<Ch*>(GetStringPointer()));
}
break;
default:
@ -835,8 +920,13 @@ public:
*/
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
if (RAPIDJSON_LIKELY(this != &rhs)) {
// Can't destroy "this" before assigning "rhs", otherwise "rhs"
// could be used after free if it's an sub-Value of "this",
// hence the temporary danse.
GenericValue temp;
temp.RawAssign(rhs);
this->~GenericValue();
RawAssign(rhs);
RawAssign(temp);
}
return *this;
}
@ -1002,6 +1092,7 @@ public:
*/
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
#ifndef __cpp_lib_three_way_comparison
//! Equal-to operator with arbitrary types (symmetric version)
/*! \return (rhs == lhs)
*/
@ -1012,6 +1103,7 @@ public:
*/
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
//@}
#endif
//!@name Type
//@{
@ -1177,10 +1269,7 @@ public:
*/
GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsObject());
if (newCapacity > data_.o.capacity) {
SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
data_.o.capacity = newCapacity;
}
DoReserveMembers(newCapacity, allocator);
return *this;
}
@ -1254,11 +1343,7 @@ public:
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
MemberIterator member = MemberBegin();
for ( ; member != MemberEnd(); ++member)
if (name.StringEqual(member->name))
break;
return member;
return DoFindMember(name);
}
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
@ -1287,14 +1372,7 @@ public:
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
ObjectData& o = data_.o;
if (o.size >= o.capacity)
MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
Member* members = GetMembersPointer();
members[o.size].name.RawAssign(name);
members[o.size].value.RawAssign(value);
o.size++;
DoAddMember(name, value, allocator);
return *this;
}
@ -1428,9 +1506,7 @@ public:
*/
void RemoveAllMembers() {
RAPIDJSON_ASSERT(IsObject());
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
data_.o.size = 0;
DoClearMembers();
}
//! Remove a member in object by its name.
@ -1474,14 +1550,7 @@ public:
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
if (data_.o.size > 1 && m != last)
*m = *last; // Move the last one to this place
else
m->~Member(); // Only one left, just destroy
--data_.o.size;
return m;
return DoRemoveMember(m);
}
//! Remove a member from an object by iterator.
@ -1513,13 +1582,7 @@ public:
RAPIDJSON_ASSERT(first >= MemberBegin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= MemberEnd());
MemberIterator pos = MemberBegin() + (first - MemberBegin());
for (MemberIterator itr = pos; itr != last; ++itr)
itr->~Member();
std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
data_.o.size -= static_cast<SizeType>(last - first);
return pos;
return DoEraseMembers(first, last);
}
//! Erase a member in object by its name.
@ -1548,7 +1611,9 @@ public:
}
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
//@}
@ -1770,12 +1835,12 @@ public:
//!@name String
//@{
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
//! Get the length of string.
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
//! Set this value as a string without copying source string.
/*! This version has better performance with supplied length, and also support string containing null character.
@ -1886,7 +1951,7 @@ public:
case kArrayType:
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
return false;
for (const GenericValue* v = Begin(); v != End(); ++v)
for (ConstValueIterator v = Begin(); v != End(); ++v)
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
return false;
return handler.EndArray(data_.a.size);
@ -1922,25 +1987,26 @@ private:
// Initial flags of different types.
kNullFlag = kNullType,
kTrueFlag = kTrueType | kBoolFlag,
kFalseFlag = kFalseType | kBoolFlag,
kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
kConstStringFlag = kStringType | kStringFlag,
kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
// These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types.
kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag),
kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag),
kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag),
kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag),
kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag),
kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag),
kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag),
kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag),
kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag),
kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag),
kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag),
kObjectFlag = kObjectType,
kArrayFlag = kArrayType,
kTypeMask = 0x07
};
static const SizeType kDefaultArrayCapacity = 16;
static const SizeType kDefaultObjectCapacity = 16;
static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY;
static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY;
struct Flag {
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
@ -2023,6 +2089,13 @@ private:
Flag f;
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
}
static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
}
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
@ -2030,6 +2103,286 @@ private:
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
#if RAPIDJSON_USE_MEMBERSMAP
struct MapTraits {
struct Less {
bool operator()(const Data& s1, const Data& s2) const {
SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
return cmp < 0 || (cmp == 0 && n1 < n2);
}
};
typedef std::pair<const Data, SizeType> Pair;
typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
typedef typename Map::iterator Iterator;
};
typedef typename MapTraits::Map Map;
typedef typename MapTraits::Less MapLess;
typedef typename MapTraits::Pair MapPair;
typedef typename MapTraits::Iterator MapIterator;
//
// Layout of the members' map/array, re(al)located according to the needed capacity:
//
// {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
//
// (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
//
static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
return RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)) +
RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
capacity * sizeof(MapIterator);
}
static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)));
}
static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)));
}
static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
RAPIDJSON_ALIGN(sizeof(Map*)) +
RAPIDJSON_ALIGN(sizeof(SizeType)) +
RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
}
static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
RAPIDJSON_ASSERT(members != 0);
return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
RAPIDJSON_ALIGN(sizeof(SizeType)) -
RAPIDJSON_ALIGN(sizeof(Map*)));
}
// Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
#if RAPIDJSON_HAS_CXX11
MapIterator ret = std::move(rhs);
#else
MapIterator ret = rhs;
#endif
rhs.~MapIterator();
return ret;
}
Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
GetMapCapacity(*newMap) = newCapacity;
if (!oldMap) {
*newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
}
else {
*newMap = *oldMap;
size_t count = (*oldMap)->size();
std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
static_cast<void*>(GetMapMembers(*oldMap)),
count * sizeof(Member));
MapIterator *oldIt = GetMapIterators(*oldMap),
*newIt = GetMapIterators(*newMap);
while (count--) {
new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
}
Allocator::Free(oldMap);
}
return *newMap;
}
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
return GetMapMembers(DoReallocMap(0, capacity, allocator));
}
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
ObjectData& o = data_.o;
if (newCapacity > o.capacity) {
Member* oldMembers = GetMembersPointer();
Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
*&newMap = DoReallocMap(oldMap, newCapacity, allocator);
RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
o.capacity = newCapacity;
}
}
template <typename SourceAllocator>
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
if (Member* members = GetMembersPointer()) {
Map* &map = GetMap(members);
MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
if (mit != map->end()) {
return MemberIterator(&members[mit->second]);
}
}
return MemberEnd();
}
void DoClearMembers() {
if (Member* members = GetMembersPointer()) {
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
for (SizeType i = 0; i < data_.o.size; i++) {
map->erase(DropMapIterator(mit[i]));
members[i].~Member();
}
data_.o.size = 0;
}
}
void DoFreeMembers() {
if (Member* members = GetMembersPointer()) {
GetMap(members)->~Map();
for (SizeType i = 0; i < data_.o.size; i++) {
members[i].~Member();
}
if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
Map** map = &GetMap(members);
Allocator::Free(*map);
Allocator::Free(map);
}
}
}
#else // !RAPIDJSON_USE_MEMBERSMAP
RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
return Malloc<Member>(allocator, capacity);
}
void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
ObjectData& o = data_.o;
if (newCapacity > o.capacity) {
Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
o.capacity = newCapacity;
}
}
template <typename SourceAllocator>
MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator member = MemberBegin();
for ( ; member != MemberEnd(); ++member)
if (name.StringEqual(member->name))
break;
return member;
}
void DoClearMembers() {
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
data_.o.size = 0;
}
void DoFreeMembers() {
for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
m->~Member();
Allocator::Free(GetMembersPointer());
}
#endif // !RAPIDJSON_USE_MEMBERSMAP
void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
ObjectData& o = data_.o;
if (o.size >= o.capacity)
DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
Member* members = GetMembersPointer();
Member* m = members + o.size;
m->name.RawAssign(name);
m->value.RawAssign(value);
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
#endif
++o.size;
}
MemberIterator DoRemoveMember(MemberIterator m) {
ObjectData& o = data_.o;
Member* members = GetMembersPointer();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(members);
MapIterator* mit = GetMapIterators(map);
SizeType mpos = static_cast<SizeType>(&*m - members);
map->erase(DropMapIterator(mit[mpos]));
#endif
MemberIterator last(members + (o.size - 1));
if (o.size > 1 && m != last) {
#if RAPIDJSON_USE_MEMBERSMAP
new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
mit[mpos]->second = mpos;
#endif
*m = *last; // Move the last one to this place
}
else {
m->~Member(); // Only one left, just destroy
}
--o.size;
return m;
}
MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
ObjectData& o = data_.o;
MemberIterator beg = MemberBegin(),
pos = beg + (first - beg),
end = MemberEnd();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(GetMembersPointer());
MapIterator* mit = GetMapIterators(map);
#endif
for (MemberIterator itr = pos; itr != last; ++itr) {
#if RAPIDJSON_USE_MEMBERSMAP
map->erase(DropMapIterator(mit[itr - beg]));
#endif
itr->~Member();
}
#if RAPIDJSON_USE_MEMBERSMAP
if (first != last) {
// Move remaining members/iterators
MemberIterator next = pos + (last - first);
for (MemberIterator itr = pos; next != end; ++itr, ++next) {
std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
SizeType mpos = static_cast<SizeType>(itr - beg);
new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
mit[mpos]->second = mpos;
}
}
#else
std::memmove(static_cast<void*>(&*pos), &*last,
static_cast<size_t>(end - last) * sizeof(Member));
#endif
o.size -= static_cast<SizeType>(last - first);
return pos;
}
template <typename SourceAllocator>
void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
data_.f.flags = kObjectFlag;
SizeType count = rhs.data_.o.size;
Member* lm = DoAllocMembers(count, allocator);
const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(lm);
MapIterator* mit = GetMapIterators(map);
#endif
for (SizeType i = 0; i < count; i++) {
new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
#if RAPIDJSON_USE_MEMBERSMAP
new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
#endif
}
data_.o.size = data_.o.capacity = count;
SetMembersPointer(lm);
}
// Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
data_.f.flags = kArrayFlag;
@ -2047,9 +2400,16 @@ private:
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
data_.f.flags = kObjectFlag;
if (count) {
Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
Member* m = DoAllocMembers(count, allocator);
SetMembersPointer(m);
std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
#if RAPIDJSON_USE_MEMBERSMAP
Map* &map = GetMap(m);
MapIterator* mit = GetMapIterators(map);
for (SizeType i = 0; i < count; i++) {
new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
}
#endif
}
else
SetMembersPointer(0);
@ -2120,7 +2480,7 @@ typedef GenericValue<UTF8<> > Value;
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
*/
template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR, typename StackAllocator = RAPIDJSON_DEFAULT_STACK_ALLOCATOR >
class GenericDocument : public GenericValue<Encoding, Allocator> {
public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
@ -2170,6 +2530,13 @@ public:
#endif
~GenericDocument() {
// Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
// runs last and may access its elements or members which would be freed
// with an allocator like MemoryPoolAllocator (CrtAllocator does not
// free its data when destroyed, but MemoryPoolAllocator does).
if (ownAllocator_) {
ValueType::SetNull();
}
Destroy();
}
@ -2505,6 +2872,7 @@ private:
//! GenericDocument with UTF8 encoding
typedef GenericDocument<UTF8<> > Document;
//! Helper class for accessing Value of array type.
/*!
Instance of this helper class is obtained by \c GenericValue::GetArray().
@ -2529,6 +2897,7 @@ public:
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
~GenericArray() {}
operator ValueType&() const { return value_; }
SizeType Size() const { return value_.Size(); }
SizeType Capacity() const { return value_.Capacity(); }
bool Empty() const { return value_.Empty(); }
@ -2584,6 +2953,7 @@ public:
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
~GenericObject() {}
operator ValueType&() const { return value_; }
SizeType MemberCount() const { return value_.MemberCount(); }
SizeType MemberCapacity() const { return value_.MemberCapacity(); }
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
@ -2649,4 +3019,9 @@ private:
RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP
#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#pragma pop_macro("GetObject")
#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
#endif
#endif // RAPIDJSON_DOCUMENT_H_

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -65,6 +65,54 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
}
}
//! Maps error code of validation into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param validateErrorCode Error code obtained from validator.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
switch (validateErrorCode) {
case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END
#ifdef __clang__

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -152,6 +152,61 @@ private:
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
///////////////////////////////////////////////////////////////////////////////
// ValidateErrorCode
//! Error codes when validating.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericSchemaValidator
*/
enum ValidateErrorCode {
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
kValidateErrorNone = 0, //!< No error.
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
kValidateErrorPatternProperties, //!< See other errors.
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
kValidateErrorType, //!< Property has a type that is not allowed by the schema..
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
};
//! Function pointer type of GetValidateError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetValidateError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
RAPIDJSON_NAMESPACE_END
#ifdef __clang__

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -102,7 +102,7 @@ class PrettyWriter;
// document.h
template <typename Encoding, typename Allocator>
struct GenericMember;
class GenericMember;
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -17,7 +17,7 @@
#include "../rapidjson.h"
#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128
#pragma intrinsic(_umul128)
#endif
@ -37,7 +37,8 @@ public:
digits_[0] = u;
}
BigInteger(const char* decimals, size_t length) : count_(1) {
template<typename Ch>
BigInteger(const Ch* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
@ -221,7 +222,8 @@ public:
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
template<typename Ch>
void AppendDecimal64(const Ch* begin, const Ch* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
@ -236,11 +238,12 @@ private:
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end) {
template<typename Ch>
static uint64_t ParseUint64(const Ch* begin, const Ch* end) {
uint64_t r = 0;
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0');
for (const Ch* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9'));
r = r * 10u + static_cast<unsigned>(*p - Ch('0'));
}
return r;
}

71
src/3rdparty/rapidjson/internal/clzll.h vendored Normal file
View file

@ -0,0 +1,71 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_CLZLL_H_
#define RAPIDJSON_CLZLL_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && !defined(UNDER_CE)
#include <intrin.h>
#if defined(_WIN64)
#pragma intrinsic(_BitScanReverse64)
#else
#pragma intrinsic(_BitScanReverse)
#endif
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline uint32_t clzll(uint64_t x) {
// Passing 0 to __builtin_clzll is UB in GCC and results in an
// infinite loop in the software implementation.
RAPIDJSON_ASSERT(x != 0);
#if defined(_MSC_VER) && !defined(UNDER_CE)
unsigned long r = 0;
#if defined(_WIN64)
_BitScanReverse64(&r, x);
#else
// Scan the high 32 bits.
if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 - (r + 32);
// Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
#endif // _WIN64
return 63 - r;
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
// __builtin_clzll wrapper
return static_cast<uint32_t>(__builtin_clzll(x));
#else
// naive version
uint32_t r = 0;
while (!(x & (static_cast<uint64_t>(1) << 63))) {
x <<= 1;
++r;
}
return r;
#endif // _MSC_VER
}
#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_CLZLL_H_

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -20,11 +20,11 @@
#define RAPIDJSON_DIYFP_H_
#include "../rapidjson.h"
#include "clzll.h"
#include <limits>
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include <intrin.h>
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
#endif
@ -100,22 +100,8 @@ struct DiyFp {
}
DiyFp Normalize() const {
RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f);
int s = static_cast<int>(clzll(f));
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary() const {

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -58,7 +58,11 @@ inline int CountDecimalDigit32(uint32_t n) {
}
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
static const uint64_t kPow10[] = { 1U, 10U, 100U, 1000U, 10000U, 100000U, 1000000U, 10000000U, 100000000U,
1000000000U, 10000000000U, 100000000000U, 1000000000000U,
10000000000000U, 100000000000000U, 1000000000000000U,
10000000000000000U, 100000000000000000U, 1000000000000000000U,
10000000000000000000U };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f);
return;
}
}
@ -103,7 +107,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
if (p2 < delta) {
*K += kappa;
int index = -kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0));
return;
}
}

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -23,7 +23,6 @@
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
@ -32,9 +31,6 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#if __GNUC__ >= 7
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
#endif
#endif
#ifndef RAPIDJSON_REGEX_VERBOSE
@ -291,6 +287,7 @@ private:
if (!CharacterEscape(ds, &codepoint))
return; // Unsupported escape character
// fall through to default
RAPIDJSON_DELIBERATE_FALLTHROUGH;
default: // Pattern character
PushOperand(operandStack, codepoint);
@ -520,6 +517,7 @@ private:
else if (!CharacterEscape(ds, &codepoint))
return false;
// fall through to default
RAPIDJSON_DELIBERATE_FALLTHROUGH;
default:
switch (step) {
@ -529,6 +527,7 @@ private:
break;
}
// fall through to step 0 for other characters
RAPIDJSON_DELIBERATE_FALLTHROUGH;
case 0:
{

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -45,6 +45,20 @@ inline SizeType StrLen(const wchar_t* s) {
return SizeType(std::wcslen(s));
}
//! Custom strcmpn() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s1 Null-terminated input string.
\param s2 Null-terminated input string.
\return 0 if equal
*/
template<typename Ch>
inline int StrCmp(const Ch* s1, const Ch* s2) {
RAPIDJSON_ASSERT(s1 != 0);
RAPIDJSON_ASSERT(s2 != 0);
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
}
//! Returns number of code points in a encoded string.
template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -128,17 +128,18 @@ inline bool StrtodFast(double d, int p, double* result) {
}
// Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
template<typename Ch>
inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) {
uint64_t significand = 0;
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < dLen; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5')))
break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
significand = significand * 10u + static_cast<unsigned>(decimals[i] - Ch('0'));
}
if (i < dLen && decimals[i] >= '5') // Rounding
if (i < dLen && decimals[i] >= Ch('5')) // Rounding
significand++;
int remaining = dLen - i;
@ -205,7 +206,8 @@ inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
template<typename Ch>
inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) {
RAPIDJSON_ASSERT(dLen >= 0);
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
Double a(approx);
@ -223,7 +225,8 @@ inline double StrtodBigInteger(double approx, const char* decimals, int dLen, in
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
template<typename Ch>
inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -16,6 +16,7 @@
#define RAPIDJSON_POINTER_H_
#include "document.h"
#include "uri.h"
#include "internal/itoa.h"
#ifdef __clang__
@ -80,6 +81,8 @@ class GenericPointer {
public:
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
typedef typename ValueType::Ch Ch; //!< Character type from Value
typedef GenericUri<ValueType, Allocator> UriType;
//! A token is the basic units of internal representation.
/*!
@ -163,7 +166,7 @@ public:
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
//! Copy constructor.
GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
*this = rhs;
}
@ -488,10 +491,11 @@ public:
v = &((*v)[t->index]);
}
else {
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd()) {
v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
m = v->MemberEnd();
v = &(--m)->value; // Assumes AddMember() appends at the end
exist = false;
}
else
@ -519,6 +523,70 @@ public:
//@}
//!@name Compute URI
//@{
//! Compute the in-scope URI for a subtree.
// For use with JSON pointers into JSON schema documents.
/*!
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\param rootUri Root URI
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
\param allocator Allocator for Uris
\return Uri if it can be resolved. Otherwise null.
\note
There are only 3 situations when a URI cannot be resolved:
1. A value in the path is not an array nor object.
2. An object value does not contain the token.
3. A token is out of range of an array value.
Use unresolvedTokenIndex to retrieve the token index.
*/
UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
static const Ch kIdString[] = { 'i', 'd', '\0' };
static const ValueType kIdValue(kIdString, 2);
UriType base = UriType(rootUri, allocator);
RAPIDJSON_ASSERT(IsValid());
ValueType* v = &root;
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
switch (v->GetType()) {
case kObjectType:
{
// See if we have an id, and if so resolve with the current base
typename ValueType::MemberIterator m = v->FindMember(kIdValue);
if (m != v->MemberEnd() && (m->value).IsString()) {
UriType here = UriType(m->value, allocator).Resolve(base, allocator);
base = here;
}
m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd())
break;
v = &m->value;
}
continue;
case kArrayType:
if (t->index == kPointerInvalidIndex || t->index >= v->Size())
break;
v = &((*v)[t->index]);
continue;
default:
break;
}
// Error: unresolved token
if (unresolvedTokenIndex)
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
return UriType(allocator);
}
return base;
}
UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
}
//!@name Query value
//@{
@ -543,7 +611,7 @@ public:
switch (v->GetType()) {
case kObjectType:
{
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd())
break;
v = &m->value;
@ -779,7 +847,7 @@ public:
switch (v->GetType()) {
case kObjectType:
{
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd())
return false;
v = &m->value;

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -60,7 +60,7 @@ public:
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
PrettyWriter(PrettyWriter&& rhs) :
@ -164,7 +164,7 @@ public:
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
typename Base::Level* level = Base::level_stack_.template Pop<typename Base::Level>(1);
auto level = Base::level_stack_.template Pop<typename Base::Level>(1);
bool empty = level->valueCount == 0;
if (!empty && !level->inLine) {

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -124,6 +124,19 @@
#define RAPIDJSON_NAMESPACE_END }
#endif
///////////////////////////////////////////////////////////////////////////////
// __cplusplus macro
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER)
#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
#else
#define RAPIDJSON_CPLUSPLUS __cplusplus
#endif
//!@endcond
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_HAS_STDSTRING
@ -149,6 +162,24 @@
#include <string>
#endif // RAPIDJSON_HAS_STDSTRING
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_USE_MEMBERSMAP
/*! \def RAPIDJSON_USE_MEMBERSMAP
\ingroup RAPIDJSON_CONFIG
\brief Enable RapidJSON support for object members handling in a \c std::multimap
By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object
members are stored in a \c std::multimap for faster lookup and deletion times, a
trade off with a slightly slower insertion time and a small object allocat(or)ed
memory overhead.
\hideinitializer
*/
#ifndef RAPIDJSON_USE_MEMBERSMAP
#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE
@ -403,7 +434,7 @@ RAPIDJSON_NAMESPACE_END
*/
#ifndef RAPIDJSON_ASSERT
#include <cassert>
#define RAPIDJSON_ASSERT(x)
#define RAPIDJSON_ASSERT(x) assert(x)
#endif // RAPIDJSON_ASSERT
///////////////////////////////////////////////////////////////////////////////
@ -411,7 +442,7 @@ RAPIDJSON_NAMESPACE_END
// Prefer C++11 static_assert, if available
#ifndef RAPIDJSON_STATIC_ASSERT
#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
#define RAPIDJSON_STATIC_ASSERT(x) \
static_assert(x, RAPIDJSON_STRINGIFY(x))
#endif // C++11
@ -490,6 +521,12 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z))
#if defined(__has_builtin)
#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x)
#else
#define RAPIDJSON_HAS_BUILTIN(x) 0
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
@ -535,8 +572,14 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// C++11 features
#ifndef RAPIDJSON_HAS_CXX11
#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
#endif
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__)
#if RAPIDJSON_HAS_CXX11
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#elif defined(__clang__)
#if __has_feature(cxx_rvalue_references) && \
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
@ -553,8 +596,14 @@ RAPIDJSON_NAMESPACE_END
#endif
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#endif
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
#if defined(__clang__)
#if RAPIDJSON_HAS_CXX11
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#elif defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
@ -564,11 +613,13 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#endif
#endif
#ifndef RAPIDJSON_NOEXCEPT
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT noexcept
#else
#define RAPIDJSON_NOEXCEPT /* noexcept */
#define RAPIDJSON_NOEXCEPT throw()
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
#endif
// no automatic detection, yet
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
@ -591,6 +642,27 @@ RAPIDJSON_NAMESPACE_END
#endif
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
///////////////////////////////////////////////////////////////////////////////
// C++17 features
#ifndef RAPIDJSON_HAS_CXX17
#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
#endif
#if RAPIDJSON_HAS_CXX17
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
#elif defined(__has_cpp_attribute)
# if __has_cpp_attribute(clang::fallthrough)
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
# elif __has_cpp_attribute(fallthrough)
# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
# else
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
# endif
#else
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
#endif
//!@endcond
//! Assertion (in non-throwing contexts).
@ -609,16 +681,29 @@ RAPIDJSON_NAMESPACE_END
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
#ifdef RAPIDJSON_ASSERT_THROWS
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
#else
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
#include <cassert>
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
#else
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
#endif // RAPIDJSON_ASSERT_THROWS
#endif // RAPIDJSON_NOEXCEPT_ASSERT
///////////////////////////////////////////////////////////////////////////////
// malloc/realloc/free
#ifndef RAPIDJSON_MALLOC
///! customization point for global \c malloc
#define RAPIDJSON_MALLOC(size) std::malloc(size)
#endif
#ifndef RAPIDJSON_REALLOC
///! customization point for global \c realloc
#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
#endif
#ifndef RAPIDJSON_FREE
///! customization point for global \c free
#define RAPIDJSON_FREE(ptr) std::free(ptr)
#endif
///////////////////////////////////////////////////////////////////////////////
// new/delete

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -20,6 +20,7 @@
#include "allocators.h"
#include "stream.h"
#include "encodedstream.h"
#include "internal/clzll.h"
#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strtod.h"
@ -153,6 +154,7 @@ enum ParseFlag {
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
};
@ -443,16 +445,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
x = vmvnq_u8(x); // Negate
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
if (low == 0) {
if (high != 0) {
int lz =__builtin_clzll(high);;
uint32_t lz = internal::clzll(high);
return p + 8 + (lz >> 3);
}
} else {
int lz = __builtin_clzll(low);;
uint32_t lz = internal::clzll(low);
return p + (lz >> 3);
}
}
@ -479,16 +481,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
x = vmvnq_u8(x); // Negate
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
if (low == 0) {
if (high != 0) {
int lz = __builtin_clzll(high);
uint32_t lz = internal::clzll(high);
return p + 8 + (lz >> 3);
}
} else {
int lz = __builtin_clzll(low);
uint32_t lz = internal::clzll(low);
return p + (lz >> 3);
}
}
@ -990,7 +992,7 @@ private:
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = {
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -1013,19 +1015,31 @@ private:
is.Take();
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
}
else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
is.Take();
os.Put('\'');
}
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
is.Take();
unsigned codepoint = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
// Handle UTF-16 surrogate pair
if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
// high surrogate, check if followed by valid low surrogate
if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
// Handle UTF-16 surrogate pair
if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
unsigned codepoint2 = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
}
// single low surrogate
else
{
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
unsigned codepoint2 = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
}
}
TEncoding::Encode(os, codepoint);
}
@ -1244,19 +1258,19 @@ private:
x = vorrq_u8(x, vcltq_u8(s, s3));
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
SizeType length = 0;
bool escaped = false;
if (low == 0) {
if (high != 0) {
unsigned lz = (unsigned)__builtin_clzll(high);;
uint32_t lz = internal::clzll(high);
length = 8 + (lz >> 3);
escaped = true;
}
} else {
unsigned lz = (unsigned)__builtin_clzll(low);;
uint32_t lz = internal::clzll(low);
length = lz >> 3;
escaped = true;
}
@ -1314,19 +1328,19 @@ private:
x = vorrq_u8(x, vcltq_u8(s, s3));
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
SizeType length = 0;
bool escaped = false;
if (low == 0) {
if (high != 0) {
unsigned lz = (unsigned)__builtin_clzll(high);
uint32_t lz = internal::clzll(high);
length = 8 + (lz >> 3);
escaped = true;
}
} else {
unsigned lz = (unsigned)__builtin_clzll(low);
uint32_t lz = internal::clzll(low);
length = lz >> 3;
escaped = true;
}
@ -1370,17 +1384,17 @@ private:
x = vorrq_u8(x, vcltq_u8(s, s3));
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
if (low == 0) {
if (high != 0) {
int lz = __builtin_clzll(high);
uint32_t lz = internal::clzll(high);
p += 8 + (lz >> 3);
break;
}
} else {
int lz = __builtin_clzll(low);
uint32_t lz = internal::clzll(low);
p += lz >> 3;
break;
}
@ -1390,11 +1404,11 @@ private:
}
#endif // RAPIDJSON_NEON
template<typename InputStream, bool backup, bool pushOnTake>
template<typename InputStream, typename StackCharacter, bool backup, bool pushOnTake>
class NumberStream;
template<typename InputStream>
class NumberStream<InputStream, false, false> {
template<typename InputStream, typename StackCharacter>
class NumberStream<InputStream, StackCharacter, false, false> {
public:
typedef typename InputStream::Ch Ch;
@ -1403,11 +1417,11 @@ private:
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
RAPIDJSON_FORCEINLINE void Push(char) {}
RAPIDJSON_FORCEINLINE void Push(char) {}
size_t Tell() { return is.Tell(); }
size_t Length() { return 0; }
const char* Pop() { return 0; }
const StackCharacter* Pop() { return 0; }
protected:
NumberStream& operator=(const NumberStream&);
@ -1415,35 +1429,35 @@ private:
InputStream& is;
};
template<typename InputStream>
class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
typedef NumberStream<InputStream, false, false> Base;
template<typename InputStream, typename StackCharacter>
class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> {
typedef NumberStream<InputStream, StackCharacter, false, false> Base;
public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
RAPIDJSON_FORCEINLINE Ch TakePush() {
stackStream.Put(static_cast<char>(Base::is.Peek()));
stackStream.Put(static_cast<StackCharacter>(Base::is.Peek()));
return Base::is.Take();
}
RAPIDJSON_FORCEINLINE void Push(char c) {
RAPIDJSON_FORCEINLINE void Push(StackCharacter c) {
stackStream.Put(c);
}
size_t Length() { return stackStream.Length(); }
const char* Pop() {
const StackCharacter* Pop() {
stackStream.Put('\0');
return stackStream.Pop();
}
private:
StackStream<char> stackStream;
StackStream<StackCharacter> stackStream;
};
template<typename InputStream>
class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
typedef NumberStream<InputStream, true, false> Base;
template<typename InputStream, typename StackCharacter>
class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> {
typedef NumberStream<InputStream, StackCharacter, true, false> Base;
public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
@ -1452,8 +1466,10 @@ private:
template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) {
typedef typename internal::SelectIf<internal::BoolType<(parseFlags & kParseNumbersAsStringsFlag) != 0>, typename TargetEncoding::Ch, char>::Type NumberCharacter;
internal::StreamLocalCopy<InputStream> copy(is);
NumberStream<InputStream,
NumberStream<InputStream, NumberCharacter,
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
((parseFlags & kParseInsituFlag) == 0) :
((parseFlags & kParseFullPrecisionFlag) != 0),
@ -1678,10 +1694,10 @@ private:
}
else {
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
StringStream srcStream(s.Pop());
GenericStringStream<UTF8<NumberCharacter>> srcStream(s.Pop());
StackStream<typename TargetEncoding::Ch> dstStream(stack_);
while (numCharsToCopy--) {
Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);
}
dstStream.Put('\0');
const typename TargetEncoding::Ch* str = dstStream.Pop();
@ -1691,7 +1707,7 @@ private:
}
else {
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) {
int p = exp + expFrac;

210
src/3rdparty/rapidjson/readme.md vendored Normal file
View file

@ -0,0 +1,210 @@
![RapidJSON logo](doc/logo/rapidjson.png)
![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg)
## A fast JSON parser/generator for C++ with both SAX/DOM style API
Tencent is pleased to support the open source community by making RapidJSON available.
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
* RapidJSON Documentation
* [English](http://rapidjson.org/)
* [简体中文](http://rapidjson.org/zh-cn/)
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
## Build status
| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] |
| :---------------: | :-----------------: | :-------------------: |
| ![lin-badge] | ![win-badge] | ![cov-badge] |
[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status"
[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status"
[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status"
[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status"
[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage"
[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage"
## Introduction
RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/).
* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL.
* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
More features can be read [here](doc/features.md).
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
* [Introducing JSON](http://json.org/)
* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
## Highlights in v1.1 (2016-8-25)
* Added [JSON Pointer](doc/pointer.md)
* Added [JSON Schema](doc/schema.md)
* Added [relaxed JSON syntax](doc/dom.md) (comment, trailing comma, NaN/Infinity)
* Iterating array/object with [C++11 Range-based for loop](doc/tutorial.md)
* Reduce memory overhead of each `Value` from 24 bytes to 16 bytes in x86-64 architecture.
For other changes please refer to [change log](CHANGELOG.md).
## Compatibility
RapidJSON is cross-platform. Some platform/compiler combinations which have been tested are shown as follows.
* Visual C++ 2008/2010/2013 on Windows (32/64-bit)
* GNU C++ 3.8.x on Cygwin
* Clang 3.4 on Mac OS X (32/64-bit) and iOS
* Clang 3.4 on Android NDK
Users can build and run the unit tests on their platform/compiler.
## Installation
RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install rapidjson with CMake integration in a single command:
* vcpkg install rapidjson
RapidJSON uses following software as its dependencies:
* [CMake](https://cmake.org/) as a general build tool
* (optional) [Doxygen](http://www.doxygen.org) to build documentation
* (optional) [googletest](https://github.com/google/googletest) for unit and performance testing
To generate user documentation and run tests please proceed with the steps below:
1. Execute `git submodule update --init` to get the files of thirdparty submodules (google test).
2. Create directory called `build` in rapidjson source directory.
3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application.
4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory.
On successful build you will find compiled test and example binaries in `bin`
directory. The generated documentation will be available in `doc/html`
directory of the build tree. To run tests after finished build please run `make
test` or `ctest` from your build tree. You can get detailed output using `ctest
-V` command.
It is possible to install library system-wide by running `make install` command
from the build tree with administrative privileges. This will install all files
according to system preferences. Once RapidJSON is installed, it is possible
to use it from other CMake projects by adding `find_package(RapidJSON)` line to
your CMakeLists.txt.
## Usage at a glance
This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string.
~~~~~~~~~~cpp
// rapidjson/example/simpledom/simpledom.cpp`
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>
using namespace rapidjson;
int main() {
// 1. Parse a JSON string into DOM.
const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
Document d;
d.Parse(json);
// 2. Modify it by DOM.
Value& s = d["stars"];
s.SetInt(s.GetInt() + 1);
// 3. Stringify the DOM
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
d.Accept(writer);
// Output {"project":"rapidjson","stars":11}
std::cout << buffer.GetString() << std::endl;
return 0;
}
~~~~~~~~~~
Note that this example did not handle potential errors.
The following diagram shows the process.
![simpledom](doc/diagram/simpledom.png)
More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available:
* DOM API
* [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API.
* SAX API
* [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`.
* [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed.
* [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`.
* [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON.
* [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API.
* [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API.
* [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format.
* Schema
* [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema.
* Advanced
* [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings.
* [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
* [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
* [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
## Contributing
RapidJSON welcomes contributions. When contributing, please follow the code below.
### Issues
Feel free to submit issues and enhancement requests.
Please help us by providing **minimal reproducible examples**, because source code is easier to let other people understand what happens.
For crash problems on certain platforms, please bring stack dump content with the detail of the OS, compiler, etc.
Please try breakpoint debugging first, tell us what you found, see if we can start exploring based on more information been prepared.
### Workflow
In general, we follow the "fork-and-pull" Git workflow.
1. **Fork** the repo on GitHub
2. **Clone** the project to your own machine
3. **Checkout** a new branch on your fork, start developing on the branch
4. **Test** the change before commit, Make sure the changes pass all the tests, including `unittest` and `preftest`, please add test case for each new feature or bug-fix if needed.
5. **Commit** changes to your own branch
6. **Push** your work back up to your fork
7. Submit a **Pull request** so that we can review your changes
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
### Copyright and Licensing
You can copy and paste the license summary from below.
```
Tencent is pleased to support the open source community by making RapidJSON available.
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
Licensed under the MIT License (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
```

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at

466
src/3rdparty/rapidjson/uri.h vendored Normal file
View file

@ -0,0 +1,466 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// (C) Copyright IBM Corporation 2021
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_URI_H_
#define RAPIDJSON_URI_H_
#include "internal/strfunc.h"
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// GenericUri
template <typename ValueType, typename Allocator=CrtAllocator>
class GenericUri {
public:
typedef typename ValueType::Ch Ch;
#if RAPIDJSON_HAS_STDSTRING
typedef std::basic_string<Ch> String;
#endif
//! Constructors
GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
}
GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
Parse(uri, len);
}
GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
Parse(uri, internal::StrLen<Ch>(uri));
}
// Use with specializations of GenericValue
template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
const Ch* u = uri.template Get<const Ch*>(); // TypeHelper from document.h
Parse(u, internal::StrLen<Ch>(u));
}
#if RAPIDJSON_HAS_STDSTRING
GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
Parse(uri.c_str(), internal::StrLen<Ch>(uri.c_str()));
}
#endif
//! Copy constructor
GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() {
*this = rhs;
}
//! Copy constructor
GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
*this = rhs;
}
//! Destructor.
~GenericUri() {
Free();
RAPIDJSON_DELETE(ownAllocator_);
}
//! Assignment operator
GenericUri& operator=(const GenericUri& rhs) {
if (this != &rhs) {
// Do not delete ownAllocator
Free();
Allocate(rhs.GetStringLength());
auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength());
path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength());
query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength());
frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength());
base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength());
uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength());
CopyPart(uri_, rhs.uri_, rhs.GetStringLength());
}
return *this;
}
//! Getters
// Use with specializations of GenericValue
template<typename T> void Get(T& uri, Allocator& allocator) {
uri.template Set<const Ch*>(this->GetString(), allocator); // TypeHelper from document.h
}
const Ch* GetString() const { return uri_; }
SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
const Ch* GetBaseString() const { return base_; }
SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
const Ch* GetSchemeString() const { return scheme_; }
SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
const Ch* GetAuthString() const { return auth_; }
SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
const Ch* GetPathString() const { return path_; }
SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
const Ch* GetQueryString() const { return query_; }
SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
const Ch* GetFragString() const { return frag_; }
SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(frag_); }
#if RAPIDJSON_HAS_STDSTRING
static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); }
static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); }
static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); }
static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); }
static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); }
static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); }
static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); }
#endif
//! Equality operators
bool operator==(const GenericUri& rhs) const {
return Match(rhs, true);
}
bool operator!=(const GenericUri& rhs) const {
return !Match(rhs, true);
}
bool Match(const GenericUri& uri, bool full = true) const {
Ch* s1;
Ch* s2;
if (full) {
s1 = uri_;
s2 = uri.uri_;
} else {
s1 = base_;
s2 = uri.base_;
}
if (s1 == s2) return true;
if (s1 == 0 || s2 == 0) return false;
return internal::StrCmp<Ch>(s1, s2) == 0;
}
//! Resolve this URI against another (base) URI in accordance with URI resolution rules.
// See https://tools.ietf.org/html/rfc3986
// Use for resolving an id or $ref with an in-scope id.
// Returns a new GenericUri for the resolved URI.
GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) {
GenericUri resuri;
resuri.allocator_ = allocator;
// Ensure enough space for combining paths
resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash
if (!(GetSchemeStringLength() == 0)) {
// Use all of this URI
resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength());
resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
resuri.RemoveDotSegments();
} else {
// Use the base scheme
resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength());
if (!(GetAuthStringLength() == 0)) {
// Use this auth, path, query
resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
resuri.RemoveDotSegments();
} else {
// Use the base auth
resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength());
if (GetPathStringLength() == 0) {
// Use the base path
resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength());
if (GetQueryStringLength() == 0) {
// Use the base query
resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength());
} else {
// Use this query
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
}
} else {
if (path_[0] == '/') {
// Absolute path - use all of this path
resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
resuri.RemoveDotSegments();
} else {
// Relative path - append this path to base path after base path's last slash
size_t pos = 0;
if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) {
resuri.path_[pos] = '/';
pos++;
}
size_t lastslashpos = baseuri.GetPathStringLength();
while (lastslashpos > 0) {
if (baseuri.path_[lastslashpos - 1] == '/') break;
lastslashpos--;
}
std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch));
pos += lastslashpos;
resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength());
resuri.RemoveDotSegments();
}
// Use this query
resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
}
}
}
// Always use this frag
resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength());
// Re-constitute base_ and uri_
resuri.SetBase();
resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1;
resuri.SetUri();
return resuri;
}
//! Get the allocator of this GenericUri.
Allocator& GetAllocator() { return *allocator_; }
private:
// Allocate memory for a URI
// Returns total amount allocated
std::size_t Allocate(std::size_t len) {
// Create own allocator if user did not supply.
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
// Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated.
// Order: scheme, auth, path, query, frag, base, uri
size_t total = (3 * len + 7) * sizeof(Ch);
scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
*scheme_ = '\0';
auth_ = scheme_ + 1;
*auth_ = '\0';
path_ = auth_ + 1;
*path_ = '\0';
query_ = path_ + 1;
*query_ = '\0';
frag_ = query_ + 1;
*frag_ = '\0';
base_ = frag_ + 1;
*base_ = '\0';
uri_ = base_ + 1;
*uri_ = '\0';
return total;
}
// Free memory for a URI
void Free() {
if (scheme_) {
Allocator::Free(scheme_);
scheme_ = 0;
}
}
// Parse a URI into constituent scheme, authority, path, query, & fragment parts
// Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per
// https://tools.ietf.org/html/rfc3986
void Parse(const Ch* uri, std::size_t len) {
std::size_t start = 0, pos1 = 0, pos2 = 0;
Allocate(len);
// Look for scheme ([^:/?#]+):)?
if (start < len) {
while (pos1 < len) {
if (uri[pos1] == ':') break;
pos1++;
}
if (pos1 != len) {
while (pos2 < len) {
if (uri[pos2] == '/') break;
if (uri[pos2] == '?') break;
if (uri[pos2] == '#') break;
pos2++;
}
if (pos1 < pos2) {
pos1++;
std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
scheme_[pos1] = '\0';
start = pos1;
}
}
}
// Look for auth (//([^/?#]*))?
auth_ = scheme_ + GetSchemeStringLength() + 1;
*auth_ = '\0';
if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
pos2 = start + 2;
while (pos2 < len) {
if (uri[pos2] == '/') break;
if (uri[pos2] == '?') break;
if (uri[pos2] == '#') break;
pos2++;
}
std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
auth_[pos2 - start] = '\0';
start = pos2;
}
// Look for path ([^?#]*)
path_ = auth_ + GetAuthStringLength() + 1;
*path_ = '\0';
if (start < len) {
pos2 = start;
while (pos2 < len) {
if (uri[pos2] == '?') break;
if (uri[pos2] == '#') break;
pos2++;
}
if (start != pos2) {
std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
path_[pos2 - start] = '\0';
if (path_[0] == '/')
RemoveDotSegments(); // absolute path - normalize
start = pos2;
}
}
// Look for query (\?([^#]*))?
query_ = path_ + GetPathStringLength() + 1;
*query_ = '\0';
if (start < len && uri[start] == '?') {
pos2 = start + 1;
while (pos2 < len) {
if (uri[pos2] == '#') break;
pos2++;
}
if (start != pos2) {
std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
query_[pos2 - start] = '\0';
start = pos2;
}
}
// Look for fragment (#(.*))?
frag_ = query_ + GetQueryStringLength() + 1;
*frag_ = '\0';
if (start < len && uri[start] == '#') {
std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
frag_[len - start] = '\0';
}
// Re-constitute base_ and uri_
base_ = frag_ + GetFragStringLength() + 1;
SetBase();
uri_ = base_ + GetBaseStringLength() + 1;
SetUri();
}
// Reconstitute base
void SetBase() {
Ch* next = base_;
std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
next+= GetSchemeStringLength();
std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
next+= GetAuthStringLength();
std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
next+= GetPathStringLength();
std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
next+= GetQueryStringLength();
*next = '\0';
}
// Reconstitute uri
void SetUri() {
Ch* next = uri_;
std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
next+= GetBaseStringLength();
std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
next+= GetFragStringLength();
*next = '\0';
}
// Copy a part from one GenericUri to another
// Return the pointer to the next part to be copied to
Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
RAPIDJSON_ASSERT(to != 0);
RAPIDJSON_ASSERT(from != 0);
std::memcpy(to, from, len * sizeof(Ch));
to[len] = '\0';
Ch* next = to + len + 1;
return next;
}
// Remove . and .. segments from the path_ member.
// https://tools.ietf.org/html/rfc3986
// This is done in place as we are only removing segments.
void RemoveDotSegments() {
std::size_t pathlen = GetPathStringLength();
std::size_t pathpos = 0; // Position in path_
std::size_t newpos = 0; // Position in new path_
// Loop through each segment in original path_
while (pathpos < pathlen) {
// Get next segment, bounded by '/' or end
size_t slashpos = 0;
while ((pathpos + slashpos) < pathlen) {
if (path_[pathpos + slashpos] == '/') break;
slashpos++;
}
// Check for .. and . segments
if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
// Backup a .. segment in the new path_
// We expect to find a previously added slash at the end or nothing
RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
size_t lastslashpos = newpos;
// Make sure we don't go beyond the start segment
if (lastslashpos > 1) {
// Find the next to last slash and back up to it
lastslashpos--;
while (lastslashpos > 0) {
if (path_[lastslashpos - 1] == '/') break;
lastslashpos--;
}
// Set the new path_ position
newpos = lastslashpos;
}
} else if (slashpos == 1 && path_[pathpos] == '.') {
// Discard . segment, leaves new path_ unchanged
} else {
// Move any other kind of segment to the new path_
RAPIDJSON_ASSERT(newpos <= pathpos);
std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
newpos += slashpos;
// Add slash if not at end
if ((pathpos + slashpos) < pathlen) {
path_[newpos] = '/';
newpos++;
}
}
// Move to next segment
pathpos += slashpos + 1;
}
path_[newpos] = '\0';
}
Ch* uri_; // Everything
Ch* base_; // Everything except fragment
Ch* scheme_; // Includes the :
Ch* auth_; // Includes the //
Ch* path_; // Absolute if starts with /
Ch* query_; // Includes the ?
Ch* frag_; // Includes the #
Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
Allocator* ownAllocator_; //!< Allocator owned by this Uri.
};
//! GenericUri for Value (UTF-8, default allocator).
typedef GenericUri<Value> Uri;
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_URI_H_

View file

@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@ -16,6 +16,7 @@
#define RAPIDJSON_WRITER_H_
#include "stream.h"
#include "internal/clzll.h"
#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
@ -226,7 +227,7 @@ public:
return Key(str.data(), SizeType(str.size()));
}
#endif
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
@ -282,6 +283,8 @@ public:
os_->Flush();
}
static const size_t kDefaultLevelDepth = 32;
protected:
//! Information for each nested level
struct Level {
@ -291,8 +294,6 @@ protected:
bool inLine = false;
};
static const size_t kDefaultLevelDepth = 32;
bool WriteNull() {
PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
@ -669,19 +670,19 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
x = vorrq_u8(x, vcltq_u8(s, s3));
x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
SizeType len = 0;
bool escaped = false;
if (low == 0) {
if (high != 0) {
unsigned lz = (unsigned)__builtin_clzll(high);
uint32_t lz = internal::clzll(high);
len = 8 + (lz >> 3);
escaped = true;
}
} else {
unsigned lz = (unsigned)__builtin_clzll(low);
uint32_t lz = internal::clzll(low);
len = lz >> 3;
escaped = true;
}

View file

@ -1,12 +1,6 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "backend/common/Threads.h"
#include "3rdparty/rapidjson/document.h"
#include "backend/cpu/CpuThreads.h"
@ -43,7 +36,6 @@ namespace xmrig {
static const char *kAsterisk = "*";
static const char *kCn2 = "cn/2";
} // namespace xmrig
@ -112,7 +104,7 @@ xmrig::String xmrig::Threads<T>::profileName(const Algorithm &algorithm, bool st
return String();
}
const String name = algorithm.shortName();
String name = algorithm.name();
if (has(name)) {
return name;
}
@ -125,12 +117,12 @@ xmrig::String xmrig::Threads<T>::profileName(const Algorithm &algorithm, bool st
return String();
}
if (algorithm.family() == Algorithm::CN && CnAlgo<>::base(algorithm) == Algorithm::CN_2 && has(kCn2)) {
return kCn2;
if (algorithm.family() == Algorithm::CN && algorithm.base() == Algorithm::CN_2 && has(Algorithm::kCN_2)) {
return Algorithm::kCN_2;
}
if (name.contains("/")) {
const String base = name.split('/').at(0);
String base = name.split('/').at(0);
if (has(base)) {
return base;
}
@ -155,11 +147,11 @@ void xmrig::Threads<T>::toJSON(rapidjson::Value &out, rapidjson::Document &doc)
}
for (const Algorithm &algo : m_disabled) {
out.AddMember(StringRef(algo.shortName()), false, allocator);
out.AddMember(StringRef(algo.name()), false, allocator);
}
for (const auto &kv : m_aliases) {
out.AddMember(StringRef(kv.first.shortName()), kv.second.toJSON(), allocator);
out.AddMember(StringRef(kv.first.name()), kv.second.toJSON(), allocator);
}
}

View file

@ -1,12 +1,6 @@
/* XMRig
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
* Copyright 2017-2018 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef XMRIG_THREADS_H
#define XMRIG_THREADS_H
@ -45,7 +40,7 @@ public:
inline bool has(const char *profile) const { return m_profiles.count(profile) > 0; }
inline bool isDisabled(const Algorithm &algo) const { return m_disabled.count(algo) > 0; }
inline bool isEmpty() const { return m_profiles.empty(); }
inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.shortName()); }
inline bool isExist(const Algorithm &algo) const { return isDisabled(algo) || m_aliases.count(algo) > 0 || has(algo.name()); }
inline const T &get(const Algorithm &algo, bool strict = false) const { return get(profileName(algo, strict)); }
inline void disable(const Algorithm &algo) { m_disabled.insert(algo); }
inline void setAlias(const Algorithm &algo, const char *profile) { m_aliases[algo] = profile; }

View file

@ -85,9 +85,10 @@ public:
}
inline int32_t nonceOffset() const { return currentJob().nonceOffset(); }
inline size_t nonceSize() const { return currentJob().nonceSize(); }
private:
inline int32_t nonceOffset() const { return currentJob().nonceOffset(); }
inline size_t nonceSize() const { return currentJob().nonceSize(); }
inline uint64_t nonceMask() const { return m_nonce_mask[index()]; }
inline void save(const Job &job, uint32_t reserveCount, Nonce::Backend backend)

View file

@ -1,6 +1,6 @@
/* XMRig
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "backend/common/Workers.h"
#include "backend/common/Hashrate.h"
#include "backend/common/interfaces/IBackend.h"
@ -200,7 +199,7 @@ void *xmrig::Workers<T>::onReady(void *arg)
template<class T>
void xmrig::Workers<T>::start(const std::vector<T> &data, bool sleep)
void xmrig::Workers<T>::start(const std::vector<T> &data, bool /*sleep*/)
{
for (const auto &item : data) {
m_workers.push_back(new Thread<T>(d_ptr->backend, m_workers.size(), item));

Some files were not shown because too many files have changed in this diff Show more