Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f33d2fb2e7 | ||
![]() |
a9eec35aff | ||
![]() |
8534f2d1e2 | ||
![]() |
00740fb23b | ||
![]() |
37e9010887 | ||
![]() |
4bd2c75056 | ||
![]() |
b9ed850b98 | ||
![]() |
11cea17496 | ||
![]() |
163597ef69 | ||
![]() |
95f84afd33 | ||
![]() |
9f7fd1fbfb | ||
![]() |
940cab8620 | ||
![]() |
5b84c99d79 | ||
![]() |
b295024574 | ||
![]() |
34180f1745 | ||
![]() |
665031467a | ||
![]() |
df33171107 | ||
![]() |
53f4044890 | ||
![]() |
a5049136ff | ||
![]() |
705b3c6b63 | ||
![]() |
6b4ac66962 | ||
![]() |
0964b06240 | ||
![]() |
92eeca3ba7 | ||
![]() |
2a86554ac4 | ||
![]() |
805caa30ce | ||
![]() |
a56949e9fa | ||
![]() |
43da4c0eca | ||
![]() |
b9c7771830 | ||
![]() |
35db88affe | ||
![]() |
e38faca455 | ||
![]() |
0255e8710c | ||
![]() |
6d89020f80 | ||
![]() |
9c56c49e73 | ||
![]() |
acb798e544 | ||
![]() |
c5720a15c7 | ||
![]() |
90709b332a | ||
![]() |
81f17d10c8 | ||
![]() |
773de38bd9 | ||
![]() |
a48704925d | ||
![]() |
fa4beeee75 | ||
![]() |
d8351772d3 | ||
![]() |
68d1abdb85 | ||
![]() |
7e8474a85a | ||
![]() |
82da364b8b | ||
![]() |
7fa91ec175 | ||
![]() |
1d3a09d377 | ||
![]() |
02563a35f0 | ||
![]() |
d653f35bb7 | ||
![]() |
a543627abd | ||
![]() |
80f2ba7fca | ||
![]() |
32bca64920 | ||
![]() |
7fa1a84ec3 | ||
![]() |
ab4bb26a0a | ||
![]() |
4b8d258cff | ||
![]() |
3c29aa6271 | ||
![]() |
51464b4317 | ||
![]() |
2fec463542 | ||
![]() |
1affc641c4 | ||
![]() |
0cfd4fff62 | ||
![]() |
8904127c10 |
NEWS
android
configure.acdoc
src
Compiler.hIdle.cxxLogBackend.cxxLogInit.cxxSongFilter.cxxSongLoader.cxx
db
plugins
decoder
event
filter
plugins
fs
input
lib
output
plugins
pcm
playlist
storage
plugins
tag
thread
util
34
NEWS
34
NEWS
@@ -1,3 +1,28 @@
|
||||
ver 0.19.8 (2015/01/14)
|
||||
* input
|
||||
- curl: fix bug after rewinding from end-of-file
|
||||
- mms: reduce delay at the beginning of playback
|
||||
* decoder
|
||||
- dsdiff, dsf: allow ID3 tags larger than 4 kB
|
||||
- ffmpeg: support interleaved floating point
|
||||
* fix clang 3.6 warnings
|
||||
* fix build failure on NetBSD
|
||||
|
||||
ver 0.19.7 (2014/12/17)
|
||||
* input
|
||||
- nfs: fix crash while canceling a failing file open operation
|
||||
- nfs: fix memory leak on connection failure
|
||||
- nfs: fix reconnect after mount failure
|
||||
- nfs: implement mount timeout (60 seconds)
|
||||
* storage
|
||||
- nfs: implement I/O timeout (60 seconds)
|
||||
* playlist
|
||||
- embcue: fix filename suffix detection
|
||||
- don't skip non-existent songs in "listplaylist"
|
||||
* decoder
|
||||
- ffmpeg: fix time stamp underflow
|
||||
* fix memory allocator bug on Windows
|
||||
|
||||
ver 0.19.6 (2014/12/08)
|
||||
* decoder
|
||||
- ffmpeg: support FFmpeg 2.5
|
||||
@@ -146,6 +171,15 @@ ver 0.19 (2014/10/10)
|
||||
* install systemd unit for socket activation
|
||||
* Android port
|
||||
|
||||
ver 0.18.22 (2014/01/14)
|
||||
* fix clang 3.6 warnings
|
||||
|
||||
ver 0.18.21 (2014/12/17)
|
||||
* playlist
|
||||
- embcue: fix filename suffix detection
|
||||
* decoder
|
||||
- ffmpeg: fix time stamp underflow
|
||||
|
||||
ver 0.18.20 (2014/12/08)
|
||||
* decoder
|
||||
- ffmpeg: support FFmpeg 2.5
|
||||
|
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="10"
|
||||
android:versionName="0.19.6">
|
||||
android:versionCode="12"
|
||||
android:versionName="0.19.8">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>
|
||||
|
||||
|
@@ -23,7 +23,7 @@ if not os.path.isdir(ndk_path):
|
||||
sys.exit(1)
|
||||
|
||||
# the path to the MPD sources
|
||||
mpd_path = os.path.dirname(os.path.dirname(sys.argv[0]))
|
||||
mpd_path = os.path.dirname(os.path.dirname(sys.argv[0])) or '.'
|
||||
|
||||
# output directories
|
||||
lib_path = os.path.abspath('lib')
|
||||
|
@@ -1,10 +1,10 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.19.6, musicpd-dev-team@lists.sourceforge.net)
|
||||
AC_INIT(mpd, 0.19.8, musicpd-dev-team@lists.sourceforge.net)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=19
|
||||
VERSION_REVISION=6
|
||||
VERSION_REVISION=8
|
||||
VERSION_EXTRA=0
|
||||
|
||||
AC_CONFIG_SRCDIR([src/Main.cxx])
|
||||
|
10
doc/user.xml
10
doc/user.xml
@@ -89,7 +89,7 @@ cd mpd-version</programlisting>
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
apt-get install g++ automake autoconf \
|
||||
apt-get install g++ \
|
||||
libmad0-dev libmpg123-dev libid3tag0-dev \
|
||||
libflac-dev libvorbis-dev libopus-dev \
|
||||
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
|
||||
@@ -98,19 +98,21 @@ apt-get install g++ automake autoconf \
|
||||
libsidplay2-dev libsidutils-dev libresid-builder-dev \
|
||||
libavcodec-dev libavformat-dev \
|
||||
libmp3lame-dev \
|
||||
libsamplerate0-dev \
|
||||
libsamplerate0-dev libsoxr-dev \
|
||||
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
|
||||
libzzip-dev \
|
||||
libcurl4-gnutls-dev libyajl-dev \
|
||||
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
|
||||
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
|
||||
libpulse-dev libroar-dev libshout3-dev \
|
||||
libmpdclient-dev \
|
||||
libnfs-dev libsmbclient-dev \
|
||||
libupnp-dev \
|
||||
libavahi-client-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-daemon-dev libwrap0-dev \
|
||||
libcppunit-dev xmlto \
|
||||
libboost-dev \
|
||||
libglib2.0-dev
|
||||
libglib2.0-dev libicu-dev
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
|
@@ -20,33 +20,45 @@
|
||||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
|
||||
#define GCC_CHECK_VERSION(major, minor) \
|
||||
(defined(__GNUC__) && \
|
||||
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
|
||||
#define GCC_MAKE_VERSION(major, minor, patchlevel) ((major) * 10000 + (minor) * 100 + patchlevel)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GCC_VERSION (__GNUC__ * 10000 \
|
||||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#define GCC_VERSION GCC_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
#define GCC_VERSION 0
|
||||
#endif
|
||||
|
||||
#define GCC_CHECK_VERSION(major, minor) \
|
||||
(defined(__GNUC__) && GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
/**
|
||||
* Are we building with gcc (not clang or any other compiler) and a
|
||||
* version older than the specified one?
|
||||
*/
|
||||
#define GCC_OLDER_THAN(major, minor) \
|
||||
(defined(__GNUC__) && !defined(__clang__) && \
|
||||
GCC_VERSION < GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
#ifdef __clang__
|
||||
# define CLANG_VERSION (__clang_major__ * 10000 \
|
||||
+ __clang_minor__ * 100 \
|
||||
+ __clang_patchlevel__)
|
||||
# define CLANG_VERSION GCC_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||
# if __clang_major__ < 3
|
||||
# error Sorry, your clang version is too old. You need at least version 3.1.
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if !GCC_CHECK_VERSION(4,6)
|
||||
# if GCC_OLDER_THAN(4,6)
|
||||
# error Sorry, your gcc version is too old. You need at least version 4.6.
|
||||
# endif
|
||||
#else
|
||||
# warning Untested compiler. Use at your own risk!
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Are we building with the specified version of clang or newer?
|
||||
*/
|
||||
#define CLANG_CHECK_VERSION(major, minor) \
|
||||
(defined(__clang__) && \
|
||||
CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
#if GCC_CHECK_VERSION(4,0)
|
||||
|
||||
/* GCC 4.x */
|
||||
@@ -141,7 +153,7 @@
|
||||
#if defined(__cplusplus)
|
||||
|
||||
/* support for C++11 "override" was added in gcc 4.7 */
|
||||
#if !defined(__clang__) && !GCC_CHECK_VERSION(4,7)
|
||||
#if GCC_OLDER_THAN(4,7)
|
||||
#define override
|
||||
#define final
|
||||
#endif
|
||||
|
@@ -76,7 +76,10 @@ idle_get_names(void)
|
||||
unsigned
|
||||
idle_parse_name(const char *name)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(name != nullptr);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
|
||||
if (StringEqualsCaseASCII(name, idle_names[i]))
|
||||
|
@@ -194,6 +194,12 @@ FileLog(const Domain &domain, const char *message)
|
||||
domain.GetName(),
|
||||
chomp_length(message), message);
|
||||
|
||||
#ifdef WIN32
|
||||
/* force-flush the log file, because setvbuf() does not seem
|
||||
to have an effect on WIN32 */
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
g_free(converted);
|
||||
#endif
|
||||
|
@@ -111,6 +111,9 @@ log_early_init(bool verbose)
|
||||
#ifdef ANDROID
|
||||
(void)verbose;
|
||||
#else
|
||||
/* force stderr to be line-buffered */
|
||||
setvbuf(stderr, nullptr, _IOLBF, 0);
|
||||
|
||||
if (verbose)
|
||||
SetLogThreshold(LogLevel::DEBUG);
|
||||
#endif
|
||||
|
@@ -77,7 +77,10 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
|
||||
bool
|
||||
SongFilter::Item::StringMatch(const char *s) const
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(s != nullptr);
|
||||
#endif
|
||||
|
||||
if (fold_case) {
|
||||
const std::string folded = IcuCaseFold(s);
|
||||
|
@@ -77,7 +77,10 @@ SongLoader::LoadFile(const char *path_utf8, Error &error) const
|
||||
DetachedSong *
|
||||
SongLoader::LoadSong(const char *uri_utf8, Error &error) const
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(uri_utf8 != nullptr);
|
||||
#endif
|
||||
|
||||
if (memcmp(uri_utf8, "file:///", 8) == 0)
|
||||
/* absolute path */
|
||||
|
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||
Error &error) const override;
|
||||
virtual void ReturnSong(const LightSong *song) const;
|
||||
void ReturnSong(const LightSong *song) const override;
|
||||
|
||||
virtual bool Visit(const DatabaseSelection &selection,
|
||||
VisitDirectory visit_directory,
|
||||
|
@@ -103,7 +103,7 @@ public:
|
||||
virtual void Close() override;
|
||||
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||
Error &error) const override;
|
||||
virtual void ReturnSong(const LightSong *song) const;
|
||||
void ReturnSong(const LightSong *song) const override;
|
||||
|
||||
virtual bool Visit(const DatabaseSelection &selection,
|
||||
VisitDirectory visit_directory,
|
||||
@@ -731,7 +731,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
|
||||
{
|
||||
// TODO: eliminate the const_cast
|
||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
if (!visit_directory && !visit_playlist && selection.recursive &&
|
||||
(ServerSupportsSearchBase(connection)
|
||||
@@ -757,7 +757,7 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
|
||||
{
|
||||
// TODO: eliminate the const_cast
|
||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
enum mpd_tag_type tag_type2 = Convert(tag_type);
|
||||
if (tag_type2 == MPD_TAG_COUNT) {
|
||||
@@ -810,7 +810,7 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
|
||||
|
||||
// TODO: eliminate the const_cast
|
||||
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
struct mpd_stats *stats2 =
|
||||
mpd_run_stats(connection);
|
||||
|
@@ -435,9 +435,12 @@ SimpleDatabase::Save(Error &error)
|
||||
bool
|
||||
SimpleDatabase::Mount(const char *uri, Database *db, Error &error)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(uri != nullptr);
|
||||
assert(*uri != 0);
|
||||
assert(db != nullptr);
|
||||
#endif
|
||||
assert(*uri != 0);
|
||||
|
||||
ScopeDatabaseLock protect;
|
||||
|
||||
@@ -445,13 +448,13 @@ SimpleDatabase::Mount(const char *uri, Database *db, Error &error)
|
||||
if (r.uri == nullptr) {
|
||||
error.Format(db_domain, DB_CONFLICT,
|
||||
"Already exists: %s", uri);
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strchr(r.uri, '/') != nullptr) {
|
||||
error.Format(db_domain, DB_NOT_FOUND,
|
||||
"Parent not found: %s", uri);
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
Directory *mnt = r.directory->CreateChild(r.uri);
|
||||
@@ -478,7 +481,7 @@ SimpleDatabase::Mount(const char *local_uri, const char *storage_uri,
|
||||
if (cache_path.IsNull()) {
|
||||
error.Format(db_domain, DB_NOT_FOUND,
|
||||
"No 'cache_directory' configured");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name(storage_uri);
|
||||
|
@@ -110,9 +110,9 @@ public:
|
||||
virtual bool Open(Error &error) override;
|
||||
virtual void Close() override;
|
||||
|
||||
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||
Error &error) const override;
|
||||
virtual void ReturnSong(const LightSong *song) const;
|
||||
const LightSong *GetSong(const char *uri_utf8,
|
||||
Error &error) const override;
|
||||
void ReturnSong(const LightSong *song) const override;
|
||||
|
||||
virtual bool Visit(const DatabaseSelection &selection,
|
||||
VisitDirectory visit_directory,
|
||||
|
@@ -85,7 +85,7 @@ public:
|
||||
virtual void Close() override;
|
||||
virtual const LightSong *GetSong(const char *uri_utf8,
|
||||
Error &error) const override;
|
||||
virtual void ReturnSong(const LightSong *song) const;
|
||||
void ReturnSong(const LightSong *song) const override;
|
||||
|
||||
virtual bool Visit(const DatabaseSelection &selection,
|
||||
VisitDirectory visit_directory,
|
||||
@@ -101,7 +101,9 @@ public:
|
||||
virtual bool GetStats(const DatabaseSelection &selection,
|
||||
DatabaseStats &stats,
|
||||
Error &error) const override;
|
||||
virtual time_t GetUpdateStamp() const {return 0;}
|
||||
time_t GetUpdateStamp() const override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
@@ -26,7 +26,10 @@
|
||||
bool
|
||||
DecoderPlugin::SupportsSuffix(const char *suffix) const
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(suffix != nullptr);
|
||||
#endif
|
||||
|
||||
return suffixes != nullptr && string_array_contains(suffixes, suffix);
|
||||
|
||||
@@ -35,7 +38,10 @@ DecoderPlugin::SupportsSuffix(const char *suffix) const
|
||||
bool
|
||||
DecoderPlugin::SupportsMimeType(const char *mime_type) const
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(mime_type != nullptr);
|
||||
#endif
|
||||
|
||||
return mime_types != nullptr &&
|
||||
string_array_contains(mime_types, mime_type);
|
||||
|
@@ -29,8 +29,10 @@
|
||||
#include "input/InputStream.hxx"
|
||||
#include "tag/TagId3.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Alloc.hxx"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_ID3TAG
|
||||
#include <id3tag.h>
|
||||
@@ -123,22 +125,27 @@ dsdlib_tag_id3(InputStream &is,
|
||||
|
||||
const id3_length_t count = size - offset;
|
||||
|
||||
/* Check and limit id3 tag size to prevent a stack overflow */
|
||||
id3_byte_t dsdid3[4096];
|
||||
if (count == 0 || count > sizeof(dsdid3))
|
||||
if (count < 10 || count > 256*1024)
|
||||
return;
|
||||
|
||||
if (!decoder_read_full(nullptr, is, dsdid3, count))
|
||||
return;
|
||||
id3_byte_t *const id3_buf = static_cast<id3_byte_t*>(xalloc(count));
|
||||
|
||||
struct id3_tag *id3_tag = id3_tag_parse(dsdid3, count);
|
||||
if (id3_tag == nullptr)
|
||||
if (!decoder_read_full(nullptr, is, id3_buf, count)) {
|
||||
free(id3_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
struct id3_tag *id3_tag = id3_tag_parse(id3_buf, count);
|
||||
if (id3_tag == nullptr) {
|
||||
free(id3_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
scan_id3_tag(id3_tag, handler, handler_ctx);
|
||||
|
||||
id3_tag_delete(id3_tag);
|
||||
|
||||
free(id3_buf);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@@ -313,10 +313,13 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
|
||||
AVFrame *frame,
|
||||
uint8_t **buffer, int *buffer_size)
|
||||
{
|
||||
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE)
|
||||
decoder_timestamp(decoder,
|
||||
time_from_ffmpeg(packet->pts - start_time_fallback(*stream),
|
||||
stream->time_base));
|
||||
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE) {
|
||||
auto start = start_time_fallback(*stream);
|
||||
if (packet->pts >= start)
|
||||
decoder_timestamp(decoder,
|
||||
time_from_ffmpeg(packet->pts - start,
|
||||
stream->time_base));
|
||||
}
|
||||
|
||||
AVPacket packet2 = *packet;
|
||||
|
||||
@@ -371,6 +374,7 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
|
||||
case AV_SAMPLE_FMT_S32P:
|
||||
return SampleFormat::S32;
|
||||
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
return SampleFormat::FLOAT;
|
||||
|
||||
|
@@ -179,9 +179,10 @@ EventLoop::Run()
|
||||
mutex.lock();
|
||||
HandleDeferred();
|
||||
busy = false;
|
||||
const bool _again = again;
|
||||
mutex.unlock();
|
||||
|
||||
if (again)
|
||||
if (_again)
|
||||
/* re-evaluate timers because one of the
|
||||
IdleMonitors may have added a new
|
||||
timeout */
|
||||
|
@@ -53,10 +53,11 @@ public:
|
||||
children.emplace_back(name, filter);
|
||||
}
|
||||
|
||||
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
virtual void Close();
|
||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error);
|
||||
/* virtual methods from class Filter */
|
||||
AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@@ -34,10 +34,11 @@ class NormalizeFilter final : public Filter {
|
||||
PcmBuffer buffer;
|
||||
|
||||
public:
|
||||
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
virtual void Close();
|
||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
/* virtual methods from class Filter */
|
||||
AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
};
|
||||
|
||||
static Filter *
|
||||
|
@@ -112,10 +112,11 @@ public:
|
||||
*/
|
||||
void Update();
|
||||
|
||||
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
virtual void Close();
|
||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
/* virtual methods from class Filter */
|
||||
AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
};
|
||||
|
||||
void
|
||||
|
@@ -120,10 +120,11 @@ public:
|
||||
*/
|
||||
bool Configure(const config_param ¶m, Error &error);
|
||||
|
||||
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
virtual void Close();
|
||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
/* virtual methods from class Filter */
|
||||
AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
};
|
||||
|
||||
bool
|
||||
|
@@ -43,10 +43,11 @@ public:
|
||||
pv.SetVolume(_volume);
|
||||
}
|
||||
|
||||
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
virtual void Close();
|
||||
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
/* virtual methods from class Filter */
|
||||
AudioFormat Open(AudioFormat &af, Error &error) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
};
|
||||
|
||||
static constexpr Domain volume_domain("pcm_volume");
|
||||
|
@@ -103,7 +103,10 @@ static inline void FixSeparators(std::string &s)
|
||||
std::string
|
||||
PathToUTF8(const char *path_fs)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(path_fs != nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
if (fs_charset.empty()) {
|
||||
@@ -144,7 +147,10 @@ PathToUTF8(const char *path_fs)
|
||||
char *
|
||||
PathFromUTF8(const char *path_utf8)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(path_utf8 != nullptr);
|
||||
#endif
|
||||
|
||||
if (fs_charset.empty())
|
||||
return g_strdup(path_utf8);
|
||||
|
@@ -52,7 +52,10 @@ template<typename Traits>
|
||||
typename Traits::const_pointer
|
||||
GetBasePathImpl(typename Traits::const_pointer p)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
|
||||
return sep != nullptr
|
||||
@@ -64,7 +67,10 @@ template<typename Traits>
|
||||
typename Traits::string
|
||||
GetParentPathImpl(typename Traits::const_pointer p)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
|
||||
if (sep == nullptr)
|
||||
|
@@ -57,7 +57,11 @@ struct PathTraitsFS {
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static const_pointer FindLastSeparator(const_pointer p) {
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
const_pointer pos = p + GetLength(p);
|
||||
while (p != pos && !IsSeparator(*pos))
|
||||
@@ -77,7 +81,11 @@ struct PathTraitsFS {
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static bool IsAbsolute(const_pointer p) {
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
if (IsDrive(p) && IsSeparator(p[2]))
|
||||
return true;
|
||||
@@ -147,7 +155,11 @@ struct PathTraitsUTF8 {
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static const_pointer FindLastSeparator(const_pointer p) {
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
return strrchr(p, SEPARATOR);
|
||||
}
|
||||
|
||||
@@ -160,7 +172,11 @@ struct PathTraitsUTF8 {
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static bool IsAbsolute(const_pointer p) {
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(p != nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
if (IsDrive(p) && IsSeparator(p[2]))
|
||||
return true;
|
||||
|
@@ -160,6 +160,11 @@ AsyncInputStream::SeekDone()
|
||||
assert(io_thread_inside());
|
||||
assert(IsSeekPending());
|
||||
|
||||
/* we may have reached end-of-file previously, and the
|
||||
connection may have been closed already; however after
|
||||
seeking successfully, the connection must be alive again */
|
||||
open = true;
|
||||
|
||||
seek_state = SeekState::NONE;
|
||||
cond.broadcast();
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ input_stream_global_init(Error &error)
|
||||
case InputPlugin::InitResult::UNAVAILABLE:
|
||||
if (error.IsDefined()) {
|
||||
FormatError(error,
|
||||
"Input plugin '%s' is unavailable: ",
|
||||
"Input plugin '%s' is unavailable",
|
||||
plugin->name);
|
||||
error.Clear();
|
||||
}
|
||||
|
@@ -122,7 +122,10 @@ InputStream::IsAvailable()
|
||||
size_t
|
||||
InputStream::LockRead(void *ptr, size_t _size, Error &error)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(ptr != nullptr);
|
||||
#endif
|
||||
assert(_size > 0);
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
|
@@ -43,7 +43,7 @@ protected:
|
||||
virtual size_t ThreadRead(void *ptr, size_t size,
|
||||
Error &error) override;
|
||||
|
||||
virtual void Close() {
|
||||
void Close() override {
|
||||
mmsx_close(mms);
|
||||
}
|
||||
};
|
||||
@@ -92,6 +92,13 @@ input_mms_open(const char *url,
|
||||
size_t
|
||||
MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error)
|
||||
{
|
||||
/* unfortunately, mmsx_read() blocks until the whole buffer
|
||||
has been filled; to avoid big latencies, limit the size of
|
||||
each chunk we read to a reasonable size */
|
||||
constexpr size_t MAX_CHUNK = 16384;
|
||||
if (read_size > MAX_CHUNK)
|
||||
read_size = MAX_CHUNK;
|
||||
|
||||
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
|
||||
if (nbytes <= 0) {
|
||||
if (nbytes < 0)
|
||||
|
@@ -121,8 +121,11 @@ gcc_pure
|
||||
int
|
||||
IcuCollate(const char *a, const char *b)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(a != nullptr);
|
||||
assert(b != nullptr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
assert(collator != nullptr);
|
||||
@@ -159,7 +162,10 @@ IcuCaseFold(const char *src)
|
||||
{
|
||||
#ifdef HAVE_ICU
|
||||
assert(collator != nullptr);
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(src != nullptr);
|
||||
#endif
|
||||
|
||||
const auto u = UCharFromUTF8(src);
|
||||
if (u.IsNull())
|
||||
|
@@ -20,7 +20,9 @@
|
||||
#include "config.h"
|
||||
#include "Blocking.hxx"
|
||||
#include "Connection.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "event/Call.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
bool
|
||||
BlockingNfsOperation::Run(Error &_error)
|
||||
@@ -31,7 +33,10 @@ BlockingNfsOperation::Run(Error &_error)
|
||||
[this](){ connection.AddLease(*this); });
|
||||
|
||||
/* wait for completion */
|
||||
LockWaitFinished();
|
||||
if (!LockWaitFinished()) {
|
||||
_error.Set(nfs_domain, 0, "Timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check for error */
|
||||
if (error.IsDefined()) {
|
||||
|
@@ -35,6 +35,8 @@ class NfsConnection;
|
||||
* thread, and method Run() waits for completion.
|
||||
*/
|
||||
class BlockingNfsOperation : protected NfsCallback, NfsLease {
|
||||
static constexpr unsigned timeout_ms = 60000;
|
||||
|
||||
Mutex mutex;
|
||||
Cond cond;
|
||||
|
||||
@@ -52,10 +54,13 @@ public:
|
||||
bool Run(Error &error);
|
||||
|
||||
private:
|
||||
void LockWaitFinished() {
|
||||
bool LockWaitFinished() {
|
||||
const ScopeLock protect(mutex);
|
||||
while (!finished)
|
||||
cond.wait(mutex);
|
||||
if (!cond.timed_wait(mutex, timeout_ms))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -157,6 +157,12 @@ public:
|
||||
|
||||
return *i;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void ForEach(F &&f) {
|
||||
for (CT &i : list)
|
||||
f(i);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -34,11 +34,15 @@ extern "C" {
|
||||
|
||||
#include <poll.h> /* for POLLIN, POLLOUT */
|
||||
|
||||
static constexpr unsigned NFS_MOUNT_TIMEOUT = 60;
|
||||
|
||||
inline bool
|
||||
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
||||
const char *path,
|
||||
Error &error)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
int result = nfs_stat_async(ctx, path, Callback, this);
|
||||
if (result < 0) {
|
||||
error.Format(nfs_domain, "nfs_stat_async() failed: %s",
|
||||
@@ -54,6 +58,8 @@ NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx,
|
||||
const char *path,
|
||||
Error &error)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
int result = nfs_opendir_async(ctx, path, Callback, this);
|
||||
if (result < 0) {
|
||||
error.Format(nfs_domain, "nfs_opendir_async() failed: %s",
|
||||
@@ -69,6 +75,8 @@ NfsConnection::CancellableCallback::Open(nfs_context *ctx,
|
||||
const char *path, int flags,
|
||||
Error &error)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
int result = nfs_open_async(ctx, path, flags,
|
||||
Callback, this);
|
||||
if (result < 0) {
|
||||
@@ -85,6 +93,8 @@ NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
|
||||
struct nfsfh *fh,
|
||||
Error &error)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
int result = nfs_fstat_async(ctx, fh, Callback, this);
|
||||
if (result < 0) {
|
||||
error.Format(nfs_domain, "nfs_fstat_async() failed: %s",
|
||||
@@ -100,6 +110,8 @@ NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
|
||||
uint64_t offset, size_t size,
|
||||
Error &error)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
int result = nfs_pread_async(ctx, fh, offset, size, Callback, this);
|
||||
if (result < 0) {
|
||||
error.Format(nfs_domain, "nfs_pread_async() failed: %s",
|
||||
@@ -113,6 +125,7 @@ NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
|
||||
inline void
|
||||
NfsConnection::CancellableCallback::CancelAndScheduleClose(struct nfsfh *fh)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
assert(!open);
|
||||
assert(close_fh == nullptr);
|
||||
assert(fh != nullptr);
|
||||
@@ -121,9 +134,22 @@ NfsConnection::CancellableCallback::CancelAndScheduleClose(struct nfsfh *fh)
|
||||
Cancel();
|
||||
}
|
||||
|
||||
inline void
|
||||
NfsConnection::CancellableCallback::PrepareDestroyContext()
|
||||
{
|
||||
assert(IsCancelled());
|
||||
|
||||
if (close_fh != nullptr) {
|
||||
connection.InternalClose(close_fh);
|
||||
close_fh = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
NfsConnection::CancellableCallback::Callback(int err, void *data)
|
||||
{
|
||||
assert(connection.GetEventLoop().IsInside());
|
||||
|
||||
if (!IsCancelled()) {
|
||||
assert(close_fh == nullptr);
|
||||
|
||||
@@ -143,8 +169,10 @@ NfsConnection::CancellableCallback::Callback(int err, void *data)
|
||||
allocated file handle immediately */
|
||||
assert(close_fh == nullptr);
|
||||
|
||||
struct nfsfh *fh = (struct nfsfh *)data;
|
||||
connection.Close(fh);
|
||||
if (err >= 0) {
|
||||
struct nfsfh *fh = (struct nfsfh *)data;
|
||||
connection.Close(fh);
|
||||
}
|
||||
} else if (close_fh != nullptr)
|
||||
connection.DeferClose(close_fh);
|
||||
|
||||
@@ -209,6 +237,7 @@ NfsConnection::RemoveLease(NfsLease &lease)
|
||||
bool
|
||||
NfsConnection::Stat(const char *path, NfsCallback &callback, Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!callbacks.Contains(callback));
|
||||
|
||||
auto &c = callbacks.Add(callback, *this, false);
|
||||
@@ -225,6 +254,7 @@ bool
|
||||
NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
|
||||
Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!callbacks.Contains(callback));
|
||||
|
||||
auto &c = callbacks.Add(callback, *this, true);
|
||||
@@ -240,12 +270,16 @@ NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
|
||||
const struct nfsdirent *
|
||||
NfsConnection::ReadDirectory(struct nfsdir *dir)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
|
||||
return nfs_readdir(context, dir);
|
||||
}
|
||||
|
||||
void
|
||||
NfsConnection::CloseDirectory(struct nfsdir *dir)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
|
||||
return nfs_closedir(context, dir);
|
||||
}
|
||||
|
||||
@@ -253,6 +287,7 @@ bool
|
||||
NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
|
||||
Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!callbacks.Contains(callback));
|
||||
|
||||
auto &c = callbacks.Add(callback, *this, true);
|
||||
@@ -268,6 +303,7 @@ NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
|
||||
bool
|
||||
NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!callbacks.Contains(callback));
|
||||
|
||||
auto &c = callbacks.Add(callback, *this, false);
|
||||
@@ -284,6 +320,7 @@ bool
|
||||
NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
|
||||
NfsCallback &callback, Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!callbacks.Contains(callback));
|
||||
|
||||
auto &c = callbacks.Add(callback, *this, false);
|
||||
@@ -307,10 +344,22 @@ DummyCallback(int, struct nfs_context *, void *, void *)
|
||||
{
|
||||
}
|
||||
|
||||
inline void
|
||||
NfsConnection::InternalClose(struct nfsfh *fh)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context != nullptr);
|
||||
assert(fh != nullptr);
|
||||
|
||||
nfs_close_async(context, fh, DummyCallback, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
NfsConnection::Close(struct nfsfh *fh)
|
||||
{
|
||||
nfs_close_async(context, fh, DummyCallback, nullptr);
|
||||
assert(GetEventLoop().IsInside());
|
||||
|
||||
InternalClose(fh);
|
||||
ScheduleSocket();
|
||||
}
|
||||
|
||||
@@ -327,12 +376,26 @@ NfsConnection::DestroyContext()
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context != nullptr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(!in_destroy);
|
||||
in_destroy = true;
|
||||
#endif
|
||||
|
||||
if (!mount_finished) {
|
||||
assert(TimeoutMonitor::IsActive());
|
||||
TimeoutMonitor::Cancel();
|
||||
}
|
||||
|
||||
/* cancel pending DeferredMonitor that was scheduled to notify
|
||||
new leases */
|
||||
DeferredMonitor::Cancel();
|
||||
|
||||
if (SocketMonitor::IsDefined())
|
||||
SocketMonitor::Cancel();
|
||||
SocketMonitor::Steal();
|
||||
|
||||
callbacks.ForEach([](CancellableCallback &c){
|
||||
c.PrepareDestroyContext();
|
||||
});
|
||||
|
||||
nfs_destroy_context(context);
|
||||
context = nullptr;
|
||||
@@ -341,8 +404,11 @@ NfsConnection::DestroyContext()
|
||||
inline void
|
||||
NfsConnection::DeferClose(struct nfsfh *fh)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(in_event);
|
||||
assert(in_service);
|
||||
assert(context != nullptr);
|
||||
assert(fh != nullptr);
|
||||
|
||||
deferred_close.push_front(fh);
|
||||
}
|
||||
@@ -350,6 +416,7 @@ NfsConnection::DeferClose(struct nfsfh *fh)
|
||||
void
|
||||
NfsConnection::ScheduleSocket()
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context != nullptr);
|
||||
|
||||
if (!SocketMonitor::IsDefined()) {
|
||||
@@ -364,9 +431,35 @@ NfsConnection::ScheduleSocket()
|
||||
SocketMonitor::Schedule(libnfs_to_events(nfs_which_events(context)));
|
||||
}
|
||||
|
||||
inline int
|
||||
NfsConnection::Service(unsigned flags)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context != nullptr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(!in_event);
|
||||
in_event = true;
|
||||
|
||||
assert(!in_service);
|
||||
in_service = true;
|
||||
#endif
|
||||
|
||||
int result = nfs_service(context, events_to_libnfs(flags));
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(context != nullptr);
|
||||
assert(in_service);
|
||||
in_service = false;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
NfsConnection::OnSocketReady(unsigned flags)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(deferred_close.empty());
|
||||
|
||||
bool closed = false;
|
||||
@@ -378,21 +471,10 @@ NfsConnection::OnSocketReady(unsigned flags)
|
||||
re-register it each time */
|
||||
SocketMonitor::Steal();
|
||||
|
||||
assert(!in_event);
|
||||
in_event = true;
|
||||
|
||||
assert(!in_service);
|
||||
in_service = true;
|
||||
|
||||
int result = nfs_service(context, events_to_libnfs(flags));
|
||||
|
||||
assert(context != nullptr);
|
||||
assert(in_service);
|
||||
in_service = false;
|
||||
const int result = Service(flags);
|
||||
|
||||
while (!deferred_close.empty()) {
|
||||
nfs_close_async(context, deferred_close.front(),
|
||||
DummyCallback, nullptr);
|
||||
InternalClose(deferred_close.front());
|
||||
deferred_close.pop_front();
|
||||
}
|
||||
|
||||
@@ -413,9 +495,9 @@ NfsConnection::OnSocketReady(unsigned flags)
|
||||
|
||||
DestroyContext();
|
||||
closed = true;
|
||||
} else if (SocketMonitor::IsDefined() && nfs_get_fd(context) < 0) {
|
||||
} else if (nfs_get_fd(context) < 0) {
|
||||
/* this happens when rpc_reconnect_requeue() is called
|
||||
after the connection broke, but autoreconnet was
|
||||
after the connection broke, but autoreconnect was
|
||||
disabled - nfs_service() returns 0 */
|
||||
Error error;
|
||||
const char *msg = nfs_get_error(context);
|
||||
@@ -431,8 +513,12 @@ NfsConnection::OnSocketReady(unsigned flags)
|
||||
closed = true;
|
||||
}
|
||||
|
||||
assert(context == nullptr || nfs_get_fd(context) >= 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(in_event);
|
||||
in_event = false;
|
||||
#endif
|
||||
|
||||
if (context != nullptr)
|
||||
ScheduleSocket();
|
||||
@@ -444,10 +530,14 @@ inline void
|
||||
NfsConnection::MountCallback(int status, gcc_unused nfs_context *nfs,
|
||||
gcc_unused void *data)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context == nfs);
|
||||
|
||||
mount_finished = true;
|
||||
|
||||
assert(TimeoutMonitor::IsActive() || in_destroy);
|
||||
TimeoutMonitor::Cancel();
|
||||
|
||||
if (status < 0) {
|
||||
postponed_mount_error.Format(nfs_domain, status,
|
||||
"nfs_mount_async() failed: %s",
|
||||
@@ -468,6 +558,7 @@ NfsConnection::MountCallback(int status, nfs_context *nfs, void *data,
|
||||
inline bool
|
||||
NfsConnection::MountInternal(Error &error)
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(context == nullptr);
|
||||
|
||||
context = nfs_init_context();
|
||||
@@ -478,8 +569,14 @@ NfsConnection::MountInternal(Error &error)
|
||||
|
||||
postponed_mount_error.Clear();
|
||||
mount_finished = false;
|
||||
|
||||
TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT);
|
||||
|
||||
#ifndef NDEBUG
|
||||
in_service = false;
|
||||
in_event = false;
|
||||
in_destroy = false;
|
||||
#endif
|
||||
|
||||
if (nfs_mount_async(context, server.c_str(), export_name.c_str(),
|
||||
MountCallback, this) != 0) {
|
||||
@@ -535,9 +632,23 @@ NfsConnection::BroadcastError(Error &&error)
|
||||
BroadcastMountError(std::move(error));
|
||||
}
|
||||
|
||||
void
|
||||
NfsConnection::OnTimeout()
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
assert(!mount_finished);
|
||||
|
||||
mount_finished = true;
|
||||
DestroyContext();
|
||||
|
||||
BroadcastMountError(Error(nfs_domain, "Mount timeout"));
|
||||
}
|
||||
|
||||
void
|
||||
NfsConnection::RunDeferred()
|
||||
{
|
||||
assert(GetEventLoop().IsInside());
|
||||
|
||||
if (context == nullptr) {
|
||||
Error error;
|
||||
if (!MountInternal(error)) {
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "Lease.hxx"
|
||||
#include "Cancellable.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/TimeoutMonitor.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
@@ -40,7 +41,7 @@ class NfsCallback;
|
||||
/**
|
||||
* An asynchronous connection to a NFS server.
|
||||
*/
|
||||
class NfsConnection : SocketMonitor, DeferredMonitor {
|
||||
class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
|
||||
class CancellableCallback : public CancellablePointer<NfsCallback> {
|
||||
NfsConnection &connection;
|
||||
|
||||
@@ -84,6 +85,13 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
|
||||
*/
|
||||
void CancelAndScheduleClose(struct nfsfh *fh);
|
||||
|
||||
/**
|
||||
* Called by NfsConnection::DestroyContext() right
|
||||
* before nfs_destroy_context(). This object is given
|
||||
* a chance to prepare for the latter.
|
||||
*/
|
||||
void PrepareDestroyContext();
|
||||
|
||||
private:
|
||||
static void Callback(int err, struct nfs_context *nfs,
|
||||
void *data, void *private_data);
|
||||
@@ -111,6 +119,7 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
|
||||
|
||||
Error postponed_mount_error;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* True when nfs_service() is being called.
|
||||
*/
|
||||
@@ -122,13 +131,20 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
|
||||
*/
|
||||
bool in_event;
|
||||
|
||||
/**
|
||||
* True when DestroyContext() is being called.
|
||||
*/
|
||||
bool in_destroy;
|
||||
#endif
|
||||
|
||||
bool mount_finished;
|
||||
|
||||
public:
|
||||
gcc_nonnull_all
|
||||
NfsConnection(EventLoop &_loop,
|
||||
const char *_server, const char *_export_name)
|
||||
:SocketMonitor(_loop), DeferredMonitor(_loop),
|
||||
:SocketMonitor(_loop), TimeoutMonitor(_loop),
|
||||
DeferredMonitor(_loop),
|
||||
server(_server), export_name(_export_name),
|
||||
context(nullptr) {}
|
||||
|
||||
@@ -184,6 +200,11 @@ protected:
|
||||
private:
|
||||
void DestroyContext();
|
||||
|
||||
/**
|
||||
* Wrapper for nfs_close_async().
|
||||
*/
|
||||
void InternalClose(struct nfsfh *fh);
|
||||
|
||||
/**
|
||||
* Invoke nfs_close_async() after nfs_service() returns.
|
||||
*/
|
||||
@@ -200,9 +221,17 @@ private:
|
||||
|
||||
void ScheduleSocket();
|
||||
|
||||
/**
|
||||
* Wrapper for nfs_service().
|
||||
*/
|
||||
int Service(unsigned flags);
|
||||
|
||||
/* virtual methods from SocketMonitor */
|
||||
virtual bool OnSocketReady(unsigned flags) override;
|
||||
|
||||
/* virtual methods from TimeoutMonitor */
|
||||
void OnTimeout() final;
|
||||
|
||||
/* virtual methods from DeferredMonitor */
|
||||
virtual void RunDeferred() override;
|
||||
};
|
||||
|
@@ -109,7 +109,7 @@ ShoutOutput::Configure(const config_param ¶m, Error &error)
|
||||
if (!audio_format.IsFullyDefined()) {
|
||||
error.Set(config_domain,
|
||||
"Need full audio format specification");
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *host = require_block_string(param, "host");
|
||||
|
@@ -44,7 +44,7 @@ PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
|
||||
"PCM conversion from %s to %s is not implemented",
|
||||
sample_format_to_string(_src_format),
|
||||
sample_format_to_string(_dest_format));
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
case SampleFormat::S16:
|
||||
case SampleFormat::S24_P32:
|
||||
|
@@ -43,12 +43,13 @@ playlist_provider_print(Client &client, const char *uri,
|
||||
DetachedSong *song;
|
||||
while ((song = e.NextSong()) != nullptr) {
|
||||
if (playlist_check_translate_song(*song, base_uri.c_str(),
|
||||
loader)) {
|
||||
if (detail)
|
||||
song_print_info(client, *song);
|
||||
else
|
||||
song_print_uri(client, *song);
|
||||
}
|
||||
loader) &&
|
||||
detail)
|
||||
song_print_info(client, *song);
|
||||
else
|
||||
/* fallback if no detail was requested or no
|
||||
detail was available */
|
||||
song_print_uri(client, *song);
|
||||
|
||||
delete song;
|
||||
}
|
||||
|
@@ -178,7 +178,7 @@ const struct playlist_plugin embcue_playlist_plugin = {
|
||||
embcue_playlist_open_uri,
|
||||
nullptr,
|
||||
|
||||
nullptr,
|
||||
embcue_playlist_suffixes,
|
||||
nullptr,
|
||||
nullptr,
|
||||
};
|
||||
|
@@ -146,6 +146,7 @@ private:
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
state = _state;
|
||||
last_error.Clear();
|
||||
last_error.Set(error);
|
||||
cond.broadcast();
|
||||
}
|
||||
@@ -287,7 +288,7 @@ NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow,
|
||||
return false;
|
||||
|
||||
if (!WaitConnected(error))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
NfsGetInfoOperation operation(*connection, path.c_str(), info);
|
||||
return operation.Run(error);
|
||||
|
@@ -182,7 +182,10 @@ TagBuilder::Complement(const Tag &other)
|
||||
inline void
|
||||
TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(value != nullptr);
|
||||
#endif
|
||||
assert(length > 0);
|
||||
|
||||
auto f = FixTagString(value, length);
|
||||
@@ -203,7 +206,10 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
|
||||
void
|
||||
TagBuilder::AddItem(TagType type, const char *value, size_t length)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(value != nullptr);
|
||||
#endif
|
||||
|
||||
if (length == 0 || ignore_tag_items[type])
|
||||
return;
|
||||
@@ -214,7 +220,10 @@ TagBuilder::AddItem(TagType type, const char *value, size_t length)
|
||||
void
|
||||
TagBuilder::AddItem(TagType type, const char *value)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(value != nullptr);
|
||||
#endif
|
||||
|
||||
AddItem(type, value, strlen(value));
|
||||
}
|
||||
|
@@ -20,17 +20,25 @@
|
||||
#ifndef MPD_THREAD_NAME_HXX
|
||||
#define MPD_THREAD_NAME_HXX
|
||||
|
||||
#ifdef HAVE_PTHREAD_SETNAME_NP
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#if defined(HAVE_PTHREAD_SETNAME_NP) && !defined(__NetBSD__)
|
||||
# define HAVE_THREAD_NAME
|
||||
# include <pthread.h>
|
||||
# include <stdio.h>
|
||||
#elif defined(HAVE_PRCTL)
|
||||
#include <sys/prctl.h>
|
||||
# include <sys/prctl.h>
|
||||
# ifdef PR_SET_NAME
|
||||
# define HAVE_THREAD_NAME
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
SetThreadName(const char *name)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_SETNAME_NP
|
||||
#if defined(HAVE_PTHREAD_SETNAME_NP) && !defined(__NetBSD__)
|
||||
/* not using pthread_setname_np() on NetBSD because it
|
||||
requires a non-const pointer argument, which we don't have
|
||||
here */
|
||||
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np(name);
|
||||
#else
|
||||
@@ -47,7 +55,7 @@ template<typename... Args>
|
||||
static inline void
|
||||
FormatThreadName(const char *fmt, gcc_unused Args&&... args)
|
||||
{
|
||||
#ifdef HAVE_PTHREAD_SETNAME_NP
|
||||
#ifdef HAVE_THREAD_NAME
|
||||
char buffer[16];
|
||||
snprintf(buffer, sizeof(buffer), fmt, args...);
|
||||
SetThreadName(buffer);
|
||||
|
@@ -43,24 +43,30 @@ gcc_pure gcc_nonnull_all
|
||||
static inline bool
|
||||
StringEqualsCaseASCII(const char *a, const char *b)
|
||||
{
|
||||
assert(a != nullptr);
|
||||
assert(b != nullptr);
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(a != nullptr);
|
||||
assert(b != nullptr);
|
||||
#endif
|
||||
|
||||
/* note: strcasecmp() depends on the locale, but for ASCII-only
|
||||
strings, it's safe to use */
|
||||
return strcasecmp(a, b) == 0;
|
||||
/* note: strcasecmp() depends on the locale, but for ASCII-only
|
||||
strings, it's safe to use */
|
||||
return strcasecmp(a, b) == 0;
|
||||
}
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static inline bool
|
||||
StringEqualsCaseASCII(const char *a, const char *b, size_t n)
|
||||
{
|
||||
assert(a != nullptr);
|
||||
assert(b != nullptr);
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(a != nullptr);
|
||||
assert(b != nullptr);
|
||||
#endif
|
||||
|
||||
/* note: strcasecmp() depends on the locale, but for ASCII-only
|
||||
strings, it's safe to use */
|
||||
return strncasecmp(a, b, n) == 0;
|
||||
/* note: strcasecmp() depends on the locale, but for ASCII-only
|
||||
strings, it's safe to use */
|
||||
return strncasecmp(a, b, n) == 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -70,7 +70,10 @@ gcc_malloc
|
||||
static inline void *
|
||||
HugeAllocate(size_t size)
|
||||
{
|
||||
return VirtualAlloc(nullptr, size, MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
// TODO: use MEM_LARGE_PAGES
|
||||
return VirtualAlloc(nullptr, size,
|
||||
MEM_COMMIT|MEM_RESERVE,
|
||||
PAGE_READWRITE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@@ -35,7 +35,7 @@
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
|
||||
#if GCC_OLDER_THAN(4,8)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
*/
|
||||
template<class T>
|
||||
class Manual {
|
||||
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
|
||||
#if GCC_OLDER_THAN(4,8)
|
||||
/* no alignas() on gcc < 4.8: apply worst-case fallback */
|
||||
__attribute__((aligned(8)))
|
||||
#else
|
||||
|
@@ -140,8 +140,11 @@ uri_remove_auth(const char *uri)
|
||||
bool
|
||||
uri_is_child(const char *parent, const char *child)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(parent != nullptr);
|
||||
assert(child != nullptr);
|
||||
#endif
|
||||
|
||||
const size_t parent_length = strlen(parent);
|
||||
return memcmp(parent, child, parent_length) == 0 &&
|
||||
|
Reference in New Issue
Block a user