summaryrefslogtreecommitdiff
path: root/tools.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2006-02-05 18:00:00 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2006-02-05 18:00:00 +0100
commitc23992b807aca1cea08193b773f80eee0cb8f829 (patch)
tree63dd7d414c790c8cb0afdff07a35d77778ed25c6 /tools.c
parentc37734080c45ef7ba60d589df0d88fb9a6064c1b (diff)
downloadvdr-patch-lnbsharing-c23992b807aca1cea08193b773f80eee0cb8f829.tar.gz
vdr-patch-lnbsharing-c23992b807aca1cea08193b773f80eee0cb8f829.tar.bz2
Version 1.3.42vdr-1.3.42
- Removed leftover 'needsBufferReserve' variable from cTransfer (thanks to Marco Schlüßler). - Fixed setting "No title" for broken event data (reported by Ronny Kornexl). - Fixed channel up/down switching on single card systems (reported by Stefan Huelswitt). - Fixed handling "pending" timers that blocked others that actually could record (reported by Thomas Koch). - Speeded up cVideoRepacker (thanks to Reinhard Nissl). - Added an 'Id' parameter to cDevice::PlayAudio() to allow plugins to easier process the audio data (thanks to Marco Schlüßler). - Added Czech language texts (thanks to Vladimír Bárta). Plugin authors may want to add the new entries to their I18N texts and contact the translators to have their texts translated. Note that there are now 21 different OSD languages, so please make sure you have 21 versions for each of your texts. - Updated the Polish OSD texts (thanks to Jaroslaw Swierczynski). - Fixed auto advance in string entry fields when pressing Up/Down in insert mode (reported by Udo Richter). - Fixed handling the "Setup/OSD/Menu button closes" option when set to 'yes' in case a replay is active (thanks to Udo Richter). - Improved cUnbufferedFile; USE_FADVISE is now defined in tools.c by default, so if you don't want to use "fadvise" you need to comment out that line (thanks to Artur Skawina). - Fixed a missing ',' in the Swedish OSD texts (thanks to Arthur Konovalov). - cDevice::Transferring() can now be used to determine whether the (primary) device is currently playing in Transfer Mode (based on a suggestion by Reinhard Nissl). - The 'runvdr' script no longer uses the $VDRUSR environment variable to set the user id under which 'vdr' shall run. Just add the '-u username' option when you call 'runvdr'. - Fixed multiple entries of the same subdirectory in the "Recordings" menu (reported by Christian Jacobsen). - Enabled generating a core dump if VDR is run with a different user id (thanks to Ville Skyttä). - Fixed handling the "Blue" key in the "Schedule" menu for the current channel (thanks to Rolf Ahrenberg). - Renamed the Makefile target 'plugins-clean' to 'clean-plugins' (suggested by Sebastian Frei). - Made all font and image data 'const' (thanks to Darren Salt). - Fixed scrolling with Up/Down in case there are non-selectable items at the beginning or end of the menu (reported by Helmut Auer). - Added cSkin::GetTextAreaWidth() and cSkin::GetTextAreaFont(), so that a plugin that wants to do special text formatting can do so (thanks to Alexander Rieger).
Diffstat (limited to 'tools.c')
-rw-r--r--tools.c174
1 files changed, 116 insertions, 58 deletions
diff --git a/tools.c b/tools.c
index 031c120..fb88789 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.112 2006/01/20 14:01:28 kls Exp $
+ * $Id: tools.c 1.114 2006/02/05 11:05:56 kls Exp $
*/
#include "tools.h"
@@ -1054,10 +1054,9 @@ bool cSafeFile::Close(void)
// --- cUnbufferedFile -------------------------------------------------------
-//#define USE_FADVISE
+#define USE_FADVISE
-#define READ_AHEAD MEGABYTE(2)
-#define WRITE_BUFFER MEGABYTE(10)
+#define WRITE_BUFFER KILOBYTE(800)
cUnbufferedFile::cUnbufferedFile(void)
{
@@ -1073,8 +1072,17 @@ int cUnbufferedFile::Open(const char *FileName, int Flags, mode_t Mode)
{
Close();
fd = open(FileName, Flags, Mode);
- begin = end = ahead = -1;
+ curpos = 0;
+#ifdef USE_FADVISE
+ begin = lastpos = ahead = 0;
+ cachedstart = 0;
+ cachedend = 0;
+ readahead = KILOBYTE(128);
written = 0;
+ totwritten = 0;
+ if (fd >= 0)
+ posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); // we could use POSIX_FADV_SEQUENTIAL, but we do our own readahead, disabling the kernel one.
+#endif
return fd;
}
@@ -1082,16 +1090,9 @@ int cUnbufferedFile::Close(void)
{
#ifdef USE_FADVISE
if (fd >= 0) {
- if (ahead > end)
- end = ahead;
- if (begin >= 0 && end > begin) {
- //dsyslog("close buffer: %d (flush: %d bytes, %ld-%ld)", fd, written, begin, end);
- if (written)
- fdatasync(fd);
- posix_fadvise(fd, begin, end - begin, POSIX_FADV_DONTNEED);
- }
- begin = end = ahead = -1;
- written = 0;
+ if (totwritten) // if we wrote anything make sure the data has hit the disk before
+ fdatasync(fd); // calling fadvise, as this is our last chance to un-cache it.
+ posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
}
#endif
int OldFd = fd;
@@ -1099,45 +1100,84 @@ int cUnbufferedFile::Close(void)
return close(OldFd);
}
+// When replaying and going e.g. FF->PLAY the position jumps back 2..8M
+// hence we do not want to drop recently accessed data at once.
+// We try to handle the common cases such as PLAY->FF->PLAY, small
+// jumps, moving editing marks etc.
+
+#define FADVGRAN KILOBYTE(4) // AKA fadvise-chunk-size; PAGE_SIZE or getpagesize(2) would also work.
+#define READCHUNK MEGABYTE(8)
+
+void cUnbufferedFile::SetReadAhead(size_t ra)
+{
+ readahead = ra;
+}
+
+int cUnbufferedFile::FadviseDrop(off_t Offset, off_t Len)
+{
+ // rounding up the window to make sure that not PAGE_SIZE-aligned data gets freed.
+ return posix_fadvise(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED);
+}
+
off_t cUnbufferedFile::Seek(off_t Offset, int Whence)
{
- if (fd >= 0)
- return lseek(fd, Offset, Whence);
- return -1;
+ if (Whence == SEEK_SET && Offset == curpos)
+ return curpos;
+ curpos = lseek(fd, Offset, Whence);
+ return curpos;
}
ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
{
if (fd >= 0) {
#ifdef USE_FADVISE
- off_t pos = lseek(fd, 0, SEEK_CUR);
- // jump forward - adjust end position
- if (pos > end)
- end = pos;
- // after adjusting end - don't clear more than previously requested
- if (end > ahead)
- end = ahead;
- // jump backward - drop read ahead of previous run
- if (pos < begin)
- end = ahead;
- if (begin >= 0 && end > begin)
- posix_fadvise(fd, begin - KILOBYTE(200), end - begin + KILOBYTE(200), POSIX_FADV_DONTNEED);//XXX macros/parameters???
- begin = pos;
+ off_t jumped = curpos-lastpos; // nonzero means we're not at the last offset
+ if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) {
+ // current position is outside the cached window -- invalidate it.
+ FadviseDrop(cachedstart, cachedend-cachedstart);
+ cachedstart = curpos;
+ cachedend = curpos;
+ }
+ cachedstart = min(cachedstart, curpos);
#endif
ssize_t bytesRead = safe_read(fd, Data, Size);
#ifdef USE_FADVISE
if (bytesRead > 0) {
- pos += bytesRead;
- end = pos;
- // this seems to trigger a non blocking read - this
- // may or may not have been finished when we will be called next time.
- // If it is not finished we can't release the not yet filled buffers.
- // So this is commented out till we find a better solution.
- //posix_fadvise(fd, pos, READ_AHEAD, POSIX_FADV_WILLNEED);
- ahead = pos + READ_AHEAD;
+ curpos += bytesRead;
+ cachedend = max(cachedend, curpos);
+
+ // Read ahead:
+ // no jump? (allow small forward jump still inside readahead window).
+ if (jumped >= 0 && jumped <= (off_t)readahead) {
+ // Trigger the readahead IO, but only if we've used at least
+ // 1/2 of the previously requested area. This avoids calling
+ // fadvise() after every read() call.
+ if (ahead - curpos < (off_t)(readahead / 2)) {
+ posix_fadvise(fd, curpos, readahead, POSIX_FADV_WILLNEED);
+ ahead = curpos + readahead;
+ cachedend = max(cachedend, ahead);
+ }
+ if (readahead < Size * 32) { // automagically tune readahead size.
+ readahead = Size * 32;
+ }
+ }
+ else
+ ahead = curpos; // jumped -> we really don't want any readahead, otherwise e.g. fast-rewind gets in trouble.
}
- else
- end = pos;
+
+ if (cachedstart < cachedend) {
+ if (curpos - cachedstart > READCHUNK * 2) {
+ // current position has moved forward enough, shrink tail window.
+ FadviseDrop(cachedstart, curpos - READCHUNK - cachedstart);
+ cachedstart = curpos - READCHUNK;
+ }
+ else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) {
+ // current position has moved back enough, shrink head window.
+ FadviseDrop(curpos + READCHUNK, cachedend - curpos + READCHUNK);
+ cachedend = curpos + READCHUNK;
+ }
+ }
+ lastpos = curpos;
#endif
return bytesRead;
}
@@ -1147,28 +1187,46 @@ ssize_t cUnbufferedFile::Read(void *Data, size_t Size)
ssize_t cUnbufferedFile::Write(const void *Data, size_t Size)
{
if (fd >=0) {
-#ifdef USE_FADVISE
- off_t pos = lseek(fd, 0, SEEK_CUR);
-#endif
ssize_t bytesWritten = safe_write(fd, Data, Size);
#ifdef USE_FADVISE
- if (bytesWritten >= 0) {
+ if (bytesWritten > 0) {
+ begin = min(begin, curpos);
+ curpos += bytesWritten;
written += bytesWritten;
- if (begin >= 0) {
- if (pos < begin)
- begin = pos;
- }
- else
- begin = pos;
- if (pos + bytesWritten > end)
- end = pos + bytesWritten;
+ lastpos = max(lastpos, curpos);
if (written > WRITE_BUFFER) {
- //dsyslog("flush buffer: %d (%d bytes, %ld-%ld)", fd, written, begin, end);
- fdatasync(fd);
- if (begin >= 0 && end > begin)
- posix_fadvise(fd, begin, end - begin, POSIX_FADV_DONTNEED);
- begin = end = -1;
+ if (lastpos > begin) {
+ // Now do three things:
+ // 1) Start writeback of begin..lastpos range
+ // 2) Drop the already written range (by the previous fadvise call)
+ // 3) Handle nonpagealigned data.
+ // This is why we double the WRITE_BUFFER; the first time around the
+ // last (partial) page might be skipped, writeback will start only after
+ // second call; the third call will still include this page and finally
+ // drop it from cache.
+ off_t headdrop = min(begin, WRITE_BUFFER * 2L);
+ posix_fadvise(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED);
+ }
+ begin = lastpos = curpos;
+ totwritten += written;
written = 0;
+ // The above fadvise() works when writing slowly (recording), but could
+ // leave cached data around when writing at a high rate, e.g. when cutting,
+ // because by the time we try to flush the cached pages (above) the data
+ // can still be dirty - we are faster than the disk I/O.
+ // So we do another round of flushing, just like above, but at larger
+ // intervals -- this should catch any pages that couldn't be released
+ // earlier.
+ if (totwritten > MEGABYTE(32)) {
+ // It seems in some setups, fadvise() does not trigger any I/O and
+ // a fdatasync() call would be required do all the work (reiserfs with some
+ // kind of write gathering enabled), but the syncs cause (io) load..
+ // Uncomment the next line if you think you need them.
+ //fdatasync(fd);
+ off_t headdrop = min(curpos - totwritten, totwritten * 2L);
+ posix_fadvise(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED);
+ totwritten = 0;
+ }
}
}
#endif