Squashed 'third_party/allwpilib_2019/' changes from 99e4f7dd2..c36bbcc9a
936627bd9 wpilibc: Remove direct CameraServer dependency (#1989)
8e333c0aa Use FPGA Time instead of wall clock time for odometry (#1996)
d4430b765 Gearsbot example: Use standard argument order (#1995)
75438ab2c Add RamseteCommand (#1951)
989df1b46 Bump Native Utils and OpenCV dependencies (#1993)
dbc33b61e Fix Timer usage in TrapezoidProfileCommand (#1992)
79f8c5644 Add TrapezoidProfileCommand (#1962)
9440edf2b Refactor TrajectoryGenerator (#1972)
73a30182c Add frc2::Timer (#1968)
36ea865ed Add toString for geometry and trajectory classes (#1991)
cbe05e7e8 Update ProfiledPIDController API (#1967)
d04eb3546 Deprecate old PID classes (#1964)
02264db69 Add JNI dependencies to myRobotCpp (#1980)
2a76c996e Use VID/PID detection for PS3Eye (#1977)
a3820bbdf Remove HAL_BaseInitialize (#1981)
a83fb4793 Update to 2020v5 image (#1983)
4b0ed910e Make SwerveDriveKinematics.toChassisSpeeds() public (#1976)
103c1b121 Remove DS caching from the HAL level (#1971)
6635ea75e Fix NPE in SendableRegistry.foreachLiveWindow() (#1974)
cfe23c5cd Fix grammar error in comment for configureButtonBindings (#1969)
4bde2654e Fix mac azure build (#1973)
4f034e6c1 generateTrajectory: default reversed param to false (#1953)
acf960f72 Sim GUI: Add option to disable outputs on DS disable
2d3dac99f Sim GUI: Handle low resolutions and scale default window positions
07c86e0cd Sim GUI: Support High DPI monitors
46ad95512 SimDeviceData: Add missing null check
5bce489b9 Add ProggyDotted font to imgui (both cmake and gradle)
55af553ac Simulation GUI: Map gamepad the same way as DS
c59f9cea5 CameraServer: Add VID/PID support for Linux USB devices (#1960)
3fc89c84d Make splinePointsFromSplines public (#1963)
2c5093797 Fix implicitly deleted move constructors (#1954)
f3ad927f4 Update Java SmartDashboard and LiveWindow to match C++
05c25deb7 Fix move handling of C++ Sendable in SmartDashboard and LiveWindow
d726591ce Fix Gazebo sim plugin build (#1959)
2ff694fa4 Unbreak gradle build when other compilers installed (#1958)
53816155b Improve command decorator names (#1945)
a38f183a9 Fix GenResources.cmake so it's usable in a submodule (#1956)
b3398dca3 Set gradlebase correctly for all examples (#1950)
2c311013d Add Aarch64Bionic platform detection (#1922)
c10f2003c Add generateTrajectory overload (#1944)
63cfa64fb Add getters for pose in odometry classes (#1943)
2402c2bad Fix C++ command group recursive constructor bug (#1941)
f4eedf597 Fix ConcurrentModificationException in CommandScheduler (#1938)
bb0b207d2 Fix array out of bounds exception caused by parallel race group (#1935)
7bd69e591 Fix typo in temperature (#1940)
ec9738245 Bump to 2020 v4 image (#1931)
46303a822 Add messaging to extension loading in the HAL (#1926)
d169d6be9 Set extract_static for Doxygen config so that static members show up (#1930)
4e183eb10 Bump to 2020 v3 image (#1929)
84c185803 LiveWindow: catch errors in callback/builder functions (#1921)
0e3b0f3da Remove deprecated free() calls (#1925)
7f839b87c Remove timeouts from azure builds (#1924)
45b766a5d Fix main thread ID being potentially incorrect for simulation (#1923)
56d782b16 Add secondary camera name for PS3Eye (#1920)
2b4894038 Add simulation GUI plugin
f97d16073 Add imgui build to cmake
55a844a3e HAL sim: Add encoder channel B access
10deba854 Remove sendables from SendableRegistry when close() is called (#1917)
a9f0e4668 Implement sim devices for ADXL345, ADXL362, ADXRS450, Ultrasonic
aa9064586 Add ability to associate other devices with a SimDevice
81c2c8a7d Add simulation generic device/value support
e8d6f8a2c Move mockdata/HAL_Value.h to hal/Value.h
1b266717a Add simulation module support to cmake build (#1906)
fb8f3bd06 Add testbench yaml file (#1915)
846d8def0 Update to 2020 v2 image (#1913)
d6ac6e512 Fix PortForwarder package declaration (#1912)
227157086 Fix PS3Eye exposure setting (#1911)
885744d7e Add myRobot C++ version to cmake build (#1907)
366091fa8 Document that ConditionalCommand requires all subsystems (#1909)
c58b072c8 Fix Drive usage reporting order (#1908)
762c88adb Update compiler versions in readme (#1905)
af8ce568d Add Ramsete unicycle controller (#1790)
b2c2934d0 Fix javadoc warnings about invalid usage of ">" (#1904)
cce26ec78 Replace CRLF line endings with LF (#1902)
cb54602d4 Add support for writing RTR CAN Frames to the CAN API (#1900)
9f740e590 Use OS for serial port instead of NI VISA (#1875)
b23baf611 Add ability to run robot main loop in a separate thread (#1895)
457f94ba2 Add trajectory generation using hermite splines (#1843)
fd612052f Update native utils to use new frchome directory (#1884)
8858ec55c Remove periodic can read call (#1868)
41efb8015 Update CANAPITypes.h (#1860)
c93be1b2d Remove LabVIEW HAL support (#1901)
680f8919e Remove eigen, units and libuv from doxygen generation (#1898)
c5812524f Bump GradleJNI plugin version (#1899)
971303da8 Add PortForwarder class (#1890)
50db77bf2 Fix wpiutil cmake eigen install source directory (#1891)
85d42c199 C++ PIDCommand: Add GetMeasurement() and UseOutput() (#1892)
2dfbb855d wpilibj: Fix SwerveDriveKinematics ctor parameter name (#1889)
471f375a3 Simplify Sendable interface (#1864)
1d8c4d016 Replace ::value and ::type with _v and _t suffixes (#1885)
a5650b943 Add Units Utility class for Java (#1829)
904479ad4 Deprecate GearTooth class for removal (#1878)
86b666bba Add equality comparator to geometry classes (#1882)
62f07c182 Make one-arg Rotation2d constructor implicit (#1883)
f405582f8 Add kinematics suite (#1787)
561cbbd14 Deprecate Filter class for removal (#1876)
84e2973aa Remove unused include from Filesystem.h (#1877)
f49859ebf Remove NI VISA headers, as they are now included in NI Libraries (#1879)
bc59db5e6 Rename DEBUG macro to DEBUG0 (#1871)
dd928b4cb Remove JNI logging (#1872)
3e0f7d099 Use units for new NotifierCommand (#1869)
5ffe15d5f Remove ability to build all combined artifacts (#1867)
516cbef2c Remove RoboRIO ifdef from simulation headers (#1859)
9b6ffc201 Replace SetOutputRange() with SetIntegratorRange()
ff8b8f0a8 Remove percent tolerance from PID controller
0ca8d667d Clean up AutoCloseable and other Java warnings (#1866)
7112add67 Watchdog: use units::second_t instead of double (#1863)
761bc3ef8 Change C++ WaitCommand to use units (#1865)
1fb301123 Add MathUtils.clamp() for Java (#1861)
eb3e0c9c9 Fix cmake Eigen include directory (#1862)
2250b7fbe Rename GearsBotNew example to GearsBot
c9f9feff1 Replace deprecated API usage in C++ examples
d6b9c7e14 CONTRIBUTING.md: Point to frc-docs instead of screensteps (#1858)
d10a1a797 Fix eigen build in vcpkg (#1856)
2bdb44325 Add frc2 includes to list of "other lib" regexes (#1855)
4b2b21d24 Replace outdated Java collections (#508)
8993ce5bf Move Eigen headers out of main include folder (#1854)
0f532a117 Add PWMSparkMax (#1751)
f7ad363d8 Add jni cross compile options for aarch64 (#1853)
9afea3340 Add support for aarch64 jetson bionic builds (#1844)
d787b5d60 Add more items to .gitignore (#1850)
5dd0d1b7d Use units in SPI
07ac711b3 Fix units deprecated warning in IterativeRobot
decfd858b Correctly report -1 for POV on disconnected joystick (#1852)
076ed7770 Add new C++ Command framework (#1785)
a0be07c37 Refactor HAL handle move construction/assignment (#1845)
558c38308 Add new Java Command framework (#1682)
1379735af Delete RobotState and SensorUtil constructors (#1847)
e3d86fee4 Move circular buffer class from wpilib to wpiutil (#1840)
4cd8a5667 TimedRobot.cpp: Fix deprecation warning (#1846)
b2861f894 Use 2020 artifacts and artifactory server (#1838)
98cc32703 Update to use artifactory to publish artifacts (#1833)
fa0640300 Move drive integration tests into wpilibj/src/test (#1836)
e716c36b8 Fix Nat.java generation to be incremental (#1831)
9fd2b5e3f Fix MSVC builds on cmake windows in vcpkg (#1835)
7e95010a2 Add compile-time EJML matrix wrapper to wpiutil (#1804)
3ebc5a6d3 Add ProfiledPIDController
fc98a79db Clean up PIDController interface in preparation for ProfiledPIDController
fdc098267 Fix compilation error in elevator trapezoid profile example (#1826)
a3dd84e85 Make XBoxController Button enum public (#1823)
a216b9e9e Add TrapezoidProfile example (#1814)
8f386f6bb wpilibc: Add unit-safety to C++ geometry classes (#1811)
c07ac2353 wpilibc: Add overloads for units (#1815)
f1d71da8a Move GetStackTrace and Demangle to wpiutil, add Windows support (#1819)
ef037457e Make LinearFilter copyable and moveable (#1789)
76930250c Remove objective-cpp support (#1816)
1c246418f Move TrapezoidProfileTest to trajectory folder (#1812)
95a54a0f2 Add java arcade drive example (#1810)
a4530243e HAL sim: Fix incorrectly setting dio port to initialized on cleanup (#1813)
09d00a622 Update Java examples to use new PIDController (#1809)
ba9b51742 Add missing Java examples (#841)
6411bd79c InterruptableSensorBase: Fix callback function deletion (#1807)
810e58ea8 I2C: Add tip about writeBulk() to transaction() (#1806)
607d6c148 Fix wpilibj integration tests jar name (#1808)
c9873e81b Remove PIDControllerRunner and mutex from new PIDController (#1795)
98d0706de Fix cscore build with OpenCV 4 (#1803)
fbe67c90c Make Sendable setters synchronous (#1799)
c67a488a0 Format SendableBuilderImpl javadocs (#1802)
8e93ce892 Fix PIDControllerRunner member destruction order (#1801)
c98ca7310 Add EJML dependency to wpiutil (#1769)
3b12276bc SendableBase: remove unnecessary synchronization (#1797)
e6d348f38 Fix missing default name in Java PIDController (#1792)
df12fc2a8 Java cleanups (#1776)
39561751f Update GradleVSCode version (#1786)
37d316aa0 Add C++20 std::math constants shim (#1788)
dd4310959 Deprecate frc/WPILib.h (#1779)
823174f30 Update native utils to 2020.0.4 (#1783)
37c695266 Squelch -Wdeprecated-copy for Eigen with GCC >= 9
04c9b000f Revert "Fix build of Eigen 3.3.7 with GCC 9"
ca3e71e21 wpiutil: Fix Process::Spawn() (#1778)
d946d5a2b Fix Eigen compilation errors and add tests (#1777)
8b1b9ac75 Fix build of Eigen 3.3.7 with GCC 9
2f680ba99 Add Eigen linear algebra library
a885db7d4 Make MotorEncoderTest use LinearFilter (#1775)
ee2410169 Add geometry classes (#1766)
48fe54271 Add HALSIM_SetSendError implementation (#1773)
dff58c87f Fix unused warning in release build (#1771)
dde61aad3 Remove TimerEventHandler typedef from Notifier class (#1767)
0f6ef80ab Add RobotState#IsEStopped and DriverStation#IsEStopped (#952)
e48886187 Move unit tests from integration test suite (#1170)
dffa1a5cb Make null checks more descriptive (#1688)
fe59d854d Notifier: add null check (#1684)
10731f3d6 Update uv Udp wrapper for latest features
89f7b72b6 Update libuv to 1.30.1 release
85f2f8740 wpiutil: Add unique_function (#1761)
73ec94078 Remove SampleRobot (#1658)
62be0392b Replace std::lock_guard and std::lock with std::scoped_lock (#1758)
24d31df55 Make sure move constructor is generated for TrapezoidProfile (#1757)
841ef5d73 Remove template types from lock RAII wrapper usages (#1756)
e582518ba Fix some move constructors (#1754)
8757bc471 Remove pre-C++17 shims (#1752)
ea9512977 Add replacement PIDController class (#1300)
9b798d228 Add TrapezoidProfile class (#1673)
804926fb5 Unconditionally skip athena builds for sim (#1748)
118e9d29d Add C++14 units library (#1749)
c705953d7 Add usage reporting to LinearFilter (#1750)
852d1b9ca Don't cross-build gazebo for raspbian (#1747)
eedb3a1ad Fix GCC 9 warnings (#1730)
60dce66a4 Remove wpi::ArrayRef std::initializer_list constructor (#1745)
9e19b29c3 Use base azure image for primary wpilib build (#1744)
299425071 Update jni library, fix cross builds of the jni symbol check (#1742)
a6b0e9b85 Only disable execution of cross compile google tests (#1741)
3c2093119 Use docker container to run wpiformat (#1740)
5fe2eebce Revert "Don't build halsim_gazebo on raspbian (#1737)" (#1743)
4b1b92bb7 Replace wpi::optional with C++17 std::optional (#1732)
0fbb0d989 Update to 2020 compilers (#1733)
2dc94e605 Disable google tests on cross compilers (#1738)
d9cb57a42 Don't build halsim_gazebo on raspbian (#1737)
f7cfdd7ce Replace crlf line endings with lf (#1731)
b6d5d90d9 Add JaCoCo Support (#1734)
c7ab2baa6 Add way to disable the jni check tasks from a property (#1736)
0c45c5b7e Fix skip athena and skip raspbian flags (#1735)
3dfb01d45 Update to new Native Utils (#1696)
30e936837 Clean up LinearDigitalFilter class (#782)
311e2de4c Remove deprecated Joystick constants (#1715)
c08fd6682 Update CAN manufacturer list (#1706)
258bba0c2 ErrorBase and WPIError improvements (#1727)
372ca4f45 cmake: Enable googletest unit tests (#1720)
223d47af0 HALSIM: support mocking of HAL_SendError() (#1728)
55cb683db Change compiler flags to C++17 (#1723)
ee8a33c56 wpiutil: SafeThread: Add thread id, support getting shared_ptr (#1722)
61426d08d wpiutil: Signal: make operator() const (#1721)
b630b63ef Remove functions in LiveWindow deprecated since 2018 (#1716)
1d0c05d4f Styleguide fixes for #1718 (#1719)
f07569df1 Fix newer GCC/clang compiler warnings (#1718)
0120f3124 C++ SPI: Fix SetClockRate to take int (#1717)
c2829ed98 Configure gradle to ignore unresolved headers (#1711)
221e66f46 Allow disabling static init of JNI libraries (#1672)
738852e11 cmake: Add cross toolchain files for Rio and Pi (#1710)
27b697b08 Remove frc directory include shims (#1714)
9e45373a7 Remove functions and classes deprecated for 2018 season (#1059)
eeb1025ac SPI: Report port as instance for usage reporting (#1704)
bc6f1e246 Windows compiler options improvements (#1709)
bb48ae391 cmake: Move example programs into folders (#1654)
221011494 Update for C++17 and fix MSVC warnings (#1694)
fb1239a2a Add raw sources and sinks to cscore (#1670)
7de947734 Add lambda overloads for interrupts (#1636)
90957aeea Move libuv to its own subfolder in build (#1661)
47aae502a Styleguide fixes (#1702)
0bff98b5e Correct DifferentialDrive::ArcadeDrive param docs (#1698)
b52e40b80 Allow widgets to be added by passing value suppliers (#1690)
4a00cd77b Add usage reporting for the Shuffleboard API (#1685)
e25e515f2 Publish artifacts on azure (#1678)
322ef9b96 Force Java 11, fix javadoc generation (#1695)
d42ef5df0 Fix Watchdog print formatting (#1693)
f432f65be Update copyright year in license to 2019 (#1524)
1726b77ac wpiutil: uv: Remove copy from SimpleBufferPool (#1680)
620bec9ca wpiutil: uv: Add LoopClosing status to Handle (#1647)
7cd6e2e7f UsbCamera: Solve race in windows initialization (#1638)
7732836bd Completely disable watchdog tests on mac (#1679)
698edfda9 Remove framework load, disable mac timeout test (#1676)
1c454b000 Add Shuffleboard calls to IterativeRobotBase in C++ (#1607)
f42905b32 Include missing headers in HAL.h (#1660)
bdc822fad Only generate passthrough URLs for RoboRIO (#1624)
d3affb16b Make failure of HAL_GetFPGATime() more descriptive (#1633)
2de3bf7f5 Update LLVM from stable upstream (#1653)
3cf4f38f5 Fix build on macos10.14.4 (#1648)
4e0c10f48 Fix CAN Clean using wrong ID (#1668)
3b0631324 Fix Gray to BGR conversion in CameraServer (#1665)
6cd1c73ef Fix GUID comparison creating weird symbol (#1659)
063bbab6f MavenArtifacts.md: update links to HTTPS (#1674)
aab4c494d Fix type in build.gradle (#1604)
bf46af260 Disable extraneous data warnings in libjpeg (#1630)
655763a9a Limit length of message sent to DS SendError call (#1618)
a095ec2d8 Fix linker errors with free functions in Threads.h (#1625)
12ab035aa Fix receive side of LabVIEW USB streams (#1621)
Change-Id: Ibd382e1a48925c200850cf90a8121e35c0fcffe3
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: c36bbcc9a9095489fc078229db4fba3ecd0f9b78
diff --git a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp b/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
index b885385..1c54bdf 100644
--- a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
+++ b/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -49,7 +49,10 @@
void EventLoopRunner::Stop() {
ExecAsync([](uv::Loop& loop) {
// close all handles; this will (eventually) stop the loop
- loop.Walk([](uv::Handle& h) { h.Close(); });
+ loop.Walk([](uv::Handle& h) {
+ h.SetLoopClosing(true);
+ h.Close();
+ });
});
m_owner.Join();
}
diff --git a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp b/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
index 9e65691..0308e8c 100644
--- a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
+++ b/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -77,7 +77,7 @@
void HttpServerConnection::SendData(ArrayRef<uv::Buffer> bufs,
bool closeAfter) {
- m_stream.Write(bufs, [ closeAfter, stream = &m_stream ](
+ m_stream.Write(bufs, [closeAfter, stream = &m_stream](
MutableArrayRef<uv::Buffer> bufs, uv::Error) {
for (auto&& buf : bufs) buf.Deallocate();
if (closeAfter) stream->Close();
@@ -113,7 +113,7 @@
// can send content without copying
bufs.emplace_back(content);
- m_stream.Write(bufs, [ closeAfter = !m_keepAlive, stream = &m_stream ](
+ m_stream.Write(bufs, [closeAfter = !m_keepAlive, stream = &m_stream](
MutableArrayRef<uv::Buffer> bufs, uv::Error) {
// don't deallocate the static content
for (auto&& buf : bufs.drop_back()) buf.Deallocate();
diff --git a/wpiutil/src/main/native/cpp/PortForwarder.cpp b/wpiutil/src/main/native/cpp/PortForwarder.cpp
new file mode 100644
index 0000000..fe54b63
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/PortForwarder.cpp
@@ -0,0 +1,150 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#include "wpi/PortForwarder.h"
+
+#include "wpi/DenseMap.h"
+#include "wpi/EventLoopRunner.h"
+#include "wpi/SmallString.h"
+#include "wpi/raw_ostream.h"
+#include "wpi/uv/GetAddrInfo.h"
+#include "wpi/uv/Tcp.h"
+#include "wpi/uv/Timer.h"
+
+using namespace wpi;
+
+struct PortForwarder::Impl {
+ public:
+ EventLoopRunner runner;
+ DenseMap<unsigned int, std::weak_ptr<uv::Tcp>> servers;
+};
+
+PortForwarder::PortForwarder() : m_impl{new Impl} {}
+
+PortForwarder& PortForwarder::GetInstance() {
+ static PortForwarder instance;
+ return instance;
+}
+
+static void CopyStream(uv::Stream& in, std::weak_ptr<uv::Stream> outWeak) {
+ in.data.connect([&in, outWeak](uv::Buffer& buf, size_t len) {
+ uv::Buffer buf2 = buf.Dup();
+ buf2.len = len;
+ auto out = outWeak.lock();
+ if (!out) {
+ in.Close();
+ return;
+ }
+ out->Write(buf2, [](auto bufs, uv::Error) {
+ for (auto buf : bufs) buf.Deallocate();
+ });
+ });
+}
+
+void PortForwarder::Add(unsigned int port, const Twine& remoteHost,
+ unsigned int remotePort) {
+ m_impl->runner.ExecSync([&](uv::Loop& loop) {
+ auto server = uv::Tcp::Create(loop);
+
+ // bind to local port
+ server->Bind("", port);
+
+ // when we get a connection, accept it
+ server->connection.connect([serverPtr = server.get(),
+ host = remoteHost.str(), remotePort] {
+ auto& loop = serverPtr->GetLoopRef();
+ auto client = serverPtr->Accept();
+ if (!client) return;
+
+ // close on error
+ client->error.connect(
+ [clientPtr = client.get()](uv::Error err) { clientPtr->Close(); });
+
+ // connected flag
+ auto connected = std::make_shared<bool>(false);
+ client->SetData(connected);
+
+ auto remote = uv::Tcp::Create(loop);
+ remote->error.connect(
+ [remotePtr = remote.get(),
+ clientWeak = std::weak_ptr<uv::Tcp>(client)](uv::Error err) {
+ remotePtr->Close();
+ if (auto client = clientWeak.lock()) client->Close();
+ });
+
+ // convert port to string
+ SmallString<16> remotePortStr;
+ raw_svector_ostream(remotePortStr) << remotePort;
+
+ // resolve address
+ uv::GetAddrInfo(
+ loop,
+ [clientWeak = std::weak_ptr<uv::Tcp>(client),
+ remoteWeak = std::weak_ptr<uv::Tcp>(remote)](const addrinfo& addr) {
+ auto remote = remoteWeak.lock();
+ if (!remote) return;
+
+ // connect to remote address/port
+ remote->Connect(*addr.ai_addr, [remotePtr = remote.get(),
+ remoteWeak, clientWeak] {
+ auto client = clientWeak.lock();
+ if (!client) {
+ remotePtr->Close();
+ return;
+ }
+ *(client->GetData<bool>()) = true;
+
+ // close both when either side closes
+ client->end.connect([clientPtr = client.get(), remoteWeak] {
+ clientPtr->Close();
+ if (auto remote = remoteWeak.lock()) remote->Close();
+ });
+ remotePtr->end.connect([remotePtr, clientWeak] {
+ remotePtr->Close();
+ if (auto client = clientWeak.lock()) client->Close();
+ });
+
+ // copy bidirectionally
+ client->StartRead();
+ remotePtr->StartRead();
+ CopyStream(*client, remoteWeak);
+ CopyStream(*remotePtr, clientWeak);
+ });
+ },
+ host, remotePortStr);
+
+ // time out for connection
+ uv::Timer::SingleShot(loop, uv::Timer::Time{500},
+ [connectedWeak = std::weak_ptr<bool>(connected),
+ clientWeak = std::weak_ptr<uv::Tcp>(client),
+ remoteWeak = std::weak_ptr<uv::Tcp>(remote)] {
+ if (auto connected = connectedWeak.lock()) {
+ if (!*connected) {
+ if (auto client = clientWeak.lock())
+ client->Close();
+ if (auto remote = remoteWeak.lock())
+ remote->Close();
+ }
+ }
+ });
+ });
+
+ // start listening for incoming connections
+ server->Listen();
+
+ m_impl->servers[port] = server;
+ });
+}
+
+void PortForwarder::Remove(unsigned int port) {
+ m_impl->runner.ExecSync([&](uv::Loop& loop) {
+ if (auto server = m_impl->servers.lookup(port).lock()) {
+ server->Close();
+ m_impl->servers.erase(port);
+ }
+ });
+}
diff --git a/wpiutil/src/main/native/cpp/SafeThread.cpp b/wpiutil/src/main/native/cpp/SafeThread.cpp
index 52ac700..3a906bd 100644
--- a/wpiutil/src/main/native/cpp/SafeThread.cpp
+++ b/wpiutil/src/main/native/cpp/SafeThread.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -29,14 +29,15 @@
}
void detail::SafeThreadOwnerBase::Start(std::shared_ptr<SafeThread> thr) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (auto thr = m_thread.lock()) return;
m_stdThread = std::thread([=] { thr->Main(); });
+ thr->m_threadId = m_stdThread.get_id();
m_thread = thr;
}
void detail::SafeThreadOwnerBase::Stop() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (auto thr = m_thread.lock()) {
thr->m_active = false;
thr->m_cond.notify_all();
@@ -46,7 +47,7 @@
}
void detail::SafeThreadOwnerBase::Join() {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
if (auto thr = m_thread.lock()) {
auto stdThread = std::move(m_stdThread);
m_thread.reset();
@@ -62,25 +63,24 @@
void detail::swap(SafeThreadOwnerBase& lhs, SafeThreadOwnerBase& rhs) noexcept {
using std::swap;
if (&lhs == &rhs) return;
- std::lock(lhs.m_mutex, rhs.m_mutex);
- std::lock_guard<wpi::mutex> lock_lhs(lhs.m_mutex, std::adopt_lock);
- std::lock_guard<wpi::mutex> lock_rhs(rhs.m_mutex, std::adopt_lock);
+ std::scoped_lock lock(lhs.m_mutex, rhs.m_mutex);
std::swap(lhs.m_stdThread, rhs.m_stdThread);
std::swap(lhs.m_thread, rhs.m_thread);
}
detail::SafeThreadOwnerBase::operator bool() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return !m_thread.expired();
}
std::thread::native_handle_type
detail::SafeThreadOwnerBase::GetNativeThreadHandle() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_stdThread.native_handle();
}
-std::shared_ptr<SafeThread> detail::SafeThreadOwnerBase::GetThread() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+std::shared_ptr<SafeThread> detail::SafeThreadOwnerBase::GetThreadSharedPtr()
+ const {
+ std::scoped_lock lock(m_mutex);
return m_thread.lock();
}
diff --git a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp b/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
index 0abf862..90d9496 100644
--- a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
+++ b/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
@@ -27,6 +27,7 @@
#include <cstring>
#ifdef _WIN32
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
@@ -53,7 +54,7 @@
#ifdef _WIN32
WSAData wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
- WSAStartup(wVersionRequested, &wsaData);
+ (void)WSAStartup(wVersionRequested, &wsaData);
#endif
}
@@ -151,9 +152,7 @@
return;
address.sin_port = htons(m_port);
- fd_set sdset;
- struct timeval tv;
- int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
+ int result = -1, sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) return;
// Set socket to non-blocking
diff --git a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp b/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
index e0a8a92..de8bc2c 100644
--- a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
+++ b/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -74,7 +74,7 @@
// don't start a new worker if we had a previously still-active connection
// attempt to the same server
{
- std::lock_guard<wpi::mutex> lock(local->mtx);
+ std::scoped_lock lock(local->mtx);
if (local->active.count(active_tracker) > 0) continue; // already in set
}
@@ -85,7 +85,7 @@
if (!result->done) {
// add to global state
{
- std::lock_guard<wpi::mutex> lock(local->mtx);
+ std::scoped_lock lock(local->mtx);
local->active.insert(active_tracker);
}
@@ -95,13 +95,13 @@
// remove from global state
{
- std::lock_guard<wpi::mutex> lock(local->mtx);
+ std::scoped_lock lock(local->mtx);
local->active.erase(active_tracker);
}
// successful connection
if (stream) {
- std::lock_guard<wpi::mutex> lock(result->mtx);
+ std::scoped_lock lock(result->mtx);
if (!result->done.exchange(true)) result->stream = std::move(stream);
}
}
@@ -112,7 +112,7 @@
}
// wait for a result, timeout, or all finished
- std::unique_lock<wpi::mutex> lock(result->mtx);
+ std::unique_lock lock(result->mtx);
if (timeout == 0) {
result->cv.wait(
lock, [&] { return result->stream || result->count >= num_workers; });
diff --git a/wpiutil/src/main/native/cpp/WebSocket.cpp b/wpiutil/src/main/native/cpp/WebSocket.cpp
index a38be20..82c83bb 100644
--- a/wpiutil/src/main/native/cpp/WebSocket.cpp
+++ b/wpiutil/src/main/native/cpp/WebSocket.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -228,7 +228,7 @@
});
// Start handshake timer if a timeout was specified
- if (options.handshakeTimeout != uv::Timer::Time::max()) {
+ if (options.handshakeTimeout != (uv::Timer::Time::max)()) {
auto timer = uv::Timer::Create(m_stream.GetLoopRef());
timer->timeout.connect(
[this]() { Terminate(1006, "connection timed out"); });
@@ -286,8 +286,9 @@
SmallVector<uv::Buffer, 4> bufs;
if (code != 1005) {
raw_uv_ostream os{bufs, 4096};
- os << ArrayRef<uint8_t>{static_cast<uint8_t>((code >> 8) & 0xff),
- static_cast<uint8_t>(code & 0xff)};
+ const uint8_t codeMsb[] = {static_cast<uint8_t>((code >> 8) & 0xff),
+ static_cast<uint8_t>(code & 0xff)};
+ os << ArrayRef<uint8_t>(codeMsb);
reason.print(os);
}
Send(kFlagFin | kOpClose, bufs, [](auto bufs, uv::Error) {
@@ -335,7 +336,7 @@
if (m_frameSize == UINT64_MAX) {
// Need at least two bytes to determine header length
if (m_header.size() < 2u) {
- size_t toCopy = std::min(2u - m_header.size(), data.size());
+ size_t toCopy = (std::min)(2u - m_header.size(), data.size());
m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
data = data.drop_front(toCopy);
if (m_header.size() < 2u) return; // need more data
@@ -362,7 +363,7 @@
// Need to complete header to calculate message size
if (m_header.size() < m_headerSize) {
- size_t toCopy = std::min(m_headerSize - m_header.size(), data.size());
+ size_t toCopy = (std::min)(m_headerSize - m_header.size(), data.size());
m_header.append(data.bytes_begin(), data.bytes_begin() + toCopy);
data = data.drop_front(toCopy);
if (m_header.size() < m_headerSize) return; // need more data
@@ -394,7 +395,7 @@
if (m_frameSize != UINT64_MAX) {
size_t need = m_frameStart + m_frameSize - m_payload.size();
- size_t toCopy = std::min(need, data.size());
+ size_t toCopy = (std::min)(need, data.size());
m_payload.append(data.bytes_begin(), data.bytes_begin() + toCopy);
data = data.drop_front(toCopy);
need -= toCopy;
@@ -520,18 +521,20 @@
os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | size);
} else if (size <= 0xffff) {
os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 126);
- os << ArrayRef<uint8_t>{static_cast<uint8_t>((size >> 8) & 0xff),
- static_cast<uint8_t>(size & 0xff)};
+ const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 8) & 0xff),
+ static_cast<uint8_t>(size & 0xff)};
+ os << ArrayRef<uint8_t>(sizeMsb);
} else {
os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 127);
- os << ArrayRef<uint8_t>{static_cast<uint8_t>((size >> 56) & 0xff),
- static_cast<uint8_t>((size >> 48) & 0xff),
- static_cast<uint8_t>((size >> 40) & 0xff),
- static_cast<uint8_t>((size >> 32) & 0xff),
- static_cast<uint8_t>((size >> 24) & 0xff),
- static_cast<uint8_t>((size >> 16) & 0xff),
- static_cast<uint8_t>((size >> 8) & 0xff),
- static_cast<uint8_t>(size & 0xff)};
+ const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 56) & 0xff),
+ static_cast<uint8_t>((size >> 48) & 0xff),
+ static_cast<uint8_t>((size >> 40) & 0xff),
+ static_cast<uint8_t>((size >> 32) & 0xff),
+ static_cast<uint8_t>((size >> 24) & 0xff),
+ static_cast<uint8_t>((size >> 16) & 0xff),
+ static_cast<uint8_t>((size >> 8) & 0xff),
+ static_cast<uint8_t>(size & 0xff)};
+ os << ArrayRef<uint8_t>(sizeMsb);
}
// clients need to mask the input data
diff --git a/wpiutil/src/main/native/cpp/WebSocketServer.cpp b/wpiutil/src/main/native/cpp/WebSocketServer.cpp
index 3ad5e0e..056cb62 100644
--- a/wpiutil/src/main/native/cpp/WebSocketServer.cpp
+++ b/wpiutil/src/main/native/cpp/WebSocketServer.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -96,7 +96,7 @@
auto ws = m_helper.Accept(m_stream, protocol);
// Connect the websocket open event to our connected event.
- ws->open.connect_extended([ self, s = ws.get() ](auto conn, StringRef) {
+ ws->open.connect_extended([self, s = ws.get()](auto conn, StringRef) {
self->connected(self->m_req.GetUrl(), *s);
conn.disconnect(); // one-shot
});
diff --git a/wpiutil/src/main/native/cpp/future.cpp b/wpiutil/src/main/native/cpp/future.cpp
index fb31658..7ce0875 100644
--- a/wpiutil/src/main/native/cpp/future.cpp
+++ b/wpiutil/src/main/native/cpp/future.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -16,12 +16,12 @@
}
void PromiseFactoryBase::IgnoreResult(uint64_t request) {
- std::unique_lock<wpi::mutex> lock(m_resultMutex);
+ std::unique_lock lock(m_resultMutex);
EraseRequest(request);
}
uint64_t PromiseFactoryBase::CreateRequest() {
- std::unique_lock<wpi::mutex> lock(m_resultMutex);
+ std::unique_lock lock(m_resultMutex);
uint64_t req = ++m_uid;
m_requests.push_back(req);
return req;
@@ -39,14 +39,14 @@
} // namespace detail
future<void> PromiseFactory<void>::MakeReadyFuture() {
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
uint64_t req = CreateErasedRequest();
m_results.emplace_back(req);
return future<void>{this, req};
}
void PromiseFactory<void>::SetValue(uint64_t request) {
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
if (!EraseRequest(request)) return;
auto it = std::find_if(m_thens.begin(), m_thens.end(),
[=](const auto& x) { return x.request == request; });
@@ -63,7 +63,7 @@
void PromiseFactory<void>::SetThen(uint64_t request, uint64_t outRequest,
ThenFunction func) {
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
auto it = std::find_if(m_results.begin(), m_results.end(),
[=](const auto& r) { return r == request; });
if (it != m_results.end()) {
@@ -75,7 +75,7 @@
}
bool PromiseFactory<void>::IsReady(uint64_t request) noexcept {
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
auto it = std::find_if(m_results.begin(), m_results.end(),
[=](const auto& r) { return r == request; });
return it != m_results.end();
@@ -83,7 +83,7 @@
void PromiseFactory<void>::GetResult(uint64_t request) {
// wait for response
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
while (IsActive()) {
// Did we get a response to *our* request?
auto it = std::find_if(m_results.begin(), m_results.end(),
@@ -100,7 +100,7 @@
void PromiseFactory<void>::WaitResult(uint64_t request) {
// wait for response
- std::unique_lock<wpi::mutex> lock(GetResultMutex());
+ std::unique_lock lock(GetResultMutex());
while (IsActive()) {
// Did we get a response to *our* request?
auto it = std::find_if(m_results.begin(), m_results.end(),
diff --git a/wpiutil/src/main/native/cpp/http_parser.cpp b/wpiutil/src/main/native/cpp/http_parser.cpp
index 0900219..fb56010 100644
--- a/wpiutil/src/main/native/cpp/http_parser.cpp
+++ b/wpiutil/src/main/native/cpp/http_parser.cpp
@@ -25,6 +25,10 @@
#include <string.h>
#include <limits.h>
+#ifdef _WIN32
+#pragma warning(disable : 4018 26451)
+#endif
+
#ifndef ULLONG_MAX
# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
#endif
diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
new file mode 100644
index 0000000..c14b3f4
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
@@ -0,0 +1,54 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#include <jni.h>
+
+#include "edu_wpi_first_wpiutil_WPIUtilJNI.h"
+#include "wpi/PortForwarder.h"
+#include "wpi/jni_util.h"
+
+using namespace wpi::java;
+
+extern "C" {
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
+ return JNI_ERR;
+
+ return JNI_VERSION_1_6;
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {}
+
+/*
+ * Class: edu_wpi_first_wpiutil_WPIUtilJNI
+ * Method: addPortForwarder
+ * Signature: (ILjava/lang/String;I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpiutil_WPIUtilJNI_addPortForwarder
+ (JNIEnv* env, jclass, jint port, jstring remoteHost, jint remotePort)
+{
+ wpi::PortForwarder::GetInstance().Add(static_cast<unsigned int>(port),
+ JStringRef{env, remoteHost}.str(),
+ static_cast<unsigned int>(remotePort));
+}
+
+/*
+ * Class: edu_wpi_first_wpiutil_WPIUtilJNI
+ * Method: removePortForwarder
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_wpiutil_WPIUtilJNI_removePortForwarder
+ (JNIEnv* env, jclass, jint port)
+{
+ wpi::PortForwarder::GetInstance().Remove(port);
+}
+
+} // extern "C"
diff --git a/wpiutil/src/main/native/cpp/json.cpp b/wpiutil/src/main/native/cpp/json.cpp
index 9becfdd..ba9cd8e 100644
--- a/wpiutil/src/main/native/cpp/json.cpp
+++ b/wpiutil/src/main/native/cpp/json.cpp
@@ -142,24 +142,24 @@
case value_t::object:
{
std::allocator<object_t> alloc;
- alloc.destroy(object);
- alloc.deallocate(object, 1);
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
break;
}
case value_t::array:
{
std::allocator<array_t> alloc;
- alloc.destroy(array);
- alloc.deallocate(array, 1);
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
break;
}
case value_t::string:
{
std::allocator<std::string> alloc;
- alloc.destroy(string);
- alloc.deallocate(string, 1);
+ std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
+ std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
break;
}
@@ -621,8 +621,8 @@
case value_t::object:
{
- // delegate call to std::allocator<json>::max_size()
- return std::allocator<json>().max_size();
+ // delegate call to std::allocator<object_t>::max_size()
+ return std::allocator_traits<object_t>::max_size(*m_value.object);
}
default:
diff --git a/wpiutil/src/main/native/cpp/json_binary_writer.cpp b/wpiutil/src/main/native/cpp/json_binary_writer.cpp
index 75c39aa..2c0bbee 100644
--- a/wpiutil/src/main/native/cpp/json_binary_writer.cpp
+++ b/wpiutil/src/main/native/cpp/json_binary_writer.cpp
@@ -956,7 +956,7 @@
case value_t::number_unsigned:
{
- if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
+ if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
{
return 'i';
}
@@ -964,11 +964,11 @@
{
return 'U';
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
+ else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
{
return 'I';
}
- else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
+ else if (j.m_value.number_unsigned <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
{
return 'l';
}
diff --git a/wpiutil/src/main/native/cpp/json_serializer.h b/wpiutil/src/main/native/cpp/json_serializer.h
index a9b36d2..6983920 100644
--- a/wpiutil/src/main/native/cpp/json_serializer.h
+++ b/wpiutil/src/main/native/cpp/json_serializer.h
@@ -52,10 +52,8 @@
@param[in] ichar indentation character to use
*/
serializer(raw_ostream& s, const char ichar)
- : o(s), loc(std::localeconv()),
- thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)),
- decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)),
- indent_char(ichar), indent_string(512, indent_char)
+ : o(s), loc(std::localeconv()), indent_char(ichar),
+ indent_string(512, indent_char)
{}
// delete because of pointer members
@@ -189,13 +187,6 @@
/// the locale
const std::lconv* loc = nullptr;
- /// the locale's thousand separator character
- const char thousands_sep = '\0';
- /// the locale's decimal point character
- const char decimal_point = '\0';
-
- /// string buffer
- std::array<char, 512> string_buffer{{}};
/// the indentation character
const char indent_char;
diff --git a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp b/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
index bf51c36..abe3744 100644
--- a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
@@ -8,9 +8,9 @@
*===------------------------------------------------------------------------=*/
/*
* Copyright 2001-2004 Unicode, Inc.
- *
+ *
* Disclaimer
- *
+ *
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
@@ -18,9 +18,9 @@
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
- *
+ *
* Limitations on Rights to Redistribute This Code
- *
+ *
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
@@ -117,7 +117,7 @@
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
@@ -143,7 +143,7 @@
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
+ const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
@@ -192,7 +192,7 @@
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
+ const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
@@ -246,7 +246,7 @@
return result;
}
ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
+ const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
@@ -255,7 +255,7 @@
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
+ const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
@@ -316,7 +316,7 @@
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
+ const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
@@ -325,7 +325,7 @@
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
+ const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
@@ -347,7 +347,7 @@
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
-
+
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
@@ -540,7 +540,7 @@
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
+ const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
@@ -613,7 +613,7 @@
/* --------------------------------------------------------------------- */
static ConversionResult ConvertUTF8toUTF32Impl(
- const UTF8** sourceStart, const UTF8* sourceEnd,
+ const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
Boolean InputIsPartial) {
ConversionResult result = conversionOK;
diff --git a/wpiutil/src/main/native/cpp/llvm/Error.cpp b/wpiutil/src/main/native/cpp/llvm/Error.cpp
new file mode 100644
index 0000000..7bf9c5f
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/llvm/Error.cpp
@@ -0,0 +1,138 @@
+//===----- lib/Support/Error.cpp - Error and associated utilities ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/Error.h"
+#include "wpi/Twine.h"
+#include "wpi/ErrorHandling.h"
+#include "wpi/ManagedStatic.h"
+#include <system_error>
+
+using namespace wpi;
+
+namespace {
+
+ enum class ErrorErrorCode : int {
+ MultipleErrors = 1,
+ FileError,
+ InconvertibleError
+ };
+
+ // FIXME: This class is only here to support the transition to wpi::Error. It
+ // will be removed once this transition is complete. Clients should prefer to
+ // deal with the Error value directly, rather than converting to error_code.
+ class ErrorErrorCategory : public std::error_category {
+ public:
+ const char *name() const noexcept override { return "Error"; }
+
+ std::string message(int condition) const override {
+ switch (static_cast<ErrorErrorCode>(condition)) {
+ case ErrorErrorCode::MultipleErrors:
+ return "Multiple errors";
+ case ErrorErrorCode::InconvertibleError:
+ return "Inconvertible error value. An error has occurred that could "
+ "not be converted to a known std::error_code. Please file a "
+ "bug.";
+ case ErrorErrorCode::FileError:
+ return "A file error occurred.";
+ }
+ wpi_unreachable("Unhandled error code");
+ }
+ };
+
+}
+
+static ManagedStatic<ErrorErrorCategory> ErrorErrorCat;
+
+namespace wpi {
+
+void ErrorInfoBase::anchor() {}
+char ErrorInfoBase::ID = 0;
+char ErrorList::ID = 0;
+void ECError::anchor() {}
+char ECError::ID = 0;
+char StringError::ID = 0;
+char FileError::ID = 0;
+
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner) {
+ if (!E)
+ return;
+ OS << ErrorBanner;
+ handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+ EI.log(OS);
+ OS << "\n";
+ });
+}
+
+
+std::error_code ErrorList::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(ErrorErrorCode::MultipleErrors),
+ *ErrorErrorCat);
+}
+
+std::error_code inconvertibleErrorCode() {
+ return std::error_code(static_cast<int>(ErrorErrorCode::InconvertibleError),
+ *ErrorErrorCat);
+}
+
+std::error_code FileError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(ErrorErrorCode::FileError),
+ *ErrorErrorCat);
+}
+
+Error errorCodeToError(std::error_code EC) {
+ if (!EC)
+ return Error::success();
+ return Error(std::make_unique<ECError>(ECError(EC)));
+}
+
+std::error_code errorToErrorCode(Error Err) {
+ std::error_code EC;
+ handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+ EC = EI.convertToErrorCode();
+ });
+ if (EC == inconvertibleErrorCode())
+ report_fatal_error(EC.message());
+ return EC;
+}
+
+StringError::StringError(std::error_code EC, const Twine &S)
+ : Msg(S.str()), EC(EC) {}
+
+StringError::StringError(const Twine &S, std::error_code EC)
+ : Msg(S.str()), EC(EC), PrintMsgOnly(true) {}
+
+void StringError::log(raw_ostream &OS) const {
+ if (PrintMsgOnly) {
+ OS << Msg;
+ } else {
+ OS << EC.message();
+ if (!Msg.empty())
+ OS << (" " + Msg);
+ }
+}
+
+std::error_code StringError::convertToErrorCode() const {
+ return EC;
+}
+
+Error createStringError(std::error_code EC, char const *Msg) {
+ return make_error<StringError>(Msg, EC);
+}
+
+void report_fatal_error(Error Err, bool GenCrashDiag) {
+ assert(Err && "report_fatal_error called with success value");
+ std::string ErrMsg;
+ {
+ raw_string_ostream ErrStream(ErrMsg);
+ logAllUnhandledErrors(std::move(Err), ErrStream);
+ }
+ report_fatal_error(ErrMsg);
+}
+
+} // end namespace wpi
diff --git a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp b/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
index 088e805..ef79456 100644
--- a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
@@ -12,7 +12,191 @@
//
//===----------------------------------------------------------------------===//
+#include "wpi/ErrorHandling.h"
+#include "wpi/SmallVector.h"
+#include "wpi/Twine.h"
+#include "wpi/Error.h"
#include "wpi/WindowsError.h"
+#include "wpi/raw_ostream.h"
+#include <cassert>
+#include <cstdlib>
+#include <mutex>
+#include <new>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <io.h>
+#endif
+
+using namespace wpi;
+
+static fatal_error_handler_t ErrorHandler = nullptr;
+static void *ErrorHandlerUserData = nullptr;
+
+static fatal_error_handler_t BadAllocErrorHandler = nullptr;
+static void *BadAllocErrorHandlerUserData = nullptr;
+
+// Mutexes to synchronize installing error handlers and calling error handlers.
+// Do not use ManagedStatic, or that may allocate memory while attempting to
+// report an OOM.
+//
+// This usage of std::mutex has to be conditionalized behind ifdefs because
+// of this script:
+// compiler-rt/lib/sanitizer_common/symbolizer/scripts/build_symbolizer.sh
+// That script attempts to statically link the LLVM symbolizer library with the
+// STL and hide all of its symbols with 'opt -internalize'. To reduce size, it
+// cuts out the threading portions of the hermetic copy of libc++ that it
+// builds. We can remove these ifdefs if that script goes away.
+static std::mutex ErrorHandlerMutex;
+static std::mutex BadAllocErrorHandlerMutex;
+
+void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
+ void *user_data) {
+ std::scoped_lock Lock(ErrorHandlerMutex);
+ assert(!ErrorHandler && "Error handler already registered!\n");
+ ErrorHandler = handler;
+ ErrorHandlerUserData = user_data;
+}
+
+void wpi::remove_fatal_error_handler() {
+ std::scoped_lock Lock(ErrorHandlerMutex);
+ ErrorHandler = nullptr;
+ ErrorHandlerUserData = nullptr;
+}
+
+void wpi::report_fatal_error(const char *Reason, bool GenCrashDiag) {
+ report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(const std::string &Reason, bool GenCrashDiag) {
+ report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(StringRef Reason, bool GenCrashDiag) {
+ report_fatal_error(Twine(Reason), GenCrashDiag);
+}
+
+void wpi::report_fatal_error(const Twine &Reason, bool GenCrashDiag) {
+ wpi::fatal_error_handler_t handler = nullptr;
+ void* handlerData = nullptr;
+ {
+ // Only acquire the mutex while reading the handler, so as not to invoke a
+ // user-supplied callback under a lock.
+ std::scoped_lock Lock(ErrorHandlerMutex);
+ handler = ErrorHandler;
+ handlerData = ErrorHandlerUserData;
+ }
+
+ if (handler) {
+ handler(handlerData, Reason.str(), GenCrashDiag);
+ } else {
+ // Blast the result out to stderr. We don't try hard to make sure this
+ // succeeds (e.g. handling EINTR) and we can't use errs() here because
+ // raw ostreams can call report_fatal_error.
+ SmallVector<char, 64> Buffer;
+ raw_svector_ostream OS(Buffer);
+ OS << "LLVM ERROR: " << Reason << "\n";
+ StringRef MessageStr = OS.str();
+#ifdef _WIN32
+ int written = ::_write(2, MessageStr.data(), MessageStr.size());
+#else
+ ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
+#endif
+ (void)written; // If something went wrong, we deliberately just give up.
+ }
+
+ exit(1);
+}
+
+void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
+ void *user_data) {
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+ assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
+ BadAllocErrorHandler = handler;
+ BadAllocErrorHandlerUserData = user_data;
+}
+
+void wpi::remove_bad_alloc_error_handler() {
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+ BadAllocErrorHandler = nullptr;
+ BadAllocErrorHandlerUserData = nullptr;
+}
+
+void wpi::report_bad_alloc_error(const char *Reason, bool GenCrashDiag) {
+ fatal_error_handler_t Handler = nullptr;
+ void *HandlerData = nullptr;
+ {
+ // Only acquire the mutex while reading the handler, so as not to invoke a
+ // user-supplied callback under a lock.
+ std::scoped_lock Lock(BadAllocErrorHandlerMutex);
+ Handler = BadAllocErrorHandler;
+ HandlerData = BadAllocErrorHandlerUserData;
+ }
+
+ if (Handler) {
+ Handler(HandlerData, Reason, GenCrashDiag);
+ wpi_unreachable("bad alloc handler should not return");
+ }
+
+ // Don't call the normal error handler. It may allocate memory. Directly write
+ // an OOM to stderr and abort.
+ char OOMMessage[] = "LLVM ERROR: out of memory\n";
+#ifdef _WIN32
+ int written = ::_write(2, OOMMessage, strlen(OOMMessage));
+#else
+ ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
+#endif
+ (void)written;
+ abort();
+}
+
+// Causes crash on allocation failure. It is called prior to the handler set by
+// 'install_bad_alloc_error_handler'.
+static void out_of_memory_new_handler() {
+ wpi::report_bad_alloc_error("Allocation failed");
+}
+
+// Installs new handler that causes crash on allocation failure. It does not
+// need to be called explicitly, if this file is linked to application, because
+// in this case it is called during construction of 'new_handler_installer'.
+void wpi::install_out_of_memory_new_handler() {
+ static bool out_of_memory_new_handler_installed = false;
+ if (!out_of_memory_new_handler_installed) {
+ std::set_new_handler(out_of_memory_new_handler);
+ out_of_memory_new_handler_installed = true;
+ }
+}
+
+// Static object that causes installation of 'out_of_memory_new_handler' before
+// execution of 'main'.
+static class NewHandlerInstaller {
+public:
+ NewHandlerInstaller() {
+ install_out_of_memory_new_handler();
+ }
+} new_handler_installer;
+
+void wpi::wpi_unreachable_internal(const char *msg, const char *file,
+ unsigned line) {
+ // This code intentionally doesn't call the ErrorHandler callback, because
+ // wpi_unreachable is intended to be used to indicate "impossible"
+ // situations, and not legitimate runtime errors.
+ if (msg)
+ errs() << msg << "\n";
+ errs() << "UNREACHABLE executed";
+ if (file)
+ errs() << " at " << file << ":" << line;
+ errs() << "!\n";
+ abort();
+#ifdef LLVM_BUILTIN_UNREACHABLE
+ // Windows systems and possibly others don't declare abort() to be noreturn,
+ // so use the unreachable builtin to avoid a Clang self-host warning.
+ LLVM_BUILTIN_UNREACHABLE;
+#endif
+}
#ifdef _WIN32
diff --git a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp b/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
index 51c033e..e916751 100644
--- a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
@@ -20,10 +20,10 @@
// Provide a definition and static initializer for the fixed seed. This
// initializer should always be zero to ensure its value can never appear to be
// non-zero, even during dynamic initialization.
-size_t wpi::hashing::detail::fixed_seed_override = 0;
+uint64_t wpi::hashing::detail::fixed_seed_override = 0;
// Implement the function for forced setting of the fixed seed.
// FIXME: Use atomic operations here so that there is no data race.
-void wpi::set_fixed_execution_hash_seed(size_t fixed_value) {
+void wpi::set_fixed_execution_hash_seed(uint64_t fixed_value) {
hashing::detail::fixed_seed_override = fixed_value;
}
diff --git a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
new file mode 100644
index 0000000..0cfe58a
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
@@ -0,0 +1,72 @@
+//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ManagedStatic class and wpi_shutdown().
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/ManagedStatic.h"
+#include "wpi/mutex.h"
+#include <cassert>
+#include <mutex>
+using namespace wpi;
+
+static const ManagedStaticBase *StaticList = nullptr;
+static wpi::mutex *ManagedStaticMutex = nullptr;
+static std::once_flag mutex_init_flag;
+
+static void initializeMutex() {
+ ManagedStaticMutex = new wpi::mutex();
+}
+
+static wpi::mutex* getManagedStaticMutex() {
+ std::call_once(mutex_init_flag, initializeMutex);
+ return ManagedStaticMutex;
+}
+
+void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
+ void (*Deleter)(void*)) const {
+ assert(Creator);
+ std::scoped_lock Lock(*getManagedStaticMutex());
+
+ if (!Ptr.load(std::memory_order_relaxed)) {
+ void *Tmp = Creator();
+
+ Ptr.store(Tmp, std::memory_order_release);
+ DeleterFn = Deleter;
+
+ // Add to list of managed statics.
+ Next = StaticList;
+ StaticList = this;
+ }
+}
+
+void ManagedStaticBase::destroy() const {
+ assert(DeleterFn && "ManagedStatic not initialized correctly!");
+ assert(StaticList == this &&
+ "Not destroyed in reverse order of construction?");
+ // Unlink from list.
+ StaticList = Next;
+ Next = nullptr;
+
+ // Destroy memory.
+ DeleterFn(Ptr);
+
+ // Cleanup.
+ Ptr = nullptr;
+ DeleterFn = nullptr;
+}
+
+/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
+void wpi::wpi_shutdown() {
+ std::scoped_lock Lock(*getManagedStaticMutex());
+
+ while (StaticList)
+ StaticList->destroy();
+}
diff --git a/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp b/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
index 41c43e2..985e269 100644
--- a/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
@@ -132,7 +132,7 @@
}
void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
- optional<size_t> Width) {
+ std::optional<size_t> Width) {
const size_t kMaxWidth = 128u;
size_t W = std::min(kMaxWidth, Width.value_or(0u));
@@ -162,7 +162,7 @@
}
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
- optional<size_t> Precision) {
+ std::optional<size_t> Precision) {
size_t Prec = Precision.value_or(getDefaultPrecision(Style));
if (std::isnan(N)) {
diff --git a/wpiutil/src/main/native/cpp/llvm/Path.cpp b/wpiutil/src/main/native/cpp/llvm/Path.cpp
index 12736b9..49f92d3 100644
--- a/wpiutil/src/main/native/cpp/llvm/Path.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/Path.cpp
@@ -12,7 +12,12 @@
//===----------------------------------------------------------------------===//
#include "wpi/Path.h"
-
+#include "wpi/ArrayRef.h"
+#include "wpi/Endian.h"
+#include "wpi/Errc.h"
+#include "wpi/ErrorHandling.h"
+#include "wpi/FileSystem.h"
+#include "wpi/SmallString.h"
#include <cctype>
#include <cstring>
@@ -22,10 +27,8 @@
#include <io.h>
#endif
-#include "wpi/FileSystem.h"
-#include "wpi/SmallString.h"
-
using namespace wpi;
+using namespace wpi::support::endian;
namespace {
using wpi::StringRef;
@@ -444,7 +447,7 @@
// If prefixes have the same size we can simply copy the new one over.
if (OldPrefix.size() == NewPrefix.size()) {
- std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin());
+ wpi::copy(NewPrefix, Path.begin());
return;
}
@@ -674,9 +677,8 @@
return std::error_code();
}
-static std::error_code make_absolute(const Twine ¤t_directory,
- SmallVectorImpl<char> &path,
- bool use_current_directory) {
+void make_absolute(const Twine ¤t_directory,
+ SmallVectorImpl<char> &path) {
StringRef p(path.data(), path.size());
bool rootDirectory = path::has_root_directory(p);
@@ -685,14 +687,11 @@
// Already absolute.
if (rootName && rootDirectory)
- return std::error_code();
+ return;
// All of the following conditions will need the current directory.
SmallString<128> current_dir;
- if (use_current_directory)
- current_directory.toVector(current_dir);
- else if (std::error_code ec = current_path(current_dir))
- return ec;
+ current_directory.toVector(current_dir);
// Relative path. Prepend the current directory.
if (!rootName && !rootDirectory) {
@@ -700,7 +699,7 @@
path::append(current_dir, p);
// Set path to the result.
path.swap(current_dir);
- return std::error_code();
+ return;
}
if (!rootName && rootDirectory) {
@@ -709,7 +708,7 @@
path::append(curDirRootName, p);
// Set path to the result.
path.swap(curDirRootName);
- return std::error_code();
+ return;
}
if (rootName && !rootDirectory) {
@@ -721,21 +720,23 @@
SmallString<128> res;
path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
path.swap(res);
- return std::error_code();
+ return;
}
- assert(false && "All rootName and rootDirectory combinations should have "
+ wpi_unreachable("All rootName and rootDirectory combinations should have "
"occurred above!");
- return std::error_code();
-}
-
-std::error_code make_absolute(const Twine ¤t_directory,
- SmallVectorImpl<char> &path) {
- return make_absolute(current_directory, path, true);
}
std::error_code make_absolute(SmallVectorImpl<char> &path) {
- return make_absolute(Twine(), path, false);
+ if (path::is_absolute(path))
+ return {};
+
+ SmallString<128> current_dir;
+ if (std::error_code ec = current_path(current_dir))
+ return ec;
+
+ make_absolute(current_dir, path);
+ return {};
}
bool exists(const basic_file_status &status) {
@@ -803,12 +804,13 @@
return std::error_code();
}
-void directory_entry::replace_filename(const Twine &filename,
- basic_file_status st) {
- SmallString<128> path = path::parent_path(Path);
- path::append(path, filename);
- Path = path.str();
- Status = st;
+void directory_entry::replace_filename(const Twine &Filename, file_type Type,
+ basic_file_status Status) {
+ SmallString<128> PathStr = path::parent_path(Path);
+ path::append(PathStr, Filename);
+ this->Path = PathStr.str();
+ this->Type = Type;
+ this->Status = Status;
}
ErrorOr<perms> getPermissions(const Twine &Path) {
@@ -829,20 +831,3 @@
#else
#include "Unix/Path.inc"
#endif
-
-namespace wpi {
-namespace sys {
-namespace path {
-
-bool user_cache_directory(SmallVectorImpl<char> &Result, const Twine &Path1,
- const Twine &Path2, const Twine &Path3) {
- if (getUserCacheDir(Result)) {
- append(Result, Path1, Path2, Path3);
- return true;
- }
- return false;
-}
-
-} // end namespace path
-} // end namsspace sys
-} // end namespace wpi
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp b/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
index f91b6eb..1dab1fc 100644
--- a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
@@ -15,7 +15,7 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/DenseMapInfo.h"
#include "wpi/MathExtras.h"
-#include "wpi/memory.h"
+#include "wpi/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
@@ -32,7 +32,8 @@
NumNonEmpty = NumTombstones = 0;
// Install the new array. Clear all the buckets to empty.
- CurArray = (const void**)CheckedMalloc(sizeof(void*) * CurArraySize);
+ CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
+
memset(CurArray, -1, CurArraySize*sizeof(void*));
}
@@ -96,7 +97,10 @@
bool WasSmall = isSmall();
// Install the new array. Clear all the buckets to empty.
- CurArray = (const void**) CheckedMalloc(sizeof(void*) * NewSize);
+ const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
+
+ // Reset member only if memory was allocated successfully
+ CurArray = NewBuckets;
CurArraySize = NewSize;
memset(CurArray, -1, NewSize*sizeof(void*));
@@ -123,7 +127,7 @@
CurArray = SmallArray;
// Otherwise, allocate new heap space (unless we were the same size)
} else {
- CurArray = (const void**)CheckedMalloc(sizeof(void*) * that.CurArraySize);
+ CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
}
// Copy over the that array.
@@ -152,15 +156,12 @@
// Otherwise, allocate new heap space (unless we were the same size)
} else if (CurArraySize != RHS.CurArraySize) {
if (isSmall())
- CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize);
+ CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
else {
- const void **T = (const void**)realloc(CurArray,
+ const void **T = (const void**)safe_realloc(CurArray,
sizeof(void*) * RHS.CurArraySize);
- if (!T)
- free(CurArray);
CurArray = T;
}
- assert(CurArray && "Failed to allocate memory?");
}
CopyHelper(RHS);
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp b/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
index faa5ba7..974fec9 100644
--- a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
@@ -12,30 +12,32 @@
//===----------------------------------------------------------------------===//
#include "wpi/SmallVector.h"
-#include "wpi/memory.h"
+#include "wpi/MemAlloc.h"
using namespace wpi;
/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like datatypes and is out of line to reduce code duplication.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
size_t TSize) {
- size_t CurSizeBytes = size_in_bytes();
- size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow.
- if (NewCapacityInBytes < MinSizeInBytes)
- NewCapacityInBytes = MinSizeInBytes;
+ // Ensure we can fit the new capacity in 32 bits.
+ if (MinCapacity > UINT32_MAX)
+ report_bad_alloc_error("SmallVector capacity overflow during allocation");
+
+ size_t NewCapacity = 2 * capacity() + 1; // Always grow.
+ NewCapacity =
+ std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
void *NewElts;
if (BeginX == FirstEl) {
- NewElts = CheckedMalloc(NewCapacityInBytes);
+ NewElts = safe_malloc(NewCapacity * TSize);
// Copy the elements over. No need to run dtors on PODs.
- memcpy(NewElts, this->BeginX, CurSizeBytes);
+ memcpy(NewElts, this->BeginX, size() * TSize);
} else {
// If this wasn't grown from the inline copy, grow the allocated space.
- NewElts = CheckedRealloc(this->BeginX, NewCapacityInBytes);
+ NewElts = safe_realloc(this->BeginX, NewCapacity * TSize);
}
- this->EndX = (char*)NewElts+CurSizeBytes;
this->BeginX = NewElts;
- this->CapacityX = (char*)this->BeginX + NewCapacityInBytes;
+ this->Capacity = NewCapacity;
}
diff --git a/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp b/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
index 41c3305..e4bfe8a 100644
--- a/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/StringExtras.cpp
@@ -58,16 +58,33 @@
}
}
-void wpi::PrintEscapedString(StringRef Name, raw_ostream &Out) {
+void wpi::printEscapedString(StringRef Name, raw_ostream &Out) {
for (unsigned i = 0, e = Name.size(); i != e; ++i) {
unsigned char C = Name[i];
- if (isprint(C) && C != '\\' && C != '"')
+ if (isPrint(C) && C != '\\' && C != '"')
Out << C;
else
Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
}
}
+void wpi::printHTMLEscaped(StringRef String, raw_ostream &Out) {
+ for (char C : String) {
+ if (C == '&')
+ Out << "&";
+ else if (C == '<')
+ Out << "<";
+ else if (C == '>')
+ Out << ">";
+ else if (C == '\"')
+ Out << """;
+ else if (C == '\'')
+ Out << "'";
+ else
+ Out << C;
+ }
+}
+
void wpi::printLowerCase(StringRef String, raw_ostream &Out) {
for (const char C : String)
Out << toLower(C);
diff --git a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp b/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
index ea91dbb..5c625c7 100644
--- a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
@@ -15,7 +15,6 @@
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
-#include "wpi/memory.h"
#include <cassert>
using namespace wpi;
@@ -59,7 +58,7 @@
NumTombstones = 0;
TheTable = static_cast<StringMapEntryBase **>(
- CheckedCalloc(NewNumBuckets+1,
+ safe_calloc(NewNumBuckets+1,
sizeof(StringMapEntryBase **) + sizeof(unsigned)));
// Set the member only if TheTable was successfully allocated
@@ -129,7 +128,6 @@
}
}
-
/// FindKey - Look up the bucket that contains the specified key. If it exists
/// in the map, return the bucket number of the key. Otherwise return -1.
/// This does not modify the map.
@@ -219,7 +217,7 @@
// Allocate one extra bucket which will always be non-empty. This allows the
// iterators to stop at end.
auto NewTableArray = static_cast<StringMapEntryBase **>(
- CheckedCalloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
+ safe_calloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
NewTableArray[NewSize] = (StringMapEntryBase*)2;
diff --git a/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc b/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
index a1ea5a1..b786813 100644
--- a/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
+++ b/wpiutil/src/main/native/cpp/llvm/Unix/Path.inc
@@ -16,25 +16,45 @@
//=== is guaranteed to work on *all* UNIX variants.
//===----------------------------------------------------------------------===//
+#include "wpi/Errno.h"
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
#include <dirent.h>
-#define NAMLEN(dirent) strlen((dirent)->d_name)
+#include <pwd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <unistd.h>
+using namespace wpi;
+
namespace wpi {
namespace sys {
namespace fs {
+
+const file_t kInvalidFile = -1;
+
+TimePoint<> basic_file_status::getLastAccessedTime() const {
+ return toTimePoint(fs_st_atime, fs_st_atime_nsec);
+}
+
+TimePoint<> basic_file_status::getLastModificationTime() const {
+ return toTimePoint(fs_st_mtime, fs_st_mtime_nsec);
+}
+
UniqueID file_status::getUniqueID() const {
return UniqueID(fs_st_dev, fs_st_ino);
}
+uint32_t file_status::getLinkCount() const {
+ return fs_st_nlinks;
+}
+
std::error_code current_path(SmallVectorImpl<char> &result) {
result.clear();
@@ -93,9 +113,9 @@
// Don't say that directories are executable.
struct stat buf;
if (0 != stat(P.begin(), &buf))
- return std::make_error_code(std::errc::permission_denied);
+ return errc::permission_denied;
if (!S_ISREG(buf.st_mode))
- return std::make_error_code(std::errc::permission_denied);
+ return errc::permission_denied;
}
return std::error_code();
@@ -117,37 +137,48 @@
return std::error_code();
}
+static file_type typeForMode(mode_t Mode) {
+ if (S_ISDIR(Mode))
+ return file_type::directory_file;
+ else if (S_ISREG(Mode))
+ return file_type::regular_file;
+ else if (S_ISBLK(Mode))
+ return file_type::block_file;
+ else if (S_ISCHR(Mode))
+ return file_type::character_file;
+ else if (S_ISFIFO(Mode))
+ return file_type::fifo_file;
+ else if (S_ISSOCK(Mode))
+ return file_type::socket_file;
+ else if (S_ISLNK(Mode))
+ return file_type::symlink_file;
+ return file_type::type_unknown;
+}
+
static std::error_code fillStatus(int StatRet, const struct stat &Status,
- file_status &Result) {
+ file_status &Result) {
if (StatRet != 0) {
- std::error_code ec(errno, std::generic_category());
- if (ec == std::errc::no_such_file_or_directory)
+ std::error_code EC(errno, std::generic_category());
+ if (EC == errc::no_such_file_or_directory)
Result = file_status(file_type::file_not_found);
else
Result = file_status(file_type::status_error);
- return ec;
+ return EC;
}
- file_type Type = file_type::type_unknown;
-
- if (S_ISDIR(Status.st_mode))
- Type = file_type::directory_file;
- else if (S_ISREG(Status.st_mode))
- Type = file_type::regular_file;
- else if (S_ISBLK(Status.st_mode))
- Type = file_type::block_file;
- else if (S_ISCHR(Status.st_mode))
- Type = file_type::character_file;
- else if (S_ISFIFO(Status.st_mode))
- Type = file_type::fifo_file;
- else if (S_ISSOCK(Status.st_mode))
- Type = file_type::socket_file;
- else if (S_ISLNK(Status.st_mode))
- Type = file_type::symlink_file;
+ uint32_t atime_nsec, mtime_nsec;
+#if defined(__APPLE__)
+ atime_nsec = Status.st_atimespec.tv_nsec;
+ mtime_nsec = Status.st_mtimespec.tv_nsec;
+#else
+ atime_nsec = Status.st_atim.tv_nsec;
+ mtime_nsec = Status.st_mtim.tv_nsec;
+#endif
perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
- Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
- Status.st_ino, Status.st_atime, Status.st_mtime,
+ Result = file_status(typeForMode(Status.st_mode), Perms, Status.st_dev,
+ Status.st_nlink, Status.st_ino,
+ Status.st_atime, atime_nsec, Status.st_mtime, mtime_nsec,
Status.st_uid, Status.st_gid, Status.st_size);
return std::error_code();
@@ -168,6 +199,71 @@
return fillStatus(StatRet, Status, Result);
}
+std::error_code mapped_file_region::init(int FD, uint64_t Offset,
+ mapmode Mode) {
+ assert(Size != 0);
+
+ int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
+ int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#if defined(__APPLE__)
+ //----------------------------------------------------------------------
+ // Newer versions of MacOSX have a flag that will allow us to read from
+ // binaries whose code signature is invalid without crashing by using
+ // the MAP_RESILIENT_CODESIGN flag. Also if a file from removable media
+ // is mapped we can avoid crashing and return zeroes to any pages we try
+ // to read if the media becomes unavailable by using the
+ // MAP_RESILIENT_MEDIA flag. These flags are only usable when mapping
+ // with PROT_READ, so take care not to specify them otherwise.
+ //----------------------------------------------------------------------
+ if (Mode == readonly) {
+#if defined(MAP_RESILIENT_CODESIGN)
+ flags |= MAP_RESILIENT_CODESIGN;
+#endif
+#if defined(MAP_RESILIENT_MEDIA)
+ flags |= MAP_RESILIENT_MEDIA;
+#endif
+ }
+#endif // #if defined (__APPLE__)
+
+ Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
+ if (Mapping == MAP_FAILED)
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
+mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
+ uint64_t offset, std::error_code &ec)
+ : Size(length), Mapping(), Mode(mode) {
+ (void)Mode;
+ ec = init(fd, offset, mode);
+ if (ec)
+ Mapping = nullptr;
+}
+
+mapped_file_region::~mapped_file_region() {
+ if (Mapping)
+ ::munmap(Mapping, Size);
+}
+
+size_t mapped_file_region::size() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Size;
+}
+
+char *mapped_file_region::data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<char*>(Mapping);
+}
+
+const char *mapped_file_region::const_data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<const char*>(Mapping);
+}
+
+int mapped_file_region::alignment() {
+ return ::sysconf(_SC_PAGE_SIZE);
+}
+
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
StringRef path,
bool follow_symlinks) {
@@ -191,19 +287,25 @@
return std::error_code();
}
-std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+static file_type direntType(dirent* Entry) {
+ // Most platforms provide the file type in the dirent: Linux/BSD/Mac.
+ // The DTTOIF macro lets us reuse our status -> type conversion.
+ return typeForMode(DTTOIF(Entry->d_type));
+}
+
+std::error_code detail::directory_iterator_increment(detail::DirIterState &It) {
errno = 0;
- dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
- if (cur_dir == nullptr && errno != 0) {
+ dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle));
+ if (CurDir == nullptr && errno != 0) {
return std::error_code(errno, std::generic_category());
- } else if (cur_dir != nullptr) {
- StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
- if ((name.size() == 1 && name[0] == '.') ||
- (name.size() == 2 && name[0] == '.' && name[1] == '.'))
- return directory_iterator_increment(it);
- it.CurrentEntry.replace_filename(name);
+ } else if (CurDir != nullptr) {
+ StringRef Name(CurDir->d_name);
+ if ((Name.size() == 1 && Name[0] == '.') ||
+ (Name.size() == 2 && Name[0] == '.' && Name[1] == '.'))
+ return directory_iterator_increment(It);
+ It.CurrentEntry.replace_filename(Name, direntType(CurDir));
} else
- return directory_iterator_destruct(it);
+ return directory_iterator_destruct(It);
return std::error_code();
}
@@ -224,14 +326,85 @@
}
#endif
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
- SmallVectorImpl<char> *RealPath) {
+static int nativeOpenFlags(CreationDisposition Disp, OpenFlags Flags,
+ FileAccess Access) {
+ int Result = 0;
+ if (Access == FA_Read)
+ Result |= O_RDONLY;
+ else if (Access == FA_Write)
+ Result |= O_WRONLY;
+ else if (Access == (FA_Read | FA_Write))
+ Result |= O_RDWR;
+
+ // This is for compatibility with old code that assumed F_Append implied
+ // would open an existing file. See Windows/Path.inc for a longer comment.
+ if (Flags & F_Append)
+ Disp = CD_OpenAlways;
+
+ if (Disp == CD_CreateNew) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ Result |= O_EXCL; // Fail if it does.
+ } else if (Disp == CD_CreateAlways) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ Result |= O_TRUNC; // Truncate if it does.
+ } else if (Disp == CD_OpenAlways) {
+ Result |= O_CREAT; // Create if it doesn't exist.
+ } else if (Disp == CD_OpenExisting) {
+ // Nothing special, just don't add O_CREAT and we get these semantics.
+ }
+
+ if (Flags & F_Append)
+ Result |= O_APPEND;
+
+#ifdef O_CLOEXEC
+ if (!(Flags & OF_ChildInherit))
+ Result |= O_CLOEXEC;
+#endif
+
+ return Result;
+}
+
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned Mode) {
+ int OpenFlags = nativeOpenFlags(Disp, Flags, Access);
+
SmallString<128> Storage;
StringRef P = Name.toNullTerminatedStringRef(Storage);
- while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
- if (errno != EINTR)
- return std::error_code(errno, std::generic_category());
+ // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal
+ // when open is overloaded, such as in Bionic.
+ auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); };
+ if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0)
+ return std::error_code(errno, std::generic_category());
+#ifndef O_CLOEXEC
+ if (!(Flags & OF_ChildInherit)) {
+ int r = fcntl(ResultFD, F_SETFD, FD_CLOEXEC);
+ (void)r;
+ assert(r == 0 && "fcntl(F_SETFD, FD_CLOEXEC) failed");
}
+#endif
+ return std::error_code();
+}
+
+Expected<int> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode) {
+
+ int FD;
+ std::error_code EC = openFile(Name, FD, Disp, Access, Flags, Mode);
+ if (EC)
+ return errorCodeToError(EC);
+ return FD;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ std::error_code EC =
+ openFile(Name, ResultFD, CD_OpenExisting, FA_Read, Flags, 0666);
+ if (EC)
+ return EC;
+
// Attempt to get the real name of the file, if the user asked
if(!RealPath)
return std::error_code();
@@ -251,6 +424,9 @@
if (CharCount > 0)
RealPath->append(Buffer, Buffer + CharCount);
} else {
+ SmallString<128> Storage;
+ StringRef P = Name.toNullTerminatedStringRef(Storage);
+
// Use ::realpath to get the real path name
if (::realpath(P.begin(), Buffer) != nullptr)
RealPath->append(Buffer, Buffer + strlen(Buffer));
@@ -259,38 +435,18 @@
return std::error_code();
}
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
- OpenFlags Flags, unsigned Mode) {
- // Verify that we don't have both "append" and "excl".
- assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
- "Cannot specify both 'excl' and 'append' file creation flags!");
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ file_t ResultFD;
+ std::error_code EC = openFileForRead(Name, ResultFD, Flags, RealPath);
+ if (EC)
+ return errorCodeToError(EC);
+ return ResultFD;
+}
- int OpenFlags = O_CREAT;
-
-#ifdef O_CLOEXEC
- OpenFlags |= O_CLOEXEC;
-#endif
-
- if (Flags & F_RW)
- OpenFlags |= O_RDWR;
- else
- OpenFlags |= O_WRONLY;
-
- if (Flags & F_Append)
- OpenFlags |= O_APPEND;
- else if (!(Flags & F_NoTrunc))
- OpenFlags |= O_TRUNC;
-
- if (Flags & F_Excl)
- OpenFlags |= O_EXCL;
-
- SmallString<128> Storage;
- StringRef P = Name.toNullTerminatedStringRef(Storage);
- while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
- if (errno != EINTR)
- return std::error_code(errno, std::generic_category());
- }
- return std::error_code();
+void closeFile(file_t &F) {
+ ::close(F);
+ F = kInvalidFile;
}
} // end namespace fs
@@ -298,13 +454,18 @@
namespace path {
bool home_directory(SmallVectorImpl<char> &result) {
- if (char *RequestedDir = std::getenv("HOME")) {
- result.clear();
- result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
- return true;
+ char *RequestedDir = getenv("HOME");
+ if (!RequestedDir) {
+ struct passwd *pw = getpwuid(getuid());
+ if (pw && pw->pw_dir)
+ RequestedDir = pw->pw_dir;
}
+ if (!RequestedDir)
+ return false;
- return false;
+ result.clear();
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return true;
}
static bool getDarwinConfDir(bool TempDir, SmallVectorImpl<char> &Result) {
@@ -332,29 +493,6 @@
return false;
}
-static bool getUserCacheDir(SmallVectorImpl<char> &Result) {
- // First try using XDG_CACHE_HOME env variable,
- // as specified in XDG Base Directory Specification at
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- if (const char *XdgCacheDir = std::getenv("XDG_CACHE_HOME")) {
- Result.clear();
- Result.append(XdgCacheDir, XdgCacheDir + strlen(XdgCacheDir));
- return true;
- }
-
- // Try Darwin configuration query
- if (getDarwinConfDir(false, Result))
- return true;
-
- // Use "$HOME/.cache" if $HOME is available
- if (home_directory(Result)) {
- append(Result, ".cache");
- return true;
- }
-
- return false;
-}
-
static const char *getEnvTempDir() {
// Check whether the temporary directory is specified by an environment
// variable.
diff --git a/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc b/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
index 3a170eb..e9b5280 100644
--- a/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
+++ b/wpiutil/src/main/native/cpp/llvm/Windows/Path.inc
@@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//
#include "wpi/STLExtras.h"
+#include "wpi/ConvertUTF.h"
#include "wpi/WindowsError.h"
#include <fcntl.h>
#include <io.h>
@@ -31,9 +32,17 @@
#undef max
+// MinGW doesn't define this.
+#ifndef _ERRNO_T_DEFINED
+#define _ERRNO_T_DEFINED
+typedef int errno_t;
+#endif
+
#ifdef _MSC_VER
# pragma comment(lib, "shell32.lib")
# pragma comment(lib, "ole32.lib")
+#pragma warning(push)
+#pragma warning(disable: 4244 4267 4146)
#endif
using namespace wpi;
@@ -116,6 +125,8 @@
namespace fs {
+const file_t kInvalidFile = INVALID_HANDLE_VALUE;
+
UniqueID file_status::getUniqueID() const {
// The file is uniquely identified by the volume serial number along
// with the 64-bit file identifier.
@@ -125,6 +136,24 @@
return UniqueID(VolumeSerialNumber, FileID);
}
+TimePoint<> basic_file_status::getLastAccessedTime() const {
+ FILETIME Time;
+ Time.dwLowDateTime = LastAccessedTimeLow;
+ Time.dwHighDateTime = LastAccessedTimeHigh;
+ return toTimePoint(Time);
+}
+
+TimePoint<> basic_file_status::getLastModificationTime() const {
+ FILETIME Time;
+ Time.dwLowDateTime = LastWriteTimeLow;
+ Time.dwHighDateTime = LastWriteTimeHigh;
+ return toTimePoint(Time);
+}
+
+uint32_t file_status::getLinkCount() const {
+ return NumLinks;
+}
+
std::error_code current_path(SmallVectorImpl<char> &result) {
SmallVector<wchar_t, MAX_PATH> cur_path;
DWORD len = MAX_PATH;
@@ -147,6 +176,51 @@
return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
}
+static std::error_code realPathFromHandle(HANDLE H,
+ SmallVectorImpl<wchar_t> &Buffer) {
+ DWORD CountChars = ::GetFinalPathNameByHandleW(
+ H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+ if (CountChars > Buffer.capacity()) {
+ // The buffer wasn't big enough, try again. In this case the return value
+ // *does* indicate the size of the null terminator.
+ Buffer.reserve(CountChars);
+ CountChars = ::GetFinalPathNameByHandleW(
+ H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
+ }
+ if (CountChars == 0)
+ return mapWindowsError(GetLastError());
+ Buffer.set_size(CountChars);
+ return std::error_code();
+}
+
+static std::error_code realPathFromHandle(HANDLE H,
+ SmallVectorImpl<char> &RealPath) {
+ RealPath.clear();
+ SmallVector<wchar_t, MAX_PATH> Buffer;
+ if (std::error_code EC = realPathFromHandle(H, Buffer))
+ return EC;
+
+ const wchar_t *Data = Buffer.data();
+ DWORD CountChars = Buffer.size();
+ if (CountChars >= 4) {
+ if (0 == ::memcmp(Data, L"\\\\?\\", 8)) {
+ CountChars -= 4;
+ Data += 4;
+ }
+ }
+
+ // Convert the result from UTF-16 to UTF-8.
+ return UTF16ToUTF8(Data, CountChars, RealPath);
+}
+
+static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) {
+ FILE_DISPOSITION_INFO Disposition;
+ Disposition.DeleteFile = Delete;
+ if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition,
+ sizeof(Disposition)))
+ return mapWindowsError(::GetLastError());
+ return std::error_code();
+}
std::error_code access(const Twine &Path, AccessMode Mode) {
SmallVector<wchar_t, 128> PathUtf16;
@@ -162,11 +236,11 @@
if (LastError != ERROR_FILE_NOT_FOUND &&
LastError != ERROR_PATH_NOT_FOUND)
return mapWindowsError(LastError);
- return std::make_error_code(std::errc::no_such_file_or_directory);
+ return errc::no_such_file_or_directory;
}
if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY))
- return std::make_error_code(std::errc::permission_denied);
+ return errc::permission_denied;
return std::error_code();
}
@@ -315,6 +389,143 @@
return getStatus(FileHandle, Result);
}
+std::error_code mapped_file_region::init(int FD, uint64_t Offset,
+ mapmode Mode) {
+ this->Mode = Mode;
+ HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (OrigFileHandle == INVALID_HANDLE_VALUE)
+ return make_error_code(errc::bad_file_descriptor);
+
+ DWORD flprotect;
+ switch (Mode) {
+ case readonly: flprotect = PAGE_READONLY; break;
+ case readwrite: flprotect = PAGE_READWRITE; break;
+ case priv: flprotect = PAGE_WRITECOPY; break;
+ }
+
+ HANDLE FileMappingHandle =
+ ::CreateFileMappingW(OrigFileHandle, 0, flprotect,
+ Hi_32(Size),
+ Lo_32(Size),
+ 0);
+ if (FileMappingHandle == NULL) {
+ std::error_code ec = mapWindowsError(GetLastError());
+ return ec;
+ }
+
+ DWORD dwDesiredAccess;
+ switch (Mode) {
+ case readonly: dwDesiredAccess = FILE_MAP_READ; break;
+ case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
+ case priv: dwDesiredAccess = FILE_MAP_COPY; break;
+ }
+ Mapping = ::MapViewOfFile(FileMappingHandle,
+ dwDesiredAccess,
+ Offset >> 32,
+ Offset & 0xffffffff,
+ Size);
+ if (Mapping == NULL) {
+ std::error_code ec = mapWindowsError(GetLastError());
+ ::CloseHandle(FileMappingHandle);
+ return ec;
+ }
+
+ if (Size == 0) {
+ MEMORY_BASIC_INFORMATION mbi;
+ SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
+ if (Result == 0) {
+ std::error_code ec = mapWindowsError(GetLastError());
+ ::UnmapViewOfFile(Mapping);
+ ::CloseHandle(FileMappingHandle);
+ return ec;
+ }
+ Size = mbi.RegionSize;
+ }
+
+ // Close the file mapping handle, as it's kept alive by the file mapping. But
+ // neither the file mapping nor the file mapping handle keep the file handle
+ // alive, so we need to keep a reference to the file in case all other handles
+ // are closed and the file is deleted, which may cause invalid data to be read
+ // from the file.
+ ::CloseHandle(FileMappingHandle);
+ if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle,
+ ::GetCurrentProcess(), &FileHandle, 0, 0,
+ DUPLICATE_SAME_ACCESS)) {
+ std::error_code ec = mapWindowsError(GetLastError());
+ ::UnmapViewOfFile(Mapping);
+ return ec;
+ }
+
+ return std::error_code();
+}
+
+mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
+ uint64_t offset, std::error_code &ec)
+ : Size(length), Mapping() {
+ ec = init(fd, offset, mode);
+ if (ec)
+ Mapping = 0;
+}
+
+static bool hasFlushBufferKernelBug() {
+ static bool Ret{GetWindowsOSVersion() < wpi::VersionTuple(10, 0, 0, 17763)};
+ return Ret;
+}
+
+static bool isEXE(StringRef Magic) {
+ static const char PEMagic[] = {'P', 'E', '\0', '\0'};
+ if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) {
+ uint32_t off = read32le(Magic.data() + 0x3c);
+ // PE/COFF file, either EXE or DLL.
+ if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic))))
+ return true;
+ }
+ return false;
+}
+
+mapped_file_region::~mapped_file_region() {
+ if (Mapping) {
+
+ bool Exe = isEXE(StringRef((char *)Mapping, Size));
+
+ ::UnmapViewOfFile(Mapping);
+
+ if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) {
+ // There is a Windows kernel bug, the exact trigger conditions of which
+ // are not well understood. When triggered, dirty pages are not properly
+ // flushed and subsequent process's attempts to read a file can return
+ // invalid data. Calling FlushFileBuffers on the write handle is
+ // sufficient to ensure that this bug is not triggered.
+ // The bug only occurs when writing an executable and executing it right
+ // after, under high I/O pressure.
+ ::FlushFileBuffers(FileHandle);
+ }
+
+ ::CloseHandle(FileHandle);
+ }
+}
+
+size_t mapped_file_region::size() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Size;
+}
+
+char *mapped_file_region::data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<char*>(Mapping);
+}
+
+const char *mapped_file_region::const_data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<const char*>(Mapping);
+}
+
+int mapped_file_region::alignment() {
+ SYSTEM_INFO SysInfo;
+ ::GetSystemInfo(&SysInfo);
+ return SysInfo.dwAllocationGranularity;
+}
+
static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) {
return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes),
perms_from_attrs(FindData->dwFileAttributes),
@@ -325,28 +536,28 @@
FindData->nFileSizeHigh, FindData->nFileSizeLow);
}
-std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path,
- bool follow_symlinks) {
- SmallVector<wchar_t, 128> path_utf16;
+std::error_code detail::directory_iterator_construct(detail::DirIterState &IT,
+ StringRef Path,
+ bool FollowSymlinks) {
+ SmallVector<wchar_t, 128> PathUTF16;
- if (std::error_code ec = widenPath(path, path_utf16))
- return ec;
+ if (std::error_code EC = widenPath(Path, PathUTF16))
+ return EC;
// Convert path to the format that Windows is happy with.
- if (path_utf16.size() > 0 &&
- !is_separator(path_utf16[path.size() - 1]) &&
- path_utf16[path.size() - 1] != L':') {
- path_utf16.push_back(L'\\');
- path_utf16.push_back(L'*');
+ if (PathUTF16.size() > 0 &&
+ !is_separator(PathUTF16[Path.size() - 1]) &&
+ PathUTF16[Path.size() - 1] != L':') {
+ PathUTF16.push_back(L'\\');
+ PathUTF16.push_back(L'*');
} else {
- path_utf16.push_back(L'*');
+ PathUTF16.push_back(L'*');
}
// Get the first directory entry.
WIN32_FIND_DATAW FirstFind;
ScopedFindHandle FindHandle(::FindFirstFileExW(
- c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
+ c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
NULL, FIND_FIRST_EX_LARGE_FETCH));
if (!FindHandle)
return mapWindowsError(::GetLastError());
@@ -359,43 +570,45 @@
DWORD LastError = ::GetLastError();
// Check for end.
if (LastError == ERROR_NO_MORE_FILES)
- return detail::directory_iterator_destruct(it);
+ return detail::directory_iterator_destruct(IT);
return mapWindowsError(LastError);
} else
FilenameLen = ::wcslen(FirstFind.cFileName);
// Construct the current directory entry.
- SmallString<128> directory_entry_name_utf8;
- if (std::error_code ec =
+ SmallString<128> DirectoryEntryNameUTF8;
+ if (std::error_code EC =
UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName),
- directory_entry_name_utf8))
- return ec;
+ DirectoryEntryNameUTF8))
+ return EC;
- it.IterationHandle = intptr_t(FindHandle.take());
- SmallString<128> directory_entry_path(path);
- path::append(directory_entry_path, directory_entry_name_utf8);
- it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks,
- status_from_find_data(&FirstFind));
+ IT.IterationHandle = intptr_t(FindHandle.take());
+ SmallString<128> DirectoryEntryPath(Path);
+ path::append(DirectoryEntryPath, DirectoryEntryNameUTF8);
+ IT.CurrentEntry =
+ directory_entry(DirectoryEntryPath, FollowSymlinks,
+ file_type_from_attrs(FirstFind.dwFileAttributes),
+ status_from_find_data(&FirstFind));
return std::error_code();
}
-std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
- if (it.IterationHandle != 0)
+std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) {
+ if (IT.IterationHandle != 0)
// Closes the handle if it's valid.
- ScopedFindHandle close(HANDLE(it.IterationHandle));
- it.IterationHandle = 0;
- it.CurrentEntry = directory_entry();
+ ScopedFindHandle close(HANDLE(IT.IterationHandle));
+ IT.IterationHandle = 0;
+ IT.CurrentEntry = directory_entry();
return std::error_code();
}
-std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) {
WIN32_FIND_DATAW FindData;
- if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+ if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) {
DWORD LastError = ::GetLastError();
// Check for end.
if (LastError == ERROR_NO_MORE_FILES)
- return detail::directory_iterator_destruct(it);
+ return detail::directory_iterator_destruct(IT);
return mapWindowsError(LastError);
}
@@ -403,16 +616,18 @@
if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
(FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
FindData.cFileName[1] == L'.'))
- return directory_iterator_increment(it);
+ return directory_iterator_increment(IT);
- SmallString<128> directory_entry_path_utf8;
- if (std::error_code ec =
+ SmallString<128> DirectoryEntryPathUTF8;
+ if (std::error_code EC =
UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName),
- directory_entry_path_utf8))
- return ec;
+ DirectoryEntryPathUTF8))
+ return EC;
- it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8),
- status_from_find_data(&FindData));
+ IT.CurrentEntry.replace_filename(
+ Twine(DirectoryEntryPathUTF8),
+ file_type_from_attrs(FindData.dwFileAttributes),
+ status_from_find_data(&FindData));
return std::error_code();
}
@@ -420,18 +635,82 @@
return Status;
}
-std::error_code openFileForRead(const Twine &Name, int &ResultFD,
- SmallVectorImpl<char> *RealPath) {
- ResultFD = -1;
- SmallVector<wchar_t, 128> PathUTF16;
+static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD,
+ OpenFlags Flags) {
+ int CrtOpenFlags = 0;
+ if (Flags & OF_Append)
+ CrtOpenFlags |= _O_APPEND;
+ if (Flags & OF_Text)
+ CrtOpenFlags |= _O_TEXT;
+
+ ResultFD = -1;
+ if (!H)
+ return errorToErrorCode(H.takeError());
+
+ ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags);
+ if (ResultFD == -1) {
+ ::CloseHandle(*H);
+ return mapWindowsError(ERROR_INVALID_HANDLE);
+ }
+ return std::error_code();
+}
+
+static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) {
+ // This is a compatibility hack. Really we should respect the creation
+ // disposition, but a lot of old code relied on the implicit assumption that
+ // OF_Append implied it would open an existing file. Since the disposition is
+ // now explicit and defaults to CD_CreateAlways, this assumption would cause
+ // any usage of OF_Append to append to a new file, even if the file already
+ // existed. A better solution might have two new creation dispositions:
+ // CD_AppendAlways and CD_AppendNew. This would also address the problem of
+ // OF_Append being used on a read-only descriptor, which doesn't make sense.
+ if (Flags & OF_Append)
+ return OPEN_ALWAYS;
+
+ switch (Disp) {
+ case CD_CreateAlways:
+ return CREATE_ALWAYS;
+ case CD_CreateNew:
+ return CREATE_NEW;
+ case CD_OpenAlways:
+ return OPEN_ALWAYS;
+ case CD_OpenExisting:
+ return OPEN_EXISTING;
+ }
+ wpi_unreachable("unreachable!");
+}
+
+static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) {
+ DWORD Result = 0;
+ if (Access & FA_Read)
+ Result |= GENERIC_READ;
+ if (Access & FA_Write)
+ Result |= GENERIC_WRITE;
+ if (Flags & OF_Delete)
+ Result |= DELETE;
+ if (Flags & OF_UpdateAtime)
+ Result |= FILE_WRITE_ATTRIBUTES;
+ return Result;
+}
+
+static std::error_code openNativeFileInternal(const Twine &Name,
+ file_t &ResultFile, DWORD Disp,
+ DWORD Access, DWORD Flags,
+ bool Inherit = false) {
+ SmallVector<wchar_t, 128> PathUTF16;
if (std::error_code EC = widenPath(Name, PathUTF16))
return EC;
+ SECURITY_ATTRIBUTES SA;
+ SA.nLength = sizeof(SA);
+ SA.lpSecurityDescriptor = nullptr;
+ SA.bInheritHandle = Inherit;
+
HANDLE H =
- ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ ::CreateFileW(PathUTF16.begin(), Access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA,
+ Disp, Flags, NULL);
if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError();
std::error_code EC = mapWindowsError(LastError);
@@ -441,98 +720,102 @@
if (LastError != ERROR_ACCESS_DENIED)
return EC;
if (is_directory(Name))
- return std::make_error_code(std::errc::is_a_directory);
+ return make_error_code(errc::is_a_directory);
return EC;
}
+ ResultFile = H;
+ return std::error_code();
+}
- ResultFD = ::_open_osfhandle(intptr_t(H), 0);
- if (ResultFD == -1) {
- ::CloseHandle(H);
- return mapWindowsError(ERROR_INVALID_HANDLE);
- }
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode) {
+ // Verify that we don't have both "append" and "excl".
+ assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) &&
+ "Cannot specify both 'CreateNew' and 'Append' file creation flags!");
- // Fetch the real name of the file, if the user asked
- if (RealPath) {
- RealPath->clear();
- wchar_t RealPathUTF16[MAX_PATH];
- DWORD CountChars =
- ::GetFinalPathNameByHandleW(H, RealPathUTF16, MAX_PATH,
- FILE_NAME_NORMALIZED);
- if (CountChars > 0 && CountChars < MAX_PATH) {
- // Convert the result from UTF-16 to UTF-8.
- SmallString<MAX_PATH> RealPathUTF8;
- if (!UTF16ToUTF8(RealPathUTF16, CountChars, RealPathUTF8))
- RealPath->append(RealPathUTF8.data(),
- RealPathUTF8.data() + strlen(RealPathUTF8.data()));
+ DWORD NativeDisp = nativeDisposition(Disp, Flags);
+ DWORD NativeAccess = nativeAccess(Access, Flags);
+
+ bool Inherit = false;
+ if (Flags & OF_ChildInherit)
+ Inherit = true;
+
+ file_t Result;
+ std::error_code EC = openNativeFileInternal(
+ Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit);
+ if (EC)
+ return errorCodeToError(EC);
+
+ if (Flags & OF_UpdateAtime) {
+ FILETIME FileTime;
+ SYSTEMTIME SystemTime;
+ GetSystemTime(&SystemTime);
+ if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 ||
+ SetFileTime(Result, NULL, &FileTime, NULL) == 0) {
+ DWORD LastError = ::GetLastError();
+ ::CloseHandle(Result);
+ return errorCodeToError(mapWindowsError(LastError));
}
}
- return std::error_code();
+ if (Flags & OF_Delete) {
+ if ((EC = setDeleteDisposition(Result, true))) {
+ ::CloseHandle(Result);
+ return errorCodeToError(EC);
+ }
+ }
+ return Result;
}
-std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
- OpenFlags Flags, unsigned Mode) {
- // Verify that we don't have both "append" and "excl".
- assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
- "Cannot specify both 'excl' and 'append' file creation flags!");
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned int Mode) {
+ Expected<file_t> Result = openNativeFile(Name, Disp, Access, Flags);
+ if (!Result)
+ return errorToErrorCode(Result.takeError());
- ResultFD = -1;
- SmallVector<wchar_t, 128> PathUTF16;
-
- if (std::error_code EC = widenPath(Name, PathUTF16))
- return EC;
-
- DWORD CreationDisposition;
- if (Flags & F_Excl)
- CreationDisposition = CREATE_NEW;
- else if ((Flags & F_Append) || (Flags & F_NoTrunc))
- CreationDisposition = OPEN_ALWAYS;
- else
- CreationDisposition = CREATE_ALWAYS;
-
- DWORD Access = GENERIC_WRITE;
- DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
- if (Flags & F_RW)
- Access |= GENERIC_READ;
- if (Flags & F_Delete) {
- Access |= DELETE;
- Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
- }
-
- HANDLE H =
- ::CreateFileW(PathUTF16.data(), Access,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, CreationDisposition, Attributes, NULL);
-
- if (H == INVALID_HANDLE_VALUE) {
- DWORD LastError = ::GetLastError();
- std::error_code EC = mapWindowsError(LastError);
- // Provide a better error message when trying to open directories.
- // This only runs if we failed to open the file, so there is probably
- // no performances issues.
- if (LastError != ERROR_ACCESS_DENIED)
- return EC;
- if (is_directory(Name))
- return std::make_error_code(std::errc::is_a_directory);
- return EC;
- }
-
- int OpenFlags = 0;
- if (Flags & F_Append)
- OpenFlags |= _O_APPEND;
-
- if (Flags & F_Text)
- OpenFlags |= _O_TEXT;
-
- ResultFD = ::_open_osfhandle(intptr_t(H), OpenFlags);
- if (ResultFD == -1) {
- ::CloseHandle(H);
- return mapWindowsError(ERROR_INVALID_HANDLE);
- }
-
- return std::error_code();
+ return nativeFileToFd(*Result, ResultFD, Flags);
}
+static std::error_code directoryRealPath(const Twine &Name,
+ SmallVectorImpl<char> &RealPath) {
+ file_t File;
+ std::error_code EC = openNativeFileInternal(
+ Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS);
+ if (EC)
+ return EC;
+
+ EC = realPathFromHandle(File, RealPath);
+ ::CloseHandle(File);
+ return EC;
+}
+
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ Expected<HANDLE> NativeFile = openNativeFileForRead(Name, Flags, RealPath);
+ return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None);
+}
+
+Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags,
+ SmallVectorImpl<char> *RealPath) {
+ Expected<file_t> Result =
+ openNativeFile(Name, CD_OpenExisting, FA_Read, Flags);
+
+ // Fetch the real name of the file, if the user asked
+ if (Result && RealPath)
+ realPathFromHandle(*Result, *RealPath);
+
+ return Result;
+}
+
+void closeFile(file_t &F) {
+ ::CloseHandle(F);
+ F = kInvalidFile;
+}
+
+
} // end namespace fs
namespace path {
@@ -547,10 +830,6 @@
return ok;
}
-bool getUserCacheDir(SmallVectorImpl<char> &Result) {
- return getKnownFolderPath(FOLDERID_LocalAppData, Result);
-}
-
bool home_directory(SmallVectorImpl<char> &result) {
return getKnownFolderPath(FOLDERID_Profile, result);
}
@@ -686,3 +965,7 @@
} // end namespace windows
} // end namespace sys
} // end namespace wpi
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h b/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
index 2f78a4e..d830e33 100644
--- a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
+++ b/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
@@ -38,11 +38,40 @@
#include "wpi/StringExtras.h"
#include "wpi/StringRef.h"
#include "wpi/Twine.h"
+#include "wpi/Chrono.h"
#include "wpi/Compiler.h"
+#include "wpi/VersionTuple.h"
#include <cassert>
#include <string>
#include <system_error>
+#define WIN32_NO_STATUS
#include <windows.h>
+#undef WIN32_NO_STATUS
+#include <winternl.h>
+#include <ntstatus.h>
+
+namespace wpi {
+
+/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
+/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
+/// GetVersionEx is deprecated, but this API exposes the build number which can
+/// be useful for working around certain kernel bugs.
+inline wpi::VersionTuple GetWindowsOSVersion() {
+ typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+ HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+ if (hMod) {
+ auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion");
+ if (getVer) {
+ RTL_OSVERSIONINFOEXW info{};
+ info.dwOSVersionInfoSize = sizeof(info);
+ if (getVer((PRTL_OSVERSIONINFOW)&info) == ((NTSTATUS)0x00000000L)) {
+ return wpi::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0,
+ info.dwBuildNumber);
+ }
+ }
+ }
+ return wpi::VersionTuple(0, 0, 0, 0);
+}
/// Determines if the program is running on Windows 8 or newer. This
/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
@@ -50,20 +79,7 @@
/// yet have VersionHelpers.h, so we have our own helper.
inline bool RunningWindows8OrGreater() {
// Windows 8 is version 6.2, service pack 0.
- OSVERSIONINFOEXW osvi = {};
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- osvi.dwMajorVersion = 6;
- osvi.dwMinorVersion = 2;
- osvi.wServicePackMajor = 0;
-
- DWORDLONG Mask = 0;
- Mask = VerSetConditionMask(Mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
- Mask = VerSetConditionMask(Mask, VER_MINORVERSION, VER_GREATER_EQUAL);
- Mask = VerSetConditionMask(Mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-
- return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION |
- VER_SERVICEPACKMAJOR,
- Mask) != FALSE;
+ return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
}
inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
@@ -90,8 +106,8 @@
typedef typename HandleTraits::handle_type handle_type;
handle_type Handle;
- ScopedHandle(const ScopedHandle &other); // = delete;
- void operator=(const ScopedHandle &other); // = delete;
+ ScopedHandle(const ScopedHandle &other) = delete;
+ void operator=(const ScopedHandle &other) = delete;
public:
ScopedHandle()
: Handle(HandleTraits::GetInvalid()) {}
@@ -179,7 +195,6 @@
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
-namespace wpi {
template <class T>
class SmallVectorImpl;
@@ -192,21 +207,39 @@
}
namespace sys {
-namespace path {
-std::error_code widenPath(const Twine &Path8,
- SmallVectorImpl<wchar_t> &Path16);
-} // end namespace path
-namespace windows {
-std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
-/// Convert to UTF16 from the current code page used in the system
-std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
-std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8);
-/// Convert from UTF16 to the current code page used in the system
-std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8);
-} // end namespace windows
+inline std::chrono::nanoseconds toDuration(FILETIME Time) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.LowPart = Time.dwLowDateTime;
+ TimeInteger.HighPart = Time.dwHighDateTime;
+
+ // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+ return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
+}
+
+inline TimePoint<> toTimePoint(FILETIME Time) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.LowPart = Time.dwLowDateTime;
+ TimeInteger.HighPart = Time.dwHighDateTime;
+
+ // Adjust for different epoch
+ TimeInteger.QuadPart -= 11644473600ll * 10000000;
+
+ // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+ return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
+}
+
+inline FILETIME toFILETIME(TimePoint<> TP) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
+ TimeInteger.QuadPart += 11644473600ll * 10000000;
+
+ FILETIME Time;
+ Time.dwLowDateTime = TimeInteger.LowPart;
+ Time.dwHighDateTime = TimeInteger.HighPart;
+ return Time;
+}
+
} // end namespace sys
} // end namespace wpi.
diff --git a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp b/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
index 04bae65..9f2942c 100644
--- a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
+++ b/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
@@ -11,12 +11,17 @@
//
//===----------------------------------------------------------------------===//
+#ifdef _WIN32
+#define _CRT_NONSTDC_NO_WARNINGS
+#endif
+
#include "wpi/raw_ostream.h"
#include "wpi/STLExtras.h"
#include "wpi/SmallString.h"
#include "wpi/SmallVector.h"
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
+#include "wpi/ErrorHandling.h"
#include "wpi/FileSystem.h"
#include "wpi/Format.h"
#include "wpi/MathExtras.h"
@@ -56,6 +61,7 @@
#endif
#ifdef _WIN32
+#include "wpi/ConvertUTF.h"
#include "Windows/WindowsSupport.h"
#endif
@@ -149,7 +155,7 @@
*this << '\\' << '"';
break;
default:
- if (std::isprint(c)) {
+ if (isPrint(c)) {
*this << c;
break;
}
@@ -335,7 +341,7 @@
break;
}
default:
- assert(false && "Bad Justification");
+ wpi_unreachable("Bad Justification");
}
return *this;
}
@@ -419,7 +425,7 @@
// Print the ASCII char values for each byte on this line
for (uint8_t Byte : Line) {
- if (isprint(Byte))
+ if (isPrint(Byte))
*this << static_cast<char>(Byte);
else
*this << '.';
@@ -481,14 +487,18 @@
//===----------------------------------------------------------------------===//
static int getFD(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
sys::fs::OpenFlags Flags) {
+ assert((Access & sys::fs::FA_Write) &&
+ "Cannot make a raw_ostream from a read-only descriptor!");
+
// Handle "-" as stdout. Note that when we do this, we consider ourself
// the owner of stdout and may set the "binary" flag globally based on Flags.
if (Filename == "-") {
EC = std::error_code();
// If user requested binary then put stdout into binary mode if
// possible.
- if (!(Flags & sys::fs::F_Text)) {
+ if (!(Flags & sys::fs::OF_Text)) {
#if defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY);
#endif
@@ -497,16 +507,39 @@
}
int FD;
- EC = sys::fs::openFileForWrite(Filename, FD, Flags);
+ if (Access & sys::fs::FA_Read)
+ EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags);
+ else
+ EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags);
if (EC)
return -1;
return FD;
}
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+ sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp)
+ : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::FileAccess Access)
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access,
+ sys::fs::OF_None) {}
+
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
sys::fs::OpenFlags Flags)
- : raw_fd_ostream(getFD(Filename, EC, Flags), true) {}
+ : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
+ Flags) {}
+
+raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp,
+ sys::fs::FileAccess Access,
+ sys::fs::OpenFlags Flags)
+ : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
/// closes the file when the stream is destroyed.
@@ -526,6 +559,12 @@
if (FD <= STDERR_FILENO)
ShouldClose = false;
+#ifdef _WIN32
+ // Check if this is a console device. This is not equivalent to isatty.
+ IsWindowsConsole =
+ ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
+#endif
+
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
#ifdef _WIN32
@@ -554,27 +593,87 @@
// on FD == 2.
if (FD == 2) return;
#endif
+
+ // If there are any pending errors, report them now. Clients wishing
+ // to avoid report_fatal_error calls should check for errors with
+ // has_error() and clear the error flag with clear_error() before
+ // destructing raw_ostream objects which may have errors.
+ if (has_error())
+ report_fatal_error("IO failure on output stream: " + error().message(),
+ /*GenCrashDiag=*/false);
}
+#if defined(_WIN32)
+// The most reliable way to print unicode in a Windows console is with
+// WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This
+// assumes that LLVM programs always print valid UTF-8 to the console. The data
+// might not be UTF-8 for two major reasons:
+// 1. The program is printing binary (-filetype=obj -o -), in which case it
+// would have been gibberish anyway.
+// 2. The program is printing text in a semi-ascii compatible codepage like
+// shift-jis or cp1252.
+//
+// Most LLVM programs don't produce non-ascii text unless they are quoting
+// user source input. A well-behaved LLVM program should either validate that
+// the input is UTF-8 or transcode from the local codepage to UTF-8 before
+// quoting it. If they don't, this may mess up the encoding, but this is still
+// probably the best compromise we can make.
+static bool write_console_impl(int FD, StringRef Data) {
+ SmallVector<wchar_t, 256> WideText;
+
+ // Fall back to ::write if it wasn't valid UTF-8.
+ if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText))
+ return false;
+
+ // On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data
+ // that can be written to the console at a time.
+ size_t MaxWriteSize = WideText.size();
+ if (!RunningWindows8OrGreater())
+ MaxWriteSize = 32767;
+
+ size_t WCharsWritten = 0;
+ do {
+ size_t WCharsToWrite =
+ std::min(MaxWriteSize, WideText.size() - WCharsWritten);
+ DWORD ActuallyWritten;
+ bool Success =
+ ::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten],
+ WCharsToWrite, &ActuallyWritten,
+ /*Reserved=*/nullptr);
+
+ // The most likely reason for WriteConsoleW to fail is that FD no longer
+ // points to a console. Fall back to ::write. If this isn't the first loop
+ // iteration, something is truly wrong.
+ if (!Success)
+ return false;
+
+ WCharsWritten += ActuallyWritten;
+ } while (WCharsWritten != WideText.size());
+ return true;
+}
+#endif
+
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
assert(FD >= 0 && "File already closed.");
pos += Size;
- // The maximum write size is limited to SSIZE_MAX because a write
- // greater than SSIZE_MAX is implementation-defined in POSIX.
- // Since SSIZE_MAX is not portable, we use SIZE_MAX >> 1 instead.
- size_t MaxWriteSize = SIZE_MAX >> 1;
+#if defined(_WIN32)
+ // If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
+ // and using WriteConsoleW. If that fails, fall back to plain write().
+ if (IsWindowsConsole)
+ if (write_console_impl(FD, StringRef(Ptr, Size)))
+ return;
+#endif
+
+ // The maximum write size is limited to INT32_MAX. A write
+ // greater than SSIZE_MAX is implementation-defined in POSIX,
+ // and Windows _write requires 32 bit input.
+ size_t MaxWriteSize = INT32_MAX;
#if defined(__linux__)
// It is observed that Linux returns EINVAL for a very large write (>2G).
// Make it a reasonably small value.
MaxWriteSize = 1024 * 1024 * 1024;
-#elif defined(_WIN32)
- // Writing a large size of output to Windows console returns ENOMEM. It seems
- // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and
- // the latter has a size limit (66000 bytes or less, depending on heap usage).
- if (::_isatty(FD) && !RunningWindows8OrGreater())
- MaxWriteSize = 32767;
#endif
do {
@@ -645,8 +744,17 @@
}
size_t raw_fd_ostream::preferred_buffer_size() const {
-#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__minix)
- // Windows and Minix have no st_blksize.
+#if defined(_WIN32)
+ // Disable buffering for console devices. Console output is re-encoded from
+ // UTF-8 to UTF-16 on Windows, and buffering it would require us to split the
+ // buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled
+ // below on most other OSs, so do the same thing on Windows and avoid that
+ // complexity.
+ if (IsWindowsConsole)
+ return 0;
+ return raw_ostream::preferred_buffer_size();
+#elif !defined(__minix)
+ // Minix has no st_blksize.
assert(FD >= 0 && "File not yet open!");
struct stat statbuf;
if (fstat(FD, &statbuf) != 0)
@@ -791,3 +899,5 @@
uint64_t /*Offset*/) {}
void raw_pwrite_stream::anchor() {}
+
+void buffer_ostream::anchor() {}
diff --git a/wpiutil/src/main/native/cpp/memory.cpp b/wpiutil/src/main/native/cpp/memory.cpp
deleted file mode 100644
index 54e55c9..0000000
--- a/wpiutil/src/main/native/cpp/memory.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
-/* Open Source Software - may be modified and shared by FRC teams. The code */
-/* must be accompanied by the FIRST BSD license file in the root directory of */
-/* the project. */
-/*----------------------------------------------------------------------------*/
-
-#include "wpi/memory.h"
-
-#include <exception>
-
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-void* CheckedCalloc(size_t num, size_t size) {
- void* p = std::calloc(num, size);
- if (!p) {
- errs() << "FATAL: failed to allocate " << (num * size) << " bytes\n";
- std::terminate();
- }
- return p;
-}
-
-void* CheckedMalloc(size_t size) {
- void* p = std::malloc(size == 0 ? 1 : size);
- if (!p) {
- errs() << "FATAL: failed to allocate " << size << " bytes\n";
- std::terminate();
- }
- return p;
-}
-
-void* CheckedRealloc(void* ptr, size_t size) {
- void* p = std::realloc(ptr, size == 0 ? 1 : size);
- if (!p) {
- errs() << "FATAL: failed to allocate " << size << " bytes\n";
- std::terminate();
- }
- return p;
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/raw_istream.cpp b/wpiutil/src/main/native/cpp/raw_istream.cpp
index bdfb2bb..f63c217 100644
--- a/wpiutil/src/main/native/cpp/raw_istream.cpp
+++ b/wpiutil/src/main/native/cpp/raw_istream.cpp
@@ -1,10 +1,12 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
+#define _CRT_NONSTDC_NO_WARNINGS
+
#include "wpi/raw_istream.h"
#ifdef _WIN32
diff --git a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp b/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
index 317de41..8fc103d 100644
--- a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
+++ b/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -23,7 +23,7 @@
assert(m_left != 0);
}
- size_t amt = std::min(m_left, len);
+ size_t amt = (std::min)(m_left, len);
auto& buf = m_bufs.back();
std::memcpy(buf.base + buf.len, data, amt);
data += amt;
diff --git a/wpiutil/src/main/native/cpp/uv/Pipe.cpp b/wpiutil/src/main/native/cpp/uv/Pipe.cpp
index 8d4ee76..9db879a 100644
--- a/wpiutil/src/main/native/cpp/uv/Pipe.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Pipe.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/wpiutil/src/main/native/cpp/uv/Timer.cpp b/wpiutil/src/main/native/cpp/uv/Timer.cpp
index 4825ea3..749d9a8 100644
--- a/wpiutil/src/main/native/cpp/uv/Timer.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Timer.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -26,7 +26,7 @@
void Timer::SingleShot(Loop& loop, Time timeout, std::function<void()> func) {
auto h = Create(loop);
if (!h) return;
- h->timeout.connect([ theTimer = h.get(), func ]() {
+ h->timeout.connect([theTimer = h.get(), func]() {
func();
theTimer->Close();
});
diff --git a/wpiutil/src/main/native/cpp/uv/Udp.cpp b/wpiutil/src/main/native/cpp/uv/Udp.cpp
index cc7208d..2c0d29f 100644
--- a/wpiutil/src/main/native/cpp/uv/Udp.cpp
+++ b/wpiutil/src/main/native/cpp/uv/Udp.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -69,6 +69,33 @@
Bind(reinterpret_cast<const sockaddr&>(addr), flags);
}
+void Udp::Connect(const Twine& ip, unsigned int port) {
+ sockaddr_in addr;
+ int err = NameToAddr(ip, port, &addr);
+ if (err < 0)
+ ReportError(err);
+ else
+ Connect(reinterpret_cast<const sockaddr&>(addr));
+}
+
+void Udp::Connect6(const Twine& ip, unsigned int port) {
+ sockaddr_in6 addr;
+ int err = NameToAddr(ip, port, &addr);
+ if (err < 0)
+ ReportError(err);
+ else
+ Connect(reinterpret_cast<const sockaddr&>(addr));
+}
+
+sockaddr_storage Udp::GetPeer() {
+ sockaddr_storage name;
+ int len = sizeof(name);
+ if (!Invoke(&uv_udp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
+ &len))
+ std::memset(&name, 0, sizeof(name));
+ return name;
+}
+
sockaddr_storage Udp::GetSock() {
sockaddr_storage name;
int len = sizeof(name);
@@ -111,6 +138,22 @@
Send(addr, bufs, std::make_shared<CallbackUdpSendReq>(bufs, callback));
}
+void Udp::Send(ArrayRef<Buffer> bufs, const std::shared_ptr<UdpSendReq>& req) {
+ if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(),
+ nullptr, [](uv_udp_send_t* r, int status) {
+ auto& h = *static_cast<UdpSendReq*>(r->data);
+ if (status < 0) h.ReportError(status);
+ h.complete(Error(status));
+ h.Release(); // this is always a one-shot
+ }))
+ req->Keep();
+}
+
+void Udp::Send(ArrayRef<Buffer> bufs,
+ std::function<void(MutableArrayRef<Buffer>, Error)> callback) {
+ Send(bufs, std::make_shared<CallbackUdpSendReq>(bufs, callback));
+}
+
void Udp::StartRecv() {
Invoke(&uv_udp_recv_start, GetRaw(), &AllocBuf,
[](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,