Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
737a56a0
Commit
737a56a0
authored
Nov 26, 2014
by
Max Kellermann
Browse files
Options
Browse Files
Download
Plain Diff
Merge tag 'v0.19.5'
parents
12b6959e
67cba251
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
140 additions
and
430 deletions
+140
-430
INSTALL
INSTALL
+0
-3
Makefile.am
Makefile.am
+7
-8
NEWS
NEWS
+10
-1
AndroidManifest.xml
android/AndroidManifest.xml
+2
-2
configure.ac
configure.ac
+0
-24
ZzipArchivePlugin.cxx
src/archive/plugins/ZzipArchivePlugin.cxx
+5
-4
DecoderList.cxx
src/decoder/DecoderList.cxx
+0
-4
Mp4v2DecoderPlugin.cxx
src/decoder/plugins/Mp4v2DecoderPlugin.cxx
+0
-330
Mp4v2DecoderPlugin.hxx
src/decoder/plugins/Mp4v2DecoderPlugin.hxx
+0
-25
DeferredMonitor.hxx
src/event/DeferredMonitor.hxx
+0
-3
AlsaInputPlugin.cxx
src/input/plugins/AlsaInputPlugin.cxx
+2
-0
Connection.cxx
src/lib/nfs/Connection.cxx
+8
-4
FileReader.cxx
src/lib/nfs/FileReader.cxx
+37
-1
FileReader.hxx
src/lib/nfs/FileReader.hxx
+7
-0
Manager.cxx
src/lib/nfs/Manager.cxx
+25
-5
Manager.hxx
src/lib/nfs/Manager.hxx
+29
-4
run_input.cxx
test/run_input.cxx
+8
-12
No files found.
INSTALL
View file @
737a56a0
...
...
@@ -119,9 +119,6 @@ For AdLib playback.
despotify - https://github.com/SimonKagstrom/despotify
For Spotify playback.
MP4v2 - https://code.google.com/p/mp4v2/
For MP4 playback. You will need FAAD2.
Optional Miscellaneous Dependencies
-----------------------------------
...
...
Makefile.am
View file @
737a56a0
...
...
@@ -833,7 +833,6 @@ libdecoder_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(WAVPACK_CFLAGS)
\
$(MAD_CFLAGS)
\
$(MPG123_CFLAGS)
\
$(MP4V2_CFLAGS)
\
$(OPUS_CFLAGS)
\
$(FFMPEG_CFLAGS)
\
$(MPCDEC_CFLAGS)
\
...
...
@@ -853,7 +852,6 @@ DECODER_LIBS = \
$(WAVPACK_LIBS)
\
$(MAD_LIBS)
\
$(MPG123_LIBS)
\
$(MP4V2_LIBS)
\
$(OPUS_LIBS)
\
$(FFMPEG_LIBS2)
\
$(MPCDEC_LIBS)
\
...
...
@@ -968,12 +966,6 @@ noinst_LIBRARIES += libmodplug_decoder_plugin.a
DECODER_LIBS
+=
libmodplug_decoder_plugin.a
$(MODPLUG_LIBS)
endif
if
HAVE_MP4V2
libdecoder_a_SOURCES
+=
\
src/decoder/plugins/Mp4v2DecoderPlugin.cxx
\
src/decoder/plugins/Mp4v2DecoderPlugin.hxx
endif
if
ENABLE_SIDPLAY
libdecoder_a_SOURCES
+=
\
src/decoder/plugins/SidplayDecoderPlugin.cxx
\
...
...
@@ -2193,4 +2185,11 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
$
(
wildcard scripts/
*
.sh
)
\
$(man_MANS)
$(DOCBOOK_FILES)
doc/mpdconf.example doc/doxygen.conf
\
systemd/mpd.socket
\
android/AndroidManifest.xml
\
android/build.py
\
android/custom_rules.xml
\
android/res/values/strings.xml
\
android/src/Bridge.java
\
android/src/Loader.java
\
android/src/Main.java
\
src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico
NEWS
View file @
737a56a0
...
...
@@ -9,9 +9,14 @@ ver 0.20 (not yet released)
- pulse: set channel map to WAVE-EX
* reset song priority on playback
ver 0.19.5 (not yet released)
ver 0.19.5 (2014/11/26)
* input
- nfs: fix crash on connection failure
* archive
- zzip: fix crash after seeking
* decoder
- dsdiff, dsf, opus: fix deadlock while seeking
- mp4v2: remove because of incompatible license
ver 0.19.4 (2014/11/18)
* protocol
...
...
@@ -144,6 +149,10 @@ ver 0.19 (2014/10/10)
* install systemd unit for socket activation
* Android port
ver 0.18.19 (2014/11/26)
* archive
- zzip: fix crash after seeking
ver 0.18.18 (2014/11/18)
* decoder
- ffmpeg: support opus
...
...
android/AndroidManifest.xml
View file @
737a56a0
...
...
@@ -2,8 +2,8 @@
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"org.musicpd"
android:installLocation=
"auto"
android:versionCode=
"
8
"
android:versionName=
"0.19.
4
"
>
android:versionCode=
"
9
"
android:versionName=
"0.19.
5
"
>
<uses-sdk
android:minSdkVersion=
"9"
android:targetSdkVersion=
"17"
/>
...
...
configure.ac
View file @
737a56a0
...
...
@@ -382,11 +382,6 @@ AC_ARG_ENABLE(mikmod,
[enable the mikmod decoder (default: disable)]),,
enable_mikmod=no)
AC_ARG_ENABLE(mp4v2,
AS_HELP_STRING([--enable-mp4v2],
[enable libmp4v2 decoder plugin]),,
enable_mp4v2=auto)
AC_ARG_ENABLE(mpc,
AS_HELP_STRING([--enable-mpc],
[disable musepack (MPC) support (default: auto)]),,
...
...
@@ -984,24 +979,6 @@ dnl -------------------------------- libmodplug -------------------------------
MPD_ENABLE_AUTO_PKG(modplug, MODPLUG, [libmodplug],
[modplug decoder plugin], [libmodplug not found])
dnl -------------------------------- libmp4v2 ---------------------------------
if test x$enable_aac = xyes; then
MPD_AUTO_LIB(mp4v2, MP4V2, mp4v2, MP4Create, [-lmp4v2], [],
[mp4v2], [libmp4v2 not found])
if test x$enable_mp4v2 = xyes; then
AC_DEFINE(HAVE_MP4V2, 1, [Define to use libmp4v2 for MP4 decoding])
fi
else
if test x$enable_mp4v2 = xyes; then
AC_MSG_ERROR([MP4V2 requires AAC!])
fi
enable_mp4v2=no
fi
AM_CONDITIONAL(HAVE_MP4V2, test x$enable_mp4v2 = xyes)
dnl -------------------------------- libopus ----------------------------------
MPD_ENABLE_AUTO_PKG(opus, OPUS, [opus ogg],
[opus decoder plugin], [libopus not found])
...
...
@@ -1533,7 +1510,6 @@ printf '\n\t'
results(sndfile, [libsndfile])
results(mikmod, [MikMod])
results(modplug, [MODPLUG])
results(mp4v2, [MP4V2])
results(mad, [MAD])
results(mpg123, [MPG123])
results(mpc, [Musepack])
...
...
src/archive/plugins/ZzipArchivePlugin.cxx
View file @
737a56a0
...
...
@@ -168,12 +168,13 @@ bool
ZzipInputStream
::
Seek
(
offset_type
new_offset
,
Error
&
error
)
{
zzip_off_t
ofs
=
zzip_seek
(
file
,
new_offset
,
SEEK_SET
);
if
(
ofs
!=
-
1
)
{
if
(
ofs
<
0
)
{
error
.
Set
(
zzip_domain
,
"zzip_seek() has failed"
);
offset
=
ofs
;
return
true
;
return
false
;
}
return
false
;
offset
=
ofs
;
return
true
;
}
/* exported structures */
...
...
src/decoder/DecoderList.cxx
View file @
737a56a0
...
...
@@ -37,7 +37,6 @@
#include "plugins/MadDecoderPlugin.hxx"
#include "plugins/SndfileDecoderPlugin.hxx"
#include "plugins/Mpg123DecoderPlugin.hxx"
#include "plugins/Mp4v2DecoderPlugin.hxx"
#include "plugins/WildmidiDecoderPlugin.hxx"
#include "plugins/MikmodDecoderPlugin.hxx"
#include "plugins/ModplugDecoderPlugin.hxx"
...
...
@@ -55,9 +54,6 @@ const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef ENABLE_MPG123
&
mpg123_decoder_plugin
,
#endif
#ifdef HAVE_MP4V2
&
mp4v2_decoder_plugin
,
#endif
#ifdef ENABLE_VORBIS_DECODER
&
vorbis_decoder_plugin
,
#endif
...
...
src/decoder/plugins/Mp4v2DecoderPlugin.cxx
deleted
100644 → 0
View file @
12b6959e
/*
* Copyright (C) 2003-2014 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 "config.h"
/* must be first for large file support */
#include "Mp4v2DecoderPlugin.hxx"
#include "../DecoderAPI.hxx"
#include "CheckAudioFormat.hxx"
#include "tag/TagHandler.hxx"
#include "fs/Path.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
#include <mp4v2/mp4v2.h>
#include <neaacdec.h>
#include <cstdio>
#include <cstdlib>
static
constexpr
Domain
mp4v2_decoder_domain
(
"mp4v2"
);
static
MP4TrackId
mp4_get_aac_track
(
MP4FileHandle
handle
,
NeAACDecHandle
decoder
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
unsigned
long
sample_rate
;
const
MP4TrackId
tracks
=
MP4GetNumberOfTracks
(
handle
);
for
(
MP4TrackId
id
=
1
;
id
<=
tracks
;
id
++
)
{
const
char
*
track_type
=
MP4GetTrackType
(
handle
,
id
);
if
(
track_type
==
0
)
continue
;
const
auto
obj_type
=
MP4GetTrackEsdsObjectTypeId
(
handle
,
id
);
if
(
obj_type
==
MP4_INVALID_AUDIO_TYPE
)
continue
;
if
(
obj_type
==
MP4_MPEG4_AUDIO_TYPE
)
{
const
auto
mpeg_type
=
MP4GetTrackAudioMpeg4Type
(
handle
,
id
);
if
(
!
MP4_IS_MPEG4_AAC_AUDIO_TYPE
(
mpeg_type
))
continue
;
}
else
if
(
!
MP4_IS_AAC_AUDIO_TYPE
(
obj_type
))
continue
;
if
(
decoder
==
nullptr
)
/* found audio track, no decoder */
return
id
;
unsigned
char
*
buff
=
nullptr
;
unsigned
buff_size
=
0
;
if
(
!
MP4GetTrackESConfiguration
(
handle
,
id
,
&
buff
,
&
buff_size
))
continue
;
uint8_t
channels
;
int32_t
nbytes
=
NeAACDecInit
(
decoder
,
buff
,
buff_size
,
&
sample_rate
,
&
channels
);
free
(
buff
);
if
(
nbytes
<
0
)
/* invalid stream */
continue
;
if
(
!
audio_format_init_checked
(
audio_format
,
sample_rate
,
SampleFormat
::
S16
,
channels
,
error
))
continue
;
return
id
;
}
error
.
Set
(
mp4v2_decoder_domain
,
"no valid aac track found"
);
return
MP4_INVALID_TRACK_ID
;
}
static
NeAACDecHandle
mp4_faad_new
(
MP4FileHandle
handle
,
AudioFormat
&
audio_format
,
Error
&
error
)
{
const
NeAACDecHandle
decoder
=
NeAACDecOpen
();
const
NeAACDecConfigurationPtr
config
=
NeAACDecGetCurrentConfiguration
(
decoder
);
config
->
outputFormat
=
FAAD_FMT_16BIT
;
config
->
downMatrix
=
1
;
config
->
dontUpSampleImplicitSBR
=
0
;
NeAACDecSetConfiguration
(
decoder
,
config
);
const
auto
track
=
mp4_get_aac_track
(
handle
,
decoder
,
audio_format
,
error
);
if
(
track
==
MP4_INVALID_TRACK_ID
)
{
NeAACDecClose
(
decoder
);
return
nullptr
;
}
return
decoder
;
}
static
void
mp4_file_decode
(
Decoder
&
mpd_decoder
,
Path
path_fs
)
{
const
MP4FileHandle
handle
=
MP4Read
(
path_fs
.
c_str
());
if
(
handle
==
MP4_INVALID_FILE_HANDLE
)
{
FormatError
(
mp4v2_decoder_domain
,
"unable to open file"
);
return
;
}
AudioFormat
audio_format
;
Error
error
;
const
NeAACDecHandle
decoder
=
mp4_faad_new
(
handle
,
audio_format
,
error
);
if
(
decoder
==
nullptr
)
{
LogError
(
error
);
MP4Close
(
handle
);
return
;
}
const
MP4TrackId
track
=
mp4_get_aac_track
(
handle
,
nullptr
,
audio_format
,
error
);
/* initialize the MPD core */
const
MP4Timestamp
scale
=
MP4GetTrackTimeScale
(
handle
,
track
);
const
SongTime
duration
=
SongTime
::
FromScale
<
uint64_t
>
(
MP4GetTrackDuration
(
handle
,
track
),
scale
);
const
MP4SampleId
num_samples
=
MP4GetTrackNumberOfSamples
(
handle
,
track
);
decoder_initialized
(
mpd_decoder
,
audio_format
,
true
,
duration
);
/* the decoder loop */
DecoderCommand
cmd
=
DecoderCommand
::
NONE
;
for
(
MP4SampleId
sample
=
1
;
sample
<
num_samples
&&
cmd
!=
DecoderCommand
::
STOP
;
sample
++
)
{
unsigned
char
*
data
=
nullptr
;
unsigned
int
data_length
=
0
;
if
(
cmd
==
DecoderCommand
::
SEEK
)
{
const
MP4Timestamp
offset
=
decoder_seek_time
(
mpd_decoder
).
ToScale
(
scale
);
sample
=
MP4GetSampleIdFromTime
(
handle
,
track
,
offset
,
false
);
decoder_command_finished
(
mpd_decoder
);
}
/* read */
if
(
MP4ReadSample
(
handle
,
track
,
sample
,
&
data
,
&
data_length
)
==
0
)
{
FormatError
(
mp4v2_decoder_domain
,
"unable to read sample"
);
break
;
}
/* decode it */
NeAACDecFrameInfo
frame_info
;
const
void
*
const
decoded
=
NeAACDecDecode
(
decoder
,
&
frame_info
,
data
,
data_length
);
if
(
frame_info
.
error
>
0
)
{
FormatWarning
(
mp4v2_decoder_domain
,
"error decoding AAC stream: %s"
,
NeAACDecGetErrorMessage
(
frame_info
.
error
));
break
;
}
if
(
frame_info
.
channels
!=
audio_format
.
channels
)
{
FormatDefault
(
mp4v2_decoder_domain
,
"channel count changed from %u to %u"
,
audio_format
.
channels
,
frame_info
.
channels
);
break
;
}
if
(
frame_info
.
samplerate
!=
audio_format
.
sample_rate
)
{
FormatDefault
(
mp4v2_decoder_domain
,
"sample rate changed from %u to %lu"
,
audio_format
.
sample_rate
,
(
unsigned
long
)
frame_info
.
samplerate
);
break
;
}
/* update bit rate and position */
unsigned
bit_rate
=
0
;
if
(
frame_info
.
samples
>
0
)
{
bit_rate
=
frame_info
.
bytesconsumed
*
8.0
*
frame_info
.
channels
*
audio_format
.
sample_rate
/
frame_info
.
samples
/
1000
+
0.5
;
}
/* send PCM samples to MPD */
cmd
=
decoder_data
(
mpd_decoder
,
nullptr
,
decoded
,
(
size_t
)
frame_info
.
samples
*
2
,
bit_rate
);
free
(
data
);
}
/* cleanup */
NeAACDecClose
(
decoder
);
MP4Close
(
handle
);
}
static
inline
void
mp4_safe_invoke_tag
(
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
,
TagType
tag
,
const
char
*
value
)
{
if
(
value
!=
nullptr
)
tag_handler_invoke_tag
(
handler
,
handler_ctx
,
tag
,
value
);
}
static
bool
mp4_scan_file
(
Path
path_fs
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
)
{
const
MP4FileHandle
handle
=
MP4Read
(
path_fs
.
c_str
());
if
(
handle
==
MP4_INVALID_FILE_HANDLE
)
return
false
;
AudioFormat
tmp_audio_format
;
Error
error
;
const
MP4TrackId
id
=
mp4_get_aac_track
(
handle
,
nullptr
,
tmp_audio_format
,
error
);
if
(
id
==
MP4_INVALID_TRACK_ID
)
{
LogError
(
error
);
MP4Close
(
handle
);
return
false
;
}
const
MP4Timestamp
scale
=
MP4GetTrackTimeScale
(
handle
,
id
);
const
SongTime
dur
=
SongTime
::
FromScale
<
uint64_t
>
(
MP4GetTrackDuration
(
handle
,
id
),
scale
);
tag_handler_invoke_duration
(
handler
,
handler_ctx
,
dur
);
const
MP4Tags
*
tags
=
MP4TagsAlloc
();
MP4TagsFetch
(
tags
,
handle
);
static
constexpr
struct
{
const
char
*
MP4Tags
::*
p
;
TagType
tag_type
;
}
mp4v2_tags
[]
=
{
{
&
MP4Tags
::
name
,
TAG_NAME
},
{
&
MP4Tags
::
artist
,
TAG_ARTIST
},
{
&
MP4Tags
::
albumArtist
,
TAG_ALBUM_ARTIST
},
{
&
MP4Tags
::
album
,
TAG_ALBUM
},
{
&
MP4Tags
::
composer
,
TAG_COMPOSER
},
{
&
MP4Tags
::
comments
,
TAG_COMMENT
},
{
&
MP4Tags
::
genre
,
TAG_GENRE
},
{
&
MP4Tags
::
releaseDate
,
TAG_DATE
},
{
&
MP4Tags
::
sortArtist
,
TAG_ARTIST_SORT
},
{
&
MP4Tags
::
sortAlbumArtist
,
TAG_ALBUM_ARTIST_SORT
},
};
for
(
const
auto
&
i
:
mp4v2_tags
)
mp4_safe_invoke_tag
(
handler
,
handler_ctx
,
i
.
tag_type
,
tags
->*
i
.
p
);
char
buff
[
8
];
/* tmp buffer for index to string. */
if
(
tags
->
track
!=
nullptr
)
{
sprintf
(
buff
,
"%d"
,
tags
->
track
->
index
);
tag_handler_invoke_tag
(
handler
,
handler_ctx
,
TAG_TRACK
,
buff
);
}
if
(
tags
->
disk
!=
nullptr
)
{
sprintf
(
buff
,
"%d"
,
tags
->
disk
->
index
);
tag_handler_invoke_tag
(
handler
,
handler_ctx
,
TAG_DISC
,
buff
);
}
MP4TagsFree
(
tags
);
MP4Close
(
handle
);
return
true
;
}
static
const
char
*
const
mp4_suffixes
[]
=
{
"mp4"
,
"m4a"
,
/* "m4p", encrypted */
/* "m4b", audio book */
/* "m4r", ring tones */
/* "m4v", video */
nullptr
};
static
const
char
*
const
mp4_mime_types
[]
=
{
"application/mp4"
,
"application/m4a"
,
"audio/mp4"
,
"audio/m4a"
,
/* "audio/m4p", */
/* "audio/m4b", */
/* "audio/m4r", */
/* "audio/m4v", */
nullptr
};
const
struct
DecoderPlugin
mp4v2_decoder_plugin
=
{
"mp4v2"
,
nullptr
,
nullptr
,
nullptr
,
mp4_file_decode
,
mp4_scan_file
,
nullptr
,
nullptr
,
mp4_suffixes
,
mp4_mime_types
};
src/decoder/plugins/Mp4v2DecoderPlugin.hxx
deleted
100644 → 0
View file @
12b6959e
/*
* Copyright (C) 2003-2014 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.
*/
#ifndef MPD_DECODER_MP4V2_HXX
#define MPD_DECODER_MP4V2_HXX
extern
const
struct
DecoderPlugin
mp4v2_decoder_plugin
;
#endif
src/event/DeferredMonitor.hxx
View file @
737a56a0
...
...
@@ -21,9 +21,6 @@
#define MPD_SOCKET_DEFERRED_MONITOR_HXX
#include "check.h"
#include "Compiler.h"
#include <atomic>
class
EventLoop
;
...
...
src/input/plugins/AlsaInputPlugin.cxx
View file @
737a56a0
...
...
@@ -43,6 +43,8 @@
#include <alsa/asoundlib.h>
#include <atomic>
#include <assert.h>
#include <string.h>
...
...
src/lib/nfs/Connection.cxx
View file @
737a56a0
...
...
@@ -327,6 +327,10 @@ NfsConnection::DestroyContext()
assert
(
GetEventLoop
().
IsInside
());
assert
(
context
!=
nullptr
);
/* cancel pending DeferredMonitor that was scheduled to notify
new leases */
DeferredMonitor
::
Cancel
();
if
(
SocketMonitor
::
IsDefined
())
SocketMonitor
::
Cancel
();
...
...
@@ -405,10 +409,10 @@ NfsConnection::OnSocketReady(unsigned flags)
error
.
Format
(
nfs_domain
,
"NFS connection has failed: %s"
,
nfs_get_error
(
context
));
BroadcastError
(
std
::
move
(
error
));
DestroyContext
();
closed
=
true
;
BroadcastError
(
std
::
move
(
error
));
}
else
if
(
SocketMonitor
::
IsDefined
()
&&
nfs_get_fd
(
context
)
<
0
)
{
/* this happens when rpc_reconnect_requeue() is called
after the connection broke, but autoreconnet was
...
...
@@ -421,10 +425,10 @@ NfsConnection::OnSocketReady(unsigned flags)
error
.
Format
(
nfs_domain
,
"NFS socket disappeared: %s"
,
msg
);
BroadcastError
(
std
::
move
(
error
));
DestroyContext
();
closed
=
true
;
BroadcastError
(
std
::
move
(
error
));
}
assert
(
in_event
);
...
...
src/lib/nfs/FileReader.cxx
View file @
737a56a0
...
...
@@ -56,8 +56,18 @@ NfsFileReader::Close()
return
;
}
/* this cancels State::MOUNT */
connection
->
RemoveLease
(
*
this
);
CancelOrClose
();
}
void
NfsFileReader
::
CancelOrClose
()
{
assert
(
state
!=
State
::
INITIAL
&&
state
!=
State
::
DEFER
);
if
(
state
==
State
::
IDLE
)
/* no async operation in progress: can close
immediately */
...
...
@@ -164,6 +174,8 @@ NfsFileReader::OnNfsConnectionFailed(const Error &error)
{
assert
(
state
==
State
::
MOUNT
);
state
=
State
::
INITIAL
;
Error
copy
;
copy
.
Set
(
error
);
OnNfsFileError
(
std
::
move
(
copy
));
...
...
@@ -174,7 +186,7 @@ NfsFileReader::OnNfsConnectionDisconnected(const Error &error)
{
assert
(
state
>
State
::
MOUNT
);
state
=
State
::
INITIAL
;
CancelOrClose
()
;
Error
copy
;
copy
.
Set
(
error
);
...
...
@@ -246,6 +258,30 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data)
void
NfsFileReader
::
OnNfsError
(
Error
&&
error
)
{
switch
(
state
)
{
case
State
:
:
INITIAL
:
case
State
:
:
DEFER
:
case
State
:
:
MOUNT
:
case
State
:
:
IDLE
:
assert
(
false
);
gcc_unreachable
();
case
State
:
:
OPEN
:
connection
->
RemoveLease
(
*
this
);
state
=
State
::
INITIAL
;
break
;
case
State
:
:
STAT
:
connection
->
RemoveLease
(
*
this
);
connection
->
Close
(
fh
);
state
=
State
::
INITIAL
;
break
;
case
State
:
:
READ
:
state
=
State
::
IDLE
;
break
;
}
OnNfsFileError
(
std
::
move
(
error
));
}
...
...
src/lib/nfs/FileReader.hxx
View file @
737a56a0
...
...
@@ -24,6 +24,7 @@
#include "Lease.hxx"
#include "Callback.hxx"
#include "event/DeferredMonitor.hxx"
#include "Compiler.h"
#include <string>
...
...
@@ -75,6 +76,12 @@ protected:
virtual
void
OnNfsFileError
(
Error
&&
error
)
=
0
;
private
:
/**
* Cancel the current operation, if any. The NfsLease must be
* unregistered already.
*/
void
CancelOrClose
();
void
OpenCallback
(
nfsfh
*
_fh
);
void
StatCallback
(
const
struct
stat
*
st
);
...
...
src/lib/nfs/Manager.cxx
View file @
737a56a0
...
...
@@ -29,8 +29,10 @@ NfsManager::ManagedConnection::OnNfsConnectionError(Error &&error)
{
FormatError
(
error
,
"NFS error on %s:%s"
,
GetServer
(),
GetExportName
());
manager
.
connections
.
erase
(
manager
.
connections
.
iterator_to
(
*
this
));
delete
this
;
/* defer deletion so the caller
(i.e. NfsConnection::OnSocketReady()) can still use this
object */
manager
.
ScheduleDelete
(
*
this
);
}
inline
bool
...
...
@@ -59,7 +61,9 @@ NfsManager::Compare::operator()(const ManagedConnection &a,
NfsManager
::~
NfsManager
()
{
assert
(
loop
.
IsInside
());
assert
(
GetEventLoop
().
IsInside
());
CollectGarbage
();
connections
.
clear_and_dispose
([](
ManagedConnection
*
c
){
delete
c
;
...
...
@@ -71,13 +75,13 @@ NfsManager::GetConnection(const char *server, const char *export_name)
{
assert
(
server
!=
nullptr
);
assert
(
export_name
!=
nullptr
);
assert
(
loop
.
IsInside
());
assert
(
GetEventLoop
()
.
IsInside
());
Map
::
insert_commit_data
hint
;
auto
result
=
connections
.
insert_check
(
LookupKey
{
server
,
export_name
},
Compare
(),
hint
);
if
(
result
.
second
)
{
auto
c
=
new
ManagedConnection
(
*
this
,
loop
,
auto
c
=
new
ManagedConnection
(
*
this
,
GetEventLoop
()
,
server
,
export_name
);
connections
.
insert_commit
(
*
c
,
hint
);
return
*
c
;
...
...
@@ -85,3 +89,19 @@ NfsManager::GetConnection(const char *server, const char *export_name)
return
*
result
.
first
;
}
}
void
NfsManager
::
CollectGarbage
()
{
assert
(
GetEventLoop
().
IsInside
());
garbage
.
clear_and_dispose
([](
ManagedConnection
*
c
){
delete
c
;
});
}
void
NfsManager
::
OnIdle
()
{
CollectGarbage
();
}
src/lib/nfs/Manager.hxx
View file @
737a56a0
...
...
@@ -23,14 +23,16 @@
#include "check.h"
#include "Connection.hxx"
#include "Compiler.h"
#include "event/IdleMonitor.hxx"
#include <boost/intrusive/set.hpp>
#include <boost/intrusive/slist.hpp>
/**
* A manager for NFS connections. Handles multiple connections to
* multiple NFS servers.
*/
class
NfsManager
{
class
NfsManager
final
:
IdleMonitor
{
struct
LookupKey
{
const
char
*
server
;
const
char
*
export_name
;
...
...
@@ -38,6 +40,7 @@ class NfsManager {
class
ManagedConnection
final
:
public
NfsConnection
,
public
boost
::
intrusive
::
slist_base_hook
<
boost
::
intrusive
::
link_mode
<
boost
::
intrusive
::
normal_link
>>
,
public
boost
::
intrusive
::
set_base_hook
<
boost
::
intrusive
::
link_mode
<
boost
::
intrusive
::
normal_link
>>
{
NfsManager
&
manager
;
...
...
@@ -63,8 +66,6 @@ class NfsManager {
const
LookupKey
b
)
const
;
};
EventLoop
&
loop
;
/**
* Maps server and export_name to #ManagedConnection.
*/
...
...
@@ -74,9 +75,18 @@ class NfsManager {
Map
connections
;
typedef
boost
::
intrusive
::
slist
<
ManagedConnection
>
List
;
/**
* A list of "garbage" connection objects. Their destruction
* is postponed because they were thrown into the garbage list
* when callers on the stack were still using them.
*/
List
garbage
;
public
:
NfsManager
(
EventLoop
&
_loop
)
:
loop
(
_loop
)
{}
:
IdleMonitor
(
_loop
)
{}
/**
* Must be run from EventLoop's thread.
...
...
@@ -86,6 +96,21 @@ public:
gcc_pure
NfsConnection
&
GetConnection
(
const
char
*
server
,
const
char
*
export_name
);
private
:
void
ScheduleDelete
(
ManagedConnection
&
c
)
{
connections
.
erase
(
connections
.
iterator_to
(
c
));
garbage
.
push_front
(
c
);
IdleMonitor
::
Schedule
();
}
/**
* Delete all connections on the #garbage list.
*/
void
CollectGarbage
();
/* virtual methods from IdleMonitor */
void
OnIdle
()
override
;
};
#endif
test/run_input.cxx
View file @
737a56a0
...
...
@@ -54,11 +54,6 @@ tag_save(FILE *file, const Tag &tag)
static
int
dump_input_stream
(
InputStream
*
is
)
{
Error
error
;
char
buffer
[
4096
];
size_t
num_read
;
ssize_t
num_written
;
is
->
Lock
();
/* print meta data */
...
...
@@ -76,7 +71,9 @@ dump_input_stream(InputStream *is)
delete
tag
;
}
num_read
=
is
->
Read
(
buffer
,
sizeof
(
buffer
),
error
);
Error
error
;
char
buffer
[
4096
];
size_t
num_read
=
is
->
Read
(
buffer
,
sizeof
(
buffer
),
error
);
if
(
num_read
==
0
)
{
if
(
error
.
IsDefined
())
LogError
(
error
);
...
...
@@ -84,11 +81,12 @@ dump_input_stream(InputStream *is)
break
;
}
num_written
=
write
(
1
,
buffer
,
num_read
);
ssize_t
num_written
=
write
(
1
,
buffer
,
num_read
);
if
(
num_written
<=
0
)
break
;
}
Error
error
;
if
(
!
is
->
Check
(
error
))
{
LogError
(
error
);
is
->
Unlock
();
...
...
@@ -102,10 +100,6 @@ dump_input_stream(InputStream *is)
int
main
(
int
argc
,
char
**
argv
)
{
Error
error
;
InputStream
*
is
;
int
ret
;
if
(
argc
!=
2
)
{
fprintf
(
stderr
,
"Usage: run_input URI
\n
"
);
return
EXIT_FAILURE
;
...
...
@@ -129,6 +123,7 @@ int main(int argc, char **argv)
archive_plugin_init_all
();
#endif
Error
error
;
if
(
!
input_stream_global_init
(
error
))
{
LogError
(
error
);
return
2
;
...
...
@@ -139,7 +134,8 @@ int main(int argc, char **argv)
Mutex
mutex
;
Cond
cond
;
is
=
InputStream
::
OpenReady
(
argv
[
1
],
mutex
,
cond
,
error
);
InputStream
*
is
=
InputStream
::
OpenReady
(
argv
[
1
],
mutex
,
cond
,
error
);
int
ret
;
if
(
is
!=
NULL
)
{
ret
=
dump_input_stream
(
is
);
delete
is
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment