From a8661b593132e3a0febb191072834bee39f5b14f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 18 Dec 2019 16:49:04 +0100 Subject: [PATCH 01/34] increment version number to 0.21.18 --- NEWS | 2 ++ android/AndroidManifest.xml | 4 ++-- doc/conf.py | 2 +- meson.build | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index a597a4b82..1c514b8dc 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +ver 0.21.18 (not yet released) + ver 0.21.17 (2019/12/16) * protocol - relax the ISO 8601 parser: allow omitting field separators, the diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 80fa55394..5b9f57b60 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="41" + android:versionName="0.21.18"> diff --git a/doc/conf.py b/doc/conf.py index 4fb8560fa..c494a9cf2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -38,7 +38,7 @@ author = 'Max Kellermann' # built documents. # # The short X.Y version. -version = '0.21.17' +version = '0.21.18' # The full version, including alpha/beta/rc tags. release = version diff --git a/meson.build b/meson.build index 93952164d..597989b0a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'mpd', ['c', 'cpp'], - version: '0.21.17', + version: '0.21.18', meson_version: '>= 0.49.0', default_options: [ 'c_std=c99', From 732bdc800d33e9d5fc78af4463da844309e7a312 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 18 Dec 2019 17:46:33 +0100 Subject: [PATCH 02/34] event/SocketMonitor: Schedule() returns bool --- src/event/SocketMonitor.cxx | 16 ++++++++++------ src/event/SocketMonitor.hxx | 14 +++++++++----- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx index 64cc42820..f335c8fdc 100644 --- a/src/event/SocketMonitor.cxx +++ b/src/event/SocketMonitor.cxx @@ -68,20 +68,24 @@ SocketMonitor::Close() noexcept Steal().Close(); } -void +bool SocketMonitor::Schedule(unsigned flags) noexcept { assert(IsDefined()); if (flags == GetScheduledFlags()) - return; + return true; + bool success; if (scheduled_flags == 0) - loop.AddFD(fd.Get(), flags, *this); + success = loop.AddFD(fd.Get(), flags, *this); else if (flags == 0) - loop.RemoveFD(fd.Get(), *this); + success = loop.RemoveFD(fd.Get(), *this); else - loop.ModifyFD(fd.Get(), flags, *this); + success = loop.ModifyFD(fd.Get(), flags, *this); - scheduled_flags = flags; + if (success) + scheduled_flags = flags; + + return success; } diff --git a/src/event/SocketMonitor.hxx b/src/event/SocketMonitor.hxx index df80ced04..1d8814cc5 100644 --- a/src/event/SocketMonitor.hxx +++ b/src/event/SocketMonitor.hxx @@ -98,18 +98,22 @@ public: return scheduled_flags; } - void Schedule(unsigned flags) noexcept; + /** + * @return true on success, false on error (with errno set if + * USE_EPOLL is defined) + */ + bool Schedule(unsigned flags) noexcept; void Cancel() noexcept { Schedule(0); } - void ScheduleRead() noexcept { - Schedule(GetScheduledFlags() | READ | HANGUP | ERROR); + bool ScheduleRead() noexcept { + return Schedule(GetScheduledFlags() | READ | HANGUP | ERROR); } - void ScheduleWrite() noexcept { - Schedule(GetScheduledFlags() | WRITE); + bool ScheduleWrite() noexcept { + return Schedule(GetScheduledFlags() | WRITE); } void CancelRead() noexcept { From a84bf5a92ede3fe38e9b3fc2882d7080d59c13b1 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 18 Dec 2019 17:50:21 +0100 Subject: [PATCH 03/34] event/MultiSocketMonitor: AddSocket() returns bool --- src/event/MultiSocketMonitor.hxx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index eff82bbdf..c4bad8ac0 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -50,12 +50,10 @@ class MultiSocketMonitor : IdleMonitor unsigned revents; public: - SingleFD(MultiSocketMonitor &_multi, SocketDescriptor _fd, - unsigned events) noexcept + SingleFD(MultiSocketMonitor &_multi, + SocketDescriptor _fd) noexcept :SocketMonitor(_fd, _multi.GetEventLoop()), - multi(_multi), revents(0) { - Schedule(events); - } + multi(_multi), revents(0) {} SocketDescriptor GetSocket() const noexcept { return SocketMonitor::GetSocket(); @@ -147,8 +145,14 @@ public: * * May only be called from PrepareSockets(). */ - void AddSocket(SocketDescriptor fd, unsigned events) noexcept { - fds.emplace_front(*this, fd, events); + bool AddSocket(SocketDescriptor fd, unsigned events) noexcept { + fds.emplace_front(*this, fd); + bool success = fds.front().Schedule(events); + if (!success) { + fds.pop_front(); + } + + return success; } /** From e3b347820aef0bd495eb37df3e1d6caa4f5c10de Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 20 Dec 2019 13:42:35 +0100 Subject: [PATCH 04/34] event/MultiSocketMonitor: use std::exchange() --- src/event/MultiSocketMonitor.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx index b3cd8675c..f747fd0f9 100644 --- a/src/event/MultiSocketMonitor.cxx +++ b/src/event/MultiSocketMonitor.cxx @@ -64,9 +64,7 @@ MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept if (i == end) return 0; - auto events = i->events; - i->events = 0; - return events; + return std::exchange(i->events, 0); }); for (auto i = pfds; i != end; ++i) From dcbb9fe07ce0c48ffaf6300167eb74276d129136 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 22 Dec 2019 11:58:15 +0100 Subject: [PATCH 05/34] event/Loop: round timeout up to avoid unnecessary wakeups --- NEWS | 1 + src/event/Loop.cxx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1c514b8dc..169a9610b 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,5 @@ ver 0.21.18 (not yet released) +* reduce unnecessary CPU wakeups ver 0.21.17 (2019/12/16) * protocol diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index 644cacc39..d3de427c9 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -137,7 +137,8 @@ static constexpr int ExportTimeoutMS(std::chrono::steady_clock::duration timeout) { return timeout >= timeout.zero() - ? int(std::chrono::duration_cast(timeout).count()) + /* round up (+1) to avoid unnecessary wakeups */ + ? int(std::chrono::duration_cast(timeout).count()) + 1 : -1; } From 7764719513b02149e8b101b298462a98de70fbbe Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 22 Dec 2019 12:00:12 +0100 Subject: [PATCH 06/34] event/MultiSocketMonitor: un-inline AddSocket() --- src/event/MultiSocketMonitor.cxx | 12 ++++++++++++ src/event/MultiSocketMonitor.hxx | 10 +--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx index f747fd0f9..98d57332c 100644 --- a/src/event/MultiSocketMonitor.cxx +++ b/src/event/MultiSocketMonitor.cxx @@ -42,6 +42,18 @@ MultiSocketMonitor::Reset() noexcept ready = refresh = false; } +bool +MultiSocketMonitor::AddSocket(SocketDescriptor fd, unsigned events) noexcept +{ + fds.emplace_front(*this, fd); + bool success = fds.front().Schedule(events); + if (!success) { + fds.pop_front(); + } + + return success; +} + void MultiSocketMonitor::ClearSocketList() noexcept { diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index c4bad8ac0..c1d363a29 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -145,15 +145,7 @@ public: * * May only be called from PrepareSockets(). */ - bool AddSocket(SocketDescriptor fd, unsigned events) noexcept { - fds.emplace_front(*this, fd); - bool success = fds.front().Schedule(events); - if (!success) { - fds.pop_front(); - } - - return success; - } + bool AddSocket(SocketDescriptor fd, unsigned events) noexcept; /** * Remove all sockets. From 9be3a1554e56cb23dd298dee29d9b9706ccfc0c5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 22 Dec 2019 12:08:04 +0100 Subject: [PATCH 07/34] event/MultiSocketMonitor: remove duplicate IdleMonitor::Schedule() call SetReady() does this already. --- src/event/MultiSocketMonitor.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index c1d363a29..1ce2373d3 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -228,7 +228,6 @@ private: void OnTimeout() noexcept { SetReady(); - IdleMonitor::Schedule(); } virtual void OnIdle() noexcept final; From d75a0d714ec966e63f75c9e81bd82dfae10d84a0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 22 Dec 2019 12:02:37 +0100 Subject: [PATCH 08/34] event/MultiSocketMonitor: remove unnecessary `friend` declaration --- src/event/MultiSocketMonitor.hxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index 1ce2373d3..11308d505 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -84,8 +84,6 @@ class MultiSocketMonitor : IdleMonitor } }; - friend class SingleFD; - TimerEvent timeout_event; /** From 9a577f8060413f7d5d2b557f7067dad4bceeeb36 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 20 Dec 2019 13:54:16 +0100 Subject: [PATCH 09/34] event/MultiSocketMonitor: add workaround for /dev/null The ALSA "null" driver opens /dev/null and returns the file handle from snd_pcm_poll_descriptors(), but /dev/null cannot be used with epoll, the epoll_ctl() system call returns -EPERM. This means that the ALSA output hangs, eventually freezing the whole MPD process. This commit adds a workaround to the MultiSocketMonitor class which is used by the ALSA output plugin. Closes https://github.com/MusicPlayerDaemon/MPD/issues/695 --- NEWS | 2 ++ src/event/MultiSocketMonitor.cxx | 36 +++++++++++++++++++++++++++++++- src/event/MultiSocketMonitor.hxx | 20 ++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 169a9610b..7804e0d20 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.21.18 (not yet released) +* output + - alsa: fix hang bug with ALSA "null" outputs * reduce unnecessary CPU wakeups ver 0.21.17 (2019/12/16) diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx index 98d57332c..7704bd8e8 100644 --- a/src/event/MultiSocketMonitor.cxx +++ b/src/event/MultiSocketMonitor.cxx @@ -22,6 +22,10 @@ #include +#ifdef USE_EPOLL +#include +#endif + #ifndef _WIN32 #include #endif @@ -37,6 +41,9 @@ MultiSocketMonitor::Reset() noexcept assert(GetEventLoop().IsInside()); fds.clear(); +#ifdef USE_EPOLL + always_ready_fds.clear(); +#endif IdleMonitor::Cancel(); timeout_event.Cancel(); ready = refresh = false; @@ -49,6 +56,13 @@ MultiSocketMonitor::AddSocket(SocketDescriptor fd, unsigned events) noexcept bool success = fds.front().Schedule(events); if (!success) { fds.pop_front(); + +#ifdef USE_EPOLL + if (errno == EPERM) + /* not supported by epoll (e.g. "/dev/null"): + add it to the "always ready" list */ + always_ready_fds.push_front({fd, events}); +#endif } return success; @@ -60,6 +74,9 @@ MultiSocketMonitor::ClearSocketList() noexcept assert(GetEventLoop().IsInside()); fds.clear(); +#ifdef USE_EPOLL + always_ready_fds.clear(); +#endif } #ifndef _WIN32 @@ -67,6 +84,10 @@ MultiSocketMonitor::ClearSocketList() noexcept void MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept { +#ifdef USE_EPOLL + always_ready_fds.clear(); +#endif + pollfd *const end = pfds + n; UpdateSocketList([pfds, end](SocketDescriptor fd) -> unsigned { @@ -89,7 +110,20 @@ MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept void MultiSocketMonitor::Prepare() noexcept { - const auto timeout = PrepareSockets(); + auto timeout = PrepareSockets(); + +#ifdef USE_EPOLL + if (!always_ready_fds.empty()) { + /* if there was at least one file descriptor not + supported by epoll, install a very short timeout + because we assume it's always ready */ + constexpr std::chrono::steady_clock::duration ready_timeout = + std::chrono::milliseconds(1); + if (timeout < timeout.zero() || timeout > ready_timeout) + timeout = ready_timeout; + } +#endif + if (timeout >= timeout.zero()) timeout_event.Schedule(timeout); else diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx index 11308d505..04f3bee8a 100644 --- a/src/event/MultiSocketMonitor.hxx +++ b/src/event/MultiSocketMonitor.hxx @@ -102,6 +102,21 @@ class MultiSocketMonitor : IdleMonitor std::forward_list fds; +#ifdef USE_EPOLL + struct AlwaysReady { + const SocketDescriptor fd; + const unsigned revents; + }; + + /** + * A list of file descriptors which are always ready. This is + * a kludge needed because the ALSA output plugin gives us a + * file descriptor to /dev/null, which is incompatible with + * epoll (epoll_ctl() returns -EPERM). + */ + std::forward_list always_ready_fds; +#endif + public: static constexpr unsigned READ = SocketMonitor::READ; static constexpr unsigned WRITE = SocketMonitor::WRITE; @@ -198,6 +213,11 @@ public: i.ClearReturnedEvents(); } } + +#ifdef USE_EPOLL + for (const auto &i : always_ready_fds) + f(i.fd, i.revents); +#endif } protected: From 7bfe6a33043fee920703a06ff0b38d049b4b4647 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 22 Dec 2019 19:54:31 +0100 Subject: [PATCH 10/34] test/run_storage: add command "stat" --- test/run_storage.cxx | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/run_storage.cxx b/test/run_storage.cxx index 9db2215f4..e668c7347 100644 --- a/test/run_storage.cxx +++ b/test/run_storage.cxx @@ -90,6 +90,29 @@ Ls(Storage &storage, const char *path) return EXIT_SUCCESS; } +static int +Stat(Storage &storage, const char *path) +{ + const auto info = storage.GetInfo(path, false); + switch (info.type) { + case StorageFileInfo::Type::OTHER: + printf("other\n"); + break; + + case StorageFileInfo::Type::REGULAR: + printf("regular\n"); + break; + + case StorageFileInfo::Type::DIRECTORY: + printf("directory\n"); + break; + } + + printf("size: %llu\n", (unsigned long long)info.size); + + return EXIT_SUCCESS; +} + int main(int argc, char **argv) try { @@ -117,6 +140,18 @@ try { storage_uri); return Ls(*storage, path); + } else if (strcmp(command, "stat") == 0) { + if (argc != 4) { + fprintf(stderr, "Usage: run_storage stat URI PATH\n"); + return EXIT_FAILURE; + } + + const char *const path = argv[3]; + + auto storage = MakeStorage(io_thread.GetEventLoop(), + storage_uri); + + return Stat(*storage, path); } else { fprintf(stderr, "Unknown command\n"); return EXIT_FAILURE; From d01fb6730a7ac889f104490022c9dbb581e45db2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 13:37:58 +0100 Subject: [PATCH 11/34] storage/curl: move start call out of the constructor This can cause request completion in the I/O thread before this constructor returns, leaving the object in an abstract state, causing a crash due to pure virtual method call. We should not start the request until this object is fully constructed. Closes https://github.com/MusicPlayerDaemon/MPD/issues/665 --- NEWS | 2 ++ src/storage/plugins/CurlStorage.cxx | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 7804e0d20..3e48c90e6 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ ver 0.21.18 (not yet released) * output - alsa: fix hang bug with ALSA "null" outputs +* storage + - curl: fix crash bug * reduce unnecessary CPU wakeups ver 0.21.17 (2019/12/16) diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index b4e73ba0a..5417dae29 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -109,7 +109,9 @@ public: BIND_THIS_METHOD(OnDeferredStart)), request(curl, uri, *this) { // TODO: use CurlInputStream's configuration + } + void DeferStart() noexcept { /* start the transfer inside the IOThread */ defer_start.Schedule(); } @@ -283,6 +285,7 @@ public: } using BlockingHttpRequest::GetEasy; + using BlockingHttpRequest::DeferStart; using BlockingHttpRequest::Wait; protected: @@ -430,6 +433,7 @@ public: } const StorageFileInfo &Perform() { + DeferStart(); Wait(); return info; } @@ -481,6 +485,7 @@ public: base_path(UriPathOrSlash(uri)) {} std::unique_ptr Perform() { + DeferStart(); Wait(); return ToReader(); } From f1116c92582637918d5de31ac33cde8256401dc2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 14:19:58 +0100 Subject: [PATCH 12/34] event/Loop: remove bogus assertion Can fail if somebody calls Break(). --- src/event/Loop.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx index d3de427c9..196d7475d 100644 --- a/src/event/Loop.cxx +++ b/src/event/Loop.cxx @@ -221,7 +221,6 @@ EventLoop::Run() noexcept } while (!quit); #ifndef NDEBUG - assert(busy); assert(thread.IsInside()); #endif } From 087874620f5f9dfe7f71c7afaf2193ec34ccee0b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 14:15:18 +0100 Subject: [PATCH 13/34] test/RunCurl: new debug program --- test/RunCurl.cxx | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 12 +++++++ 2 files changed, 105 insertions(+) create mode 100644 test/RunCurl.cxx diff --git a/test/RunCurl.cxx b/test/RunCurl.cxx new file mode 100644 index 000000000..c8ca25909 --- /dev/null +++ b/test/RunCurl.cxx @@ -0,0 +1,93 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "ShutdownHandler.hxx" +#include "lib/curl/Global.hxx" +#include "lib/curl/Request.hxx" +#include "lib/curl/Handler.hxx" +#include "event/Loop.hxx" +#include "util/PrintException.hxx" + +#include + +class MyHandler final : public CurlResponseHandler { + EventLoop &event_loop; + + std::exception_ptr error; + +public: + explicit MyHandler(EventLoop &_event_loop) noexcept + :event_loop(_event_loop) {} + + void Finish() { + if (error) + std::rethrow_exception(error); + } + + /* virtual methods from CurlResponseHandler */ + void OnHeaders(unsigned status, + std::multimap &&headers) override { + fprintf(stderr, "status: %u\n", status); + for (const auto &i : headers) + fprintf(stderr, "%s: %s\n", + i.first.c_str(), i.second.c_str()); + } + + void OnData(ConstBuffer data) override { + if (fwrite(data.data, data.size, 1, stdout) != 1) + throw std::runtime_error("Failed to write"); + } + + void OnEnd() override { + event_loop.Break(); + } + + void OnError(std::exception_ptr e) noexcept override { + error = std::move(e); + event_loop.Break(); + } +}; + +int +main(int argc, char **argv) noexcept +try { + if (argc != 2) { + fprintf(stderr, "Usage: RunCurl URI\n"); + return EXIT_FAILURE; + } + + const char *const uri = argv[1]; + + EventLoop event_loop; + const ShutdownHandler shutdown_handler(event_loop); + CurlGlobal curl_global(event_loop); + + MyHandler handler(event_loop); + CurlRequest request(curl_global, uri, handler); + request.Start(); + + event_loop.Run(); + + handler.Finish(); + + return EXIT_SUCCESS; +} catch (...) { + PrintException(std::current_exception()); + return EXIT_FAILURE; +} diff --git a/test/meson.build b/test/meson.build index dab10ecb2..0c7371e89 100644 --- a/test/meson.build +++ b/test/meson.build @@ -334,6 +334,18 @@ executable( ) if curl_dep.found() + executable( + 'RunCurl', + 'RunCurl.cxx', + 'ShutdownHandler.cxx', + '../src/Log.cxx', + '../src/LogBackend.cxx', + include_directories: inc, + dependencies: [ + curl_dep, + ], + ) + test('test_icy_parser', executable( 'test_icy_parser', 'test_icy_parser.cxx', From a714bdb0ce3ad43b827f0ffba009606bee1a6cdb Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 14:41:06 +0100 Subject: [PATCH 14/34] lib/curl: drop support for CURL versions older than 7.32.0 For simplicity, this commit removes a workaround for an old CURL bug. --- NEWS | 1 + src/lib/curl/Global.hxx | 10 ---------- src/lib/curl/Request.cxx | 7 ------- src/lib/curl/meson.build | 2 +- 4 files changed, 2 insertions(+), 18 deletions(-) diff --git a/NEWS b/NEWS index 3e48c90e6..516148047 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.21.18 (not yet released) - alsa: fix hang bug with ALSA "null" outputs * storage - curl: fix crash bug +* drop support for CURL versions older than 7.32.0 * reduce unnecessary CPU wakeups ver 0.21.17 (2019/12/16) diff --git a/src/lib/curl/Global.hxx b/src/lib/curl/Global.hxx index d2866c3e9..0a8067fa2 100644 --- a/src/lib/curl/Global.hxx +++ b/src/lib/curl/Global.hxx @@ -74,16 +74,6 @@ public: SocketAction(CURL_SOCKET_TIMEOUT, 0); } - /** - * This is a kludge to allow pausing/resuming a stream with - * libcurl < 7.32.0. Read the curl_easy_pause manpage for - * more information. - */ - void ResumeSockets() { - int running_handles; - curl_multi_socket_all(multi.Get(), &running_handles); - } - private: void UpdateTimeout(long timeout_ms) noexcept; static int TimerFunction(CURLM *global, long timeout_ms, diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 7714712fd..a72fde549 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -30,7 +30,6 @@ #include "config.h" #include "Request.hxx" #include "Global.hxx" -#include "Version.hxx" #include "Handler.hxx" #include "event/Call.hxx" #include "util/RuntimeError.hxx" @@ -124,12 +123,6 @@ CurlRequest::Resume() noexcept curl_easy_pause(easy.Get(), CURLPAUSE_CONT); - if (IsCurlOlderThan(0x072000)) - /* libcurl older than 7.32.0 does not update - its sockets after curl_easy_pause(); force - libcurl to do it now */ - global.ResumeSockets(); - global.InvalidateSockets(); } diff --git a/src/lib/curl/meson.build b/src/lib/curl/meson.build index 4d9f534e9..b6d015d14 100644 --- a/src/lib/curl/meson.build +++ b/src/lib/curl/meson.build @@ -1,4 +1,4 @@ -curl_dep = dependency('libcurl', version: '>= 7.18', required: get_option('curl')) +curl_dep = dependency('libcurl', version: '>= 7.32', required: get_option('curl')) conf.set('ENABLE_CURL', curl_dep.found()) if not curl_dep.found() subdir_done() From 4475b8ca04b2798519d0f6eb68913c55cf3d1846 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 14:50:51 +0100 Subject: [PATCH 15/34] lib/curl/Global: remove lower bound on timeouts This was a problem 9 years ago, and apparently, it has been fixed long ago. --- src/lib/curl/Global.cxx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/lib/curl/Global.cxx b/src/lib/curl/Global.cxx index 6f213c20d..f44b942af 100644 --- a/src/lib/curl/Global.cxx +++ b/src/lib/curl/Global.cxx @@ -227,13 +227,6 @@ CurlGlobal::UpdateTimeout(long timeout_ms) noexcept return; } - if (timeout_ms < 10) - /* CURL 7.21.1 likes to report "timeout=0", which - means we're running in a busy loop. Quite a bad - idea to waste so much CPU. Let's use a lower limit - of 10ms. */ - timeout_ms = 10; - timeout_event.Schedule(std::chrono::milliseconds(timeout_ms)); } From fe598e7d30d82794560df053623a16fee8d3fb9c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 14:27:48 +0100 Subject: [PATCH 16/34] lib/curl/Global: remove InvalidateSockets() call from Remove() curl_multi_remove_handle() calls our socket function, and there's no need to call curl_multi_socket_action(). --- src/lib/curl/Global.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/curl/Global.cxx b/src/lib/curl/Global.cxx index f44b942af..4acb16fe6 100644 --- a/src/lib/curl/Global.cxx +++ b/src/lib/curl/Global.cxx @@ -181,8 +181,6 @@ CurlGlobal::Remove(CURL *easy) noexcept assert(easy != nullptr); curl_multi_remove_handle(multi.Get(), easy); - - InvalidateSockets(); } static CurlRequest * From a1afe9afc6879960389491b6fb587f14ae1ae5df Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:47:01 +0100 Subject: [PATCH 17/34] util/Compiler.h: add gcc_fallthrough Works around build failures with ccache which may feed processed code to GCC, which doesn't have the "fall through" code comments. --- src/player/Thread.cxx | 2 ++ src/util/Compiler.h | 6 ++++++ src/util/format.c | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index 05e691bd1..64a502e6d 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -46,6 +46,7 @@ #include "CrossFade.hxx" #include "tag/Tag.hxx" #include "Idle.hxx" +#include "util/Compiler.h" #include "util/Domain.hxx" #include "thread/Name.hxx" #include "Log.hxx" @@ -1171,6 +1172,7 @@ try { } /* fall through */ + gcc_fallthrough; case PlayerCommand::PAUSE: next_song.reset(); diff --git a/src/util/Compiler.h b/src/util/Compiler.h index 6a64ad098..a97b34529 100644 --- a/src/util/Compiler.h +++ b/src/util/Compiler.h @@ -143,6 +143,12 @@ #define gcc_flatten #endif +#if CLANG_OR_GCC_VERSION(7,0) +#define gcc_fallthrough __attribute__((fallthrough)) +#else +#define gcc_fallthrough +#endif + #ifndef __cplusplus /* plain C99 has "restrict" */ #define gcc_restrict restrict diff --git a/src/util/format.c b/src/util/format.c index 62099b32e..10b53c771 100644 --- a/src/util/format.c +++ b/src/util/format.c @@ -19,6 +19,7 @@ */ #include "format.h" +#include "util/Compiler.h" #include #include @@ -238,6 +239,7 @@ format_object2(const char *format, const char **last, const void *object, } /* fall through */ + gcc_fallthrough; default: /* pass-through non-escaped portions of the format string */ From 80fe88e8f65ef275de047505a7f944226495e7b7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:27:18 +0100 Subject: [PATCH 18/34] .travis.yml: enable ccache on osx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99df7d698..722457d8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,7 @@ matrix: - os: osx osx_image: xcode9.3beta env: - - MATRIX_EVAL="" + - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH" cache: - apt From 5ff786e59c9bcfcf9b58f2398a052e149b845640 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:32:44 +0100 Subject: [PATCH 19/34] .travis.yml: enable ccache on Linux --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 722457d8d..c5f3a3eeb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ matrix: - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson env: # use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068 - - MATRIX_EVAL="export CC=gcc-6 CXX=g++-6 LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" + - MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" - os: linux dist: trusty @@ -50,7 +50,7 @@ matrix: - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson env: # use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068 - - MATRIX_EVAL="export CC=gcc-8 CXX=g++-8 LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" + - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" - os: osx osx_image: xcode9.3beta From 816ef12088587174315c50e98c0cce7716e04e47 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:58:08 +0100 Subject: [PATCH 20/34] .travis.yml: add Ubuntu Bionic build --- .travis.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.travis.yml b/.travis.yml index c5f3a3eeb..8aaa876e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,28 @@ language: cpp matrix: include: + # Ubuntu Bionic (18.04) with GCC 7 + - os: linux + dist: bionic + addons: + apt: + sources: + - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) + packages: + - libgtest-dev + - libboost-dev + - python3.6 + - python3-urllib3 + - ninja-build + before_install: + - wget https://bootstrap.pypa.io/get-pip.py + - /usr/bin/python3.6 get-pip.py --user + install: + - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson + env: + - MATRIX_EVAL="export PATH=$HOME/.local/bin:$PATH" + + # Ubuntu Trusty (16.04) with GCC 6 - os: linux dist: trusty addons: @@ -27,6 +49,7 @@ matrix: # use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068 - MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" + # Ubuntu Trusty (16.04) with GCC 8 - os: linux dist: trusty addons: From fa50cdb39e7b8b9b82fc239495967232870a6386 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 07:08:54 +0100 Subject: [PATCH 21/34] .travis.yml: escape dollar signs in MATRIX_EVAL Expand $PATH at evaluation and not at assignment, which fixes the problem that /usr/lib/ccache was added to $PATH between the MATRIX_EVAL assignment and its evaluation. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8aaa876e6..c0bbb7c00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ matrix: install: - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson env: - - MATRIX_EVAL="export PATH=$HOME/.local/bin:$PATH" + - MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH" # Ubuntu Trusty (16.04) with GCC 6 - os: linux @@ -47,7 +47,7 @@ matrix: - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson env: # use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068 - - MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" + - MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH" # Ubuntu Trusty (16.04) with GCC 8 - os: linux @@ -73,7 +73,7 @@ matrix: - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson env: # use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068 - - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH" + - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH" - os: osx osx_image: xcode9.3beta From 7770298a65e4c08eea1645abb121731867414488 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 06:39:53 +0100 Subject: [PATCH 22/34] util/Compiler.h: use `[[fallthrough]]` on clang Older clang versions don't support the GCC __attribute__ syntax. For those, don't use anything at all, and new clang versions shall use the standard syntax. --- src/util/Compiler.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/Compiler.h b/src/util/Compiler.h index a97b34529..96f63fae4 100644 --- a/src/util/Compiler.h +++ b/src/util/Compiler.h @@ -143,8 +143,10 @@ #define gcc_flatten #endif -#if CLANG_OR_GCC_VERSION(7,0) +#if GCC_CHECK_VERSION(7,0) #define gcc_fallthrough __attribute__((fallthrough)) +#elif CLANG_CHECK_VERSION(10,0) +#define gcc_fallthrough [[fallthrough]] #else #define gcc_fallthrough #endif From 2bc127bb4336d1de047cca57b07865ed1e53f967 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:06:15 +0100 Subject: [PATCH 23/34] time/ISO8601: move code to ParseTimeOfDay() --- src/time/ISO8601.cxx | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index 5cb4c486c..42bba021f 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -108,6 +108,30 @@ ParseTimeZoneOffset(const char *&s) return d; } +static const char * +ParseTimeOfDay(const char *s, struct tm &tm, + std::chrono::system_clock::duration &precision) noexcept +{ + const char *end; + + if ((end = strptime(s, "%T", &tm)) != nullptr) + precision = std::chrono::seconds(1); + else if ((end = strptime(s, "%H%M%S", &tm)) != nullptr) + /* no field separators */ + precision = std::chrono::seconds(1); + else if ((end = strptime(s, "%H%M", &tm)) != nullptr) + /* no field separators */ + precision = std::chrono::minutes(1); + else if ((end = strptime(s, "%H:%M", &tm)) != nullptr) + precision = std::chrono::minutes(1); + else if ((end = strptime(s, "%H", &tm)) != nullptr) + precision = std::chrono::hours(1); + else + return nullptr; + + return end; +} + std::pair ParseISO8601(const char *s) @@ -138,22 +162,9 @@ ParseISO8601(const char *s) if (*s == 'T') { ++s; - if ((end = strptime(s, "%T", &tm)) != nullptr) - precision = std::chrono::seconds(1); - else if ((end = strptime(s, "%H%M%S", &tm)) != nullptr) - /* no field separators */ - precision = std::chrono::seconds(1); - else if ((end = strptime(s, "%H%M", &tm)) != nullptr) - /* no field separators */ - precision = std::chrono::minutes(1); - else if ((end = strptime(s, "%H:%M", &tm)) != nullptr) - precision = std::chrono::minutes(1); - else if ((end = strptime(s, "%H", &tm)) != nullptr) - precision = std::chrono::hours(1); - else + s = ParseTimeOfDay(s, tm, precision); + if (s == nullptr) throw std::runtime_error("Failed to parse time of day"); - - s = end; } auto tp = TimeGm(tm); From 744bd1eadc0567563fc551ebb4f237134a51f905 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:12:17 +0100 Subject: [PATCH 24/34] time/ISO8601: refactor ParseTimeOfDay() to parse one by one This prepares the migration away from strptime() for Windows portability. But the real reason I'm doing this is that strptime() on Apple is buggy: strptime("14", "%H%M%S") (without separating colons) succeeds even though only the hour has been parsed. This fixes recent Travis failures in the ParseISO8601() unit test. --- NEWS | 2 ++ src/time/ISO8601.cxx | 65 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 516148047..048a9972e 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.21.18 (not yet released) +* protocol + - work around Mac OS X bug in the ISO 8601 parser * output - alsa: fix hang bug with ALSA "null" outputs * storage diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index 42bba021f..32527d053 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -112,23 +112,58 @@ static const char * ParseTimeOfDay(const char *s, struct tm &tm, std::chrono::system_clock::duration &precision) noexcept { - const char *end; + /* this function always checks "end==s" to work around a + strptime() bug on OS X: if nothing could be parsed, + strptime() returns the input string (indicating success) + instead of nullptr (indicating error) */ - if ((end = strptime(s, "%T", &tm)) != nullptr) - precision = std::chrono::seconds(1); - else if ((end = strptime(s, "%H%M%S", &tm)) != nullptr) - /* no field separators */ - precision = std::chrono::seconds(1); - else if ((end = strptime(s, "%H%M", &tm)) != nullptr) - /* no field separators */ - precision = std::chrono::minutes(1); - else if ((end = strptime(s, "%H:%M", &tm)) != nullptr) - precision = std::chrono::minutes(1); - else if ((end = strptime(s, "%H", &tm)) != nullptr) - precision = std::chrono::hours(1); - else - return nullptr; + const char *end = strptime(s, "%H", &tm); + if (end == nullptr || end == s) + return end; + s = end; + precision = std::chrono::hours(1); + + if (*s == ':') { + /* with field separators: now a minute must follow */ + + ++s; + + end = strptime(s, "%M", &tm); + if (end == nullptr || end == s) + return nullptr; + + s = end; + precision = std::chrono::minutes(1); + + /* the "seconds" field is optional */ + if (*s != ':') + return s; + + ++s; + + end = strptime(s, "%S", &tm); + if (end == nullptr || end == s) + return nullptr; + + precision = std::chrono::seconds(1); + return end; + } + + /* without field separators */ + + end = strptime(s, "%M", &tm); + if (end == nullptr || end == s) + return s; + + s = end; + precision = std::chrono::minutes(1); + + end = strptime(s, "%S", &tm); + if (end == nullptr || end == s) + return s; + + precision = std::chrono::seconds(1); return end; } From 568402584701e1c257d068524b9a81abe28c4447 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 10:17:35 +0100 Subject: [PATCH 25/34] .travis.yml: change "cache" yaml syntax --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c0bbb7c00..ebf733c5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,8 +81,8 @@ matrix: - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH" cache: - - apt - - ccache + apt: true + ccache: true before_install: - eval "${MATRIX_EVAL}" From 76cd5f8595d2fb63575142e38453c3e973eb281f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:32:19 +0100 Subject: [PATCH 26/34] .travis.yml: cache Homebrew on osx --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index ebf733c5f..a84a6bdd9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -83,6 +83,11 @@ matrix: cache: apt: true ccache: true + directories: + - $HOME/Library/Caches/Homebrew + +before_cache: + - test "$TRAVIS_OS_NAME" != "osx" || brew cleanup before_install: - eval "${MATRIX_EVAL}" From 256753ea46141ac4390b88a693cf857ea0a3d431 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 08:10:19 +0100 Subject: [PATCH 27/34] .travis.yml: disable Homebrew analytics Don't bother sending analytics data for a CI runner. This adds traffic but doesn't bring anybody any benefit. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a84a6bdd9..ad4acb8ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,7 +78,7 @@ matrix: - os: osx osx_image: xcode9.3beta env: - - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH" + - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1" cache: apt: true From 3401d26d4c4c5e3a2cdfcce2b0102603fa2a7f74 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 23 Dec 2019 17:27:40 +0100 Subject: [PATCH 28/34] .travis.yml: switch to xcode9.4, the current default --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ad4acb8ee..ed28ddbac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,7 +76,7 @@ matrix: - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH" - os: osx - osx_image: xcode9.3beta + osx_image: xcode9.4 env: - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1" @@ -96,6 +96,11 @@ before_install: install: # C++14 + + # Work around "Target /usr/local/lib/libgtest.a is a symlink + # belonging to nss. You can unlink it" during gtest install + - test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss + - test "$TRAVIS_OS_NAME" != "osx" || brew install ccache meson - test "$TRAVIS_OS_NAME" != "osx" || brew install --HEAD https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb From 23fcfdbd2af9e86d00be99d0030b1348faa00cbf Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 11:18:34 +0100 Subject: [PATCH 29/34] .travis.yml: remove "brew update" The packages from the Travis image are good enough, and this speeds up the Travis build. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed28ddbac..106be0019 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,8 +91,6 @@ before_cache: before_install: - eval "${MATRIX_EVAL}" - # C++14 - - test "$TRAVIS_OS_NAME" != "osx" || brew update install: # C++14 From 9ef1f10319257bfc725097cfc92a6b0db0578830 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 11:18:08 +0100 Subject: [PATCH 30/34] .travis.yml: install brew packages using `addons/homebrew` --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 106be0019..bcf1e5b9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -77,6 +77,11 @@ matrix: - os: osx osx_image: xcode9.4 + addons: + homebrew: + packages: + - ccache + - meson env: - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1" @@ -99,7 +104,6 @@ install: # belonging to nss. You can unlink it" during gtest install - test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss - - test "$TRAVIS_OS_NAME" != "osx" || brew install ccache meson - test "$TRAVIS_OS_NAME" != "osx" || brew install --HEAD https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb before_script: From 0dffe05bf7849b440695e2e92e4fb26b5bc32469 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 11:41:52 +0100 Subject: [PATCH 31/34] input/curl: remove unnecessary InvalidateSockets() call Like fe598e7d30d82794560df053623a16fee8d3fb9c --- src/input/plugins/CurlInputPlugin.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index b16f1eb84..71161c770 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -180,7 +180,6 @@ CurlInputStream::FreeEasyIndirect() noexcept { BlockingCall(GetEventLoop(), [this](){ FreeEasy(); - (*curl_init)->InvalidateSockets(); }); } From 6d54928d7c0aac758f3eddfe82169e27109a6255 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 16:07:33 +0100 Subject: [PATCH 32/34] Revert "lib/curl/Global: remove lower bound on timeouts" This reverts commit 4475b8ca04b2798519d0f6eb68913c55cf3d1846. Further testing revealed that the threaded resolver still uses a timeout of 0ms. This revert however lowers the bound to a minimum of 1ms instead of 10ms. --- src/lib/curl/Global.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/curl/Global.cxx b/src/lib/curl/Global.cxx index 4acb16fe6..0cd8b533d 100644 --- a/src/lib/curl/Global.cxx +++ b/src/lib/curl/Global.cxx @@ -225,6 +225,13 @@ CurlGlobal::UpdateTimeout(long timeout_ms) noexcept return; } + if (timeout_ms < 1) + /* CURL's threaded resolver sets a timeout of 0ms, which + means we're running in a busy loop. Quite a bad + idea to waste so much CPU. Let's use a lower limit + of 1ms. */ + timeout_ms = 1; + timeout_event.Schedule(std::chrono::milliseconds(timeout_ms)); } From d27e534a852f9fa934420b1079763c5d2e6e5977 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 16:12:52 +0100 Subject: [PATCH 33/34] time/ISO8601: fix Windows build failure Caused by 2bc127bb4336d1de047cca57b07865ed1e53f967 --- src/time/ISO8601.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx index 32527d053..725215ea6 100644 --- a/src/time/ISO8601.cxx +++ b/src/time/ISO8601.cxx @@ -58,6 +58,8 @@ FormatISO8601(std::chrono::system_clock::time_point tp) return FormatISO8601(GmTime(tp)); } +#ifndef _WIN32 + static std::pair ParseTimeZoneOffsetRaw(const char *&s) { @@ -167,6 +169,8 @@ ParseTimeOfDay(const char *s, struct tm &tm, return end; } +#endif + std::pair ParseISO8601(const char *s) From bf41d1ad2bed5cb0b7b64b0cf4f87688da43d62c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 24 Dec 2019 16:13:16 +0100 Subject: [PATCH 34/34] release v0.21.18 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 048a9972e..cdcad0de0 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.21.18 (not yet released) +ver 0.21.18 (2019/12/24) * protocol - work around Mac OS X bug in the ISO 8601 parser * output