Ticket #6330: locklesstfw-v4.diff

File locklesstfw-v4.diff, 22.8 KB (added by Matthias "mortalmatt" Dahl <devel@…>, 11 years ago)
  • mythtv/libs/libmythtv/ThreadedFileWriterLockless.h

     
     1#ifndef TFW_LOCKLESS_H_
     2#define TFW_LOCKLESS_H_
     3
     4#include <pthread.h>
     5
     6#include <QAtomicInt>
     7#include <QAtomicPointer>
     8#include <QMutex>
     9#include <QWaitCondition>
     10#include <QString>
     11
     12class ThreadedFileWriterLockless
     13{
     14  public:
     15    ThreadedFileWriterLockless(const QString &fname, int flags, mode_t mode);
     16    ~ThreadedFileWriterLockless();
     17
     18    bool Open(void);
     19    long long Seek(long long pos, int whence);
     20    uint Write(const void *data, uint count);
     21
     22    void SetWriteBufferSize(uint newSize = DEFAULT_BUFFER_SIZE);
     23    void SetWriteBufferMinWriteSize(uint newMinSize = MIN_WRITE_SIZE);
     24
     25    uint BufUsed(void) const;
     26    uint BufFree(void) const;
     27
     28    void Sync(void);
     29    void Flush(void);
     30
     31    static uint safe_write(int fd, const void *data, uint count, bool &ok);
     32
     33  protected:
     34    static void *BootWriter(void *);
     35    void DiskWriterLoop(void);
     36
     37    long long WriteFwdFree(const char* readPtr, const char* writePtr) const;
     38    long long ReadFwdFree(const char* readPtr, const char* writePtr) const;
     39    long long WriteFwdContinuousFree(const char* readPtr, const char* writePtr) const;
     40    long long ReadFwdContinuousFree(const char* readPtr, const char* writePtr) const;
     41
     42    void SetupBuffer(uint reqBufferSize);
     43
     44  private:
     45    // file handling related
     46    QString              fileName;
     47    int                  fileFlags;
     48    mode_t               fileMode;
     49    int                  fileFD;
     50    QAtomicPointer<uint> fileMinWriteSize;
     51    long long            fileBytesWritten;
     52
     53    // state flags
     54    QAtomicInt isFlushing;
     55    QAtomicInt isWriterRunning;
     56    QAtomicInt isInDestructor;
     57    QAtomicInt isIgnoringWrites;
     58
     59    // locks and wait conditions
     60    mutable QMutex bufferWriterLock;
     61    mutable QMutex diskWriterLock;
     62
     63    QWaitCondition bufferEmpty;
     64    QWaitCondition bufferHasData;
     65    QWaitCondition bufferWroteData;
     66
     67    // buffer and related
     68    char                *buffer;
     69    char                *bufferEnd;
     70    unsigned long        bufferSize;
     71    QAtomicPointer<char> bufferReadPtr;
     72    QAtomicPointer<char> bufferWritePtr;
     73
     74    // threads
     75    pthread_t writer;
     76
     77  private:
     78    // constants
     79    /// default buffer size
     80    static const uint DEFAULT_BUFFER_SIZE;
     81    /// maximum chunk size to write to disk in one go
     82    static const uint MAX_WRITE_SIZE;
     83    /// minimum chunk size to write to disk in one go (except when flushing)
     84    static const uint MIN_WRITE_SIZE;
     85    /// number of extra bytes to reserve before and after the actual buffer
     86    static const uint BUFFER_CUSHION;
     87    /// maximum write errors for a single call to safe_write before giving up
     88    static const uint MAX_WRITE_ERRORS;
     89};
     90#endif
  • mythtv/libs/libmythtv/libmythtv.pro

     
    163163HEADERS += channelsettings.h        previewgenerator.h
    164164HEADERS += transporteditor.h
    165165HEADERS += myth_imgconvert.h
     166HEADERS += ThreadedFileWriterLockless.h
    166167
    167168# Remove when everything is switched to MythUI
    168169HEADERS += proglist_qt.h
     
    186187SOURCES += progdetails.cpp
    187188SOURCES += channelsettings.cpp      previewgenerator.cpp
    188189SOURCES += transporteditor.cpp
     190SOURCES += ThreadedFileWriterLockless.cpp
    189191
    190192contains( CONFIG_SWSCALE, yes ) {
    191193    SOURCES += myth_imgconvert.cpp
  • mythtv/libs/libmythtv/ThreadedFileWriterLockless.cpp

     
     1// ANSI C headers
     2#include <cerrno>
     3#include <cstring>
     4
     5// Unix C headers
     6#include <sys/types.h>
     7#include <sys/stat.h>
     8#include <fcntl.h>
     9#include <unistd.h>
     10#include <signal.h>
     11
     12// MythTV headers
     13#include "ThreadedFileWriterLockless.h"
     14#include "mythcontext.h"
     15#include "compat.h"
     16#include "mythverbose.h"
     17
     18#define LOC QString("TFWL: ")
     19#define LOC_ERR QString("TFWL, Error: ")
     20
     21const uint ThreadedFileWriterLockless::DEFAULT_BUFFER_SIZE = 2*1024*1024;
     22const uint ThreadedFileWriterLockless::MAX_WRITE_SIZE      = DEFAULT_BUFFER_SIZE / 4;
     23const uint ThreadedFileWriterLockless::MIN_WRITE_SIZE      = DEFAULT_BUFFER_SIZE / 1024 / 32;
     24const uint ThreadedFileWriterLockless::BUFFER_CUSHION      = 512;
     25const uint ThreadedFileWriterLockless::MAX_WRITE_ERRORS    = 10;
     26
     27/** \class ThreadedFileWriterLockless
     28 *  \brief A (almost) lock-free threaded disk writer that buffers data written
     29 *         to it and writes it to the disk in a seperate thread.
     30 *
     31 *  This class implements a threaded ring buffer. All data written via ::Write()
     32 *  is inserted into the ring buffer while a seperate thread reads the data from
     33 *  the buffer and writes it to disk.
     34 *
     35 *  The implementation is intentionally not thread-safe but reentrant.
     36 */
     37
     38/** \fn ThreadedFileWriterLockless::safe_write(int fd, const void *data, uint count, bool &ok)
     39 *  \brief Writes all data to disk and retries in case of errors.
     40 *
     41 *  The standard POSIX write() can return early with no or just a portion of
     42 *  the desired data written to disk. This function tries to make sure that
     43 *  all data gets written to disk by...
     44 *
     45 *    1) endlessly retrying in case of EAGAIN or EINTR errors
     46 *    2) retrying up to MAX_WRITE_ERRORS times in case of other errors
     47 *    3) writing out the rest amount of data until no data is left
     48 *
     49 *  \param fd    File descriptor
     50 *  \param data  Pointer to data to write
     51 *  \param count Size of data to write in bytes
     52 *
     53 *  \return Number of written bytes
     54 */
     55uint ThreadedFileWriterLockless::safe_write(int fd, const void *data,
     56                                            uint count, bool &ok)
     57{
     58    uint bytesWritten = 0;
     59    uint errors       = 0;
     60
     61    while (bytesWritten < count && errors < MAX_WRITE_ERRORS)
     62    {
     63        int ret = write(fd, (char*)data + bytesWritten, count - bytesWritten);
     64
     65        if (ret >= 0)
     66            bytesWritten += ret;
     67        else if (errno != EAGAIN || errno != EINTR)
     68            ++errors;
     69    }
     70
     71    if (errors < MAX_WRITE_ERRORS)
     72        ok = true;
     73    else
     74        ok = false;
     75
     76    return bytesWritten;
     77}
     78
     79/** \fn ThreadedFileWriterLockless::BootWriter(void *tfw)
     80 *  \brief Helper function which simply runs the DiskWriterLoop().
     81 *
     82 *  \param tfw Pointer to ThreadedFileWriterLockless instance
     83 */
     84void *ThreadedFileWriterLockless::BootWriter(void *tfw)
     85{
     86#ifndef USING_MINGW
     87    signal(SIGXFSZ, SIG_IGN);
     88#endif
     89    ((ThreadedFileWriterLockless *)tfw)->DiskWriterLoop();
     90    return NULL;
     91}
     92
     93/** \fn ThreadedFileWriterLockless::ThreadedFileWriterLockless(const QString &fname, int flags, mode_t mode)
     94 *  \brief Constructor
     95 *
     96 *  The constructor sets the filename, the access/creation/status flags and
     97 *  the file permissions. It does not create the file nor does it start the
     98 *  writer thread.
     99 *
     100 *  \param fname  Filename
     101 *  \param flags  Access/Creation/Status flags (see POSIX open())
     102 *  \param mode   File permissions (see POSIX open())
     103 */
     104ThreadedFileWriterLockless::ThreadedFileWriterLockless(const QString &fname,
     105                                                       int flags, mode_t mode) :
     106    // file handling related
     107    fileName(fname), fileFlags(flags), fileMode(mode), fileFD(-1),
     108    fileMinWriteSize(NULL), fileBytesWritten(0),
     109    // state flags
     110    isFlushing(0), isWriterRunning(0), isInDestructor(0), isIgnoringWrites(0),
     111    // buffer and related
     112    buffer(NULL), bufferEnd(NULL), bufferSize(0), bufferReadPtr(NULL),
     113    bufferWritePtr(NULL)
     114{
     115    fileName.detach();
     116}
     117
     118/** \fn ThreadedFileWriterLockless::Open(void)
     119 *  \brief Opens the file we will be writing to and starts the DiskWriter thread.
     120 *
     121 *  \return TRUE if file was opened successfully and DiskWriter thread started
     122 */
     123bool ThreadedFileWriterLockless::Open(void)
     124{
     125    if (isWriterRunning)
     126    {
     127        VERBOSE(VB_IMPORTANT, LOC_ERR +
     128                QString("Opening file '%1' failed. Writer already running")
     129                .arg(fileName));
     130
     131        return false;
     132    }
     133
     134    isFlushing       = 0;
     135    isInDestructor   = 0;
     136    isIgnoringWrites = 0;
     137
     138    bool result = false;
     139
     140    if (fileName == "-")
     141        fileFD = fileno(stdout);
     142    else
     143        fileFD = open(fileName.toAscii().constData(), fileFlags, fileMode);
     144
     145    if (fileFD < 0)
     146    {
     147        VERBOSE(VB_IMPORTANT, LOC_ERR +
     148                QString("Opening file '%1'.").arg(fileName) + ENO);
     149
     150        result = false;
     151    }
     152    else
     153    {
     154        SetupBuffer(DEFAULT_BUFFER_SIZE);
     155        if (fileMinWriteSize == NULL)
     156            fileMinWriteSize = new uint(MIN_WRITE_SIZE);
     157
     158        pthread_create(&writer, NULL, BootWriter, this);
     159/*
     160        if(gContext->GetNumSetting("RealtimePriority", 1))
     161        {
     162            // thread priority in respect to SCHED_RR: 1
     163            struct sched_param sp = {2};
     164
     165            if(!pthread_setschedparam(writer, SCHED_RR, &sp))
     166            {
     167                VERBOSE(VB_GENERAL, LOC +
     168                        "Using realtime priority.");
     169            }
     170            else
     171            {
     172                VERBOSE(VB_IMPORTANT, LOC_ERR +
     173                        "Realtime priority requires sufficient user priviledges.");
     174            }
     175        }
     176*/
     177        result = true;
     178    }
     179
     180    return result;
     181}
     182
     183/** \fn ThreadedFileWriterLockless::~ThreadedFileWriterLockless()
     184 *  \brief Destructor which commits all writes, ends the DiskWriter thread
     185 *         and closes the file.
     186 */
     187ThreadedFileWriterLockless::~ThreadedFileWriterLockless()
     188{
     189    isInDestructor.fetchAndStoreOrdered(1);
     190
     191    if (fileFD >= 0)
     192    {
     193        // wake everyone
     194        bufferHasData.wakeAll();
     195        bufferEmpty.wakeAll();
     196
     197        // if there is still data, flush it to disk
     198        Flush();
     199
     200        pthread_join(writer, NULL);
     201
     202        close(fileFD);
     203    }
     204
     205    if (buffer)
     206        delete [] (buffer - BUFFER_CUSHION);
     207
     208    if (fileMinWriteSize)
     209        delete fileMinWriteSize;
     210}
     211
     212/** \fn ThreadedFileWriterLockless::Write(const void *data, uint count)
     213 *  \brief Writes data to the internal buffer.
     214 *
     215 *  This function writes data to the internal buffer.
     216 *
     217 *  \param data  Pointer to data
     218 *  \param count Size of data in bytes
     219 *
     220 *  \return Returns the number of bytes written
     221 */
     222uint ThreadedFileWriterLockless::Write(const void *data, uint count)
     223{
     224    if (count == 0 || isIgnoringWrites)
     225        return 0;
     226
     227    uint totalWritten = 0;
     228    while (totalWritten < count)
     229    {
     230        char* localWritePtr = static_cast<char*>(bufferWritePtr);
     231        char* localReadPtr  = static_cast<char*>(bufferReadPtr);
     232
     233        uint chunkSize = (count-totalWritten < bufferSize) ? count-totalWritten
     234                                                           : bufferSize / 2;
     235
     236        while (WriteFwdFree(localReadPtr, localWritePtr) < chunkSize)
     237        {
     238            bufferWriterLock.lock();
     239            bufferWroteData.wait(&bufferWriterLock, 150);
     240            bufferWriterLock.unlock();
     241
     242            localWritePtr = static_cast<char*>(bufferWritePtr);
     243            localReadPtr  = static_cast<char*>(bufferReadPtr);
     244        }
     245
     246        long long bufferOffset = 0;
     247        long long dataOffset   = 0;
     248        if (WriteFwdContinuousFree(localReadPtr, localWritePtr) < chunkSize)
     249        {
     250            uint contSize = WriteFwdContinuousFree(localReadPtr, localWritePtr);
     251            memcpy(localWritePtr, data, contSize);
     252
     253            totalWritten += contSize;
     254            dataOffset    = contSize;
     255            chunkSize    -= contSize;
     256
     257            if (localWritePtr + contSize <= bufferEnd)
     258                bufferOffset = contSize;
     259            else
     260                bufferOffset = -(localWritePtr - buffer);
     261        }
     262        memcpy(localWritePtr + bufferOffset, (char*)data + dataOffset, chunkSize);
     263        totalWritten += chunkSize;
     264        bufferOffset += chunkSize;
     265
     266        bufferWritePtr.fetchAndStoreOrdered(localWritePtr + bufferOffset);
     267
     268        bufferHasData.wakeAll();
     269    }
     270
     271    return totalWritten;
     272}
     273
     274/** \fn ThreadedFileWriterLockless::Seek(long long pos, int whence)
     275 *  \brief Seek to a position within the disk file
     276 *
     277 *  \param pos    New file offset (with regards to whence)
     278 *  \param whence Specifies how to interpret offset (see lseek())
     279 *
     280 *  \return Resulting offset
     281 */
     282long long ThreadedFileWriterLockless::Seek(long long pos, int whence)
     283{
     284    Flush();
     285
     286    return lseek(fileFD, pos, whence);
     287}
     288
     289/** \fn ThreadedFileWriterLockless::Flush(void)
     290 *  \brief Instructs the DiskWriter thread to flush all remaining data in the
     291 *         ring buffer to the disk. If the DiskWriter thread is currently ignoring
     292 *         writes to the disk because of e.g. previous errors, the buffer just
     293 *         gets discarded.
     294 *
     295 *  \warning This call is expensive!
     296 */
     297void ThreadedFileWriterLockless::Flush(void)
     298{
     299    isFlushing.fetchAndStoreOrdered(1);
     300
     301    // wake up DiskWriter thread
     302    bufferHasData.wakeAll();
     303
     304    diskWriterLock.lock();
     305    // loop as long as there is still data in the buffer or an ongoing write()
     306    // is registered which could potentially fill up the buffer
     307    while (BufUsed() > 0)
     308    {
     309        if (!bufferEmpty.wait(&diskWriterLock, 2000))
     310           VERBOSE(VB_IMPORTANT, LOC + "Taking a long time to flush...");
     311    }
     312    diskWriterLock.unlock();
     313
     314    isFlushing.fetchAndStoreOrdered(0);
     315}
     316
     317/** \fn ThreadedFileWriterLockless::Sync(void)
     318 *  \brief Instructs the OS to sync all file data associated data to the disk.
     319 *
     320 *  \warning This is a very expensive call which blocks until the data is on
     321 *           the disk. Some filesystems (e.g. ext3) sync the entire filesystem
     322 *           data to disk, not only the file associated ones. This can cause
     323 *           high latency and delays if used extensively. Use with care.
     324 */
     325void ThreadedFileWriterLockless::Sync(void)
     326{
     327    if (fileFD >= 0)
     328    {
     329#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
     330        fdatasync(fileFD);
     331#else
     332        fsync(fileFD);
     333#endif
     334    }
     335}
     336
     337/** \fn ThreadedFileWriterLockless::SetWriteBufferSize(uint newSize)
     338 *  \brief Sets the total size of the internal ringbuffer.
     339 *
     340 *  \warning This is an expensive call because all data currently in the ring
     341 *           buffer is flushed to the disk.
     342 *
     343 *  \param newSize New ringbuffer size in bytes
     344 */
     345void ThreadedFileWriterLockless::SetWriteBufferSize(uint newSize)
     346{
     347    if (newSize <= 0)
     348        return;
     349
     350    Flush();
     351    SetupBuffer(newSize);
     352}
     353
     354/** \fn ThreadedFileWriterLockless::SetWriteBufferMinWriteSize(uint newMinSize)
     355 *  \brief Sets the minumum number of bytes to write to disk in a single write.
     356 *
     357 *  \param newMinSize New minimum size in bytes for a single write
     358 */
     359void ThreadedFileWriterLockless::SetWriteBufferMinWriteSize(uint newMinSize)
     360{
     361    if (newMinSize <= 0)
     362        return;
     363
     364    delete(fileMinWriteSize.fetchAndStoreOrdered(new uint(newMinSize)));
     365}
     366
     367/** \fn ThreadedFileWriterLockless::DiskLoop(void)
     368 *  \brief DiskWriter thread which reads data from the ring buffer and writes it
     369 *         out to the disk.
     370 *
     371 *  The DiskWriterLoop() tries to free space as soon as possible but is limited
     372 *  by the minimum and maximum write size for a single write. Setting those
     373 *  higher can increase throughput but also latency.
     374 *
     375 */
     376void ThreadedFileWriterLockless::DiskWriterLoop(void)
     377{
     378    while (!isInDestructor || BufUsed() > 0)
     379    {
     380        uint bufferUsage = BufUsed();
     381
     382        if (!bufferUsage)
     383            bufferEmpty.wakeAll();
     384
     385        if (!bufferUsage || (!isInDestructor && !isFlushing &&
     386                             *fileMinWriteSize > bufferUsage
     387                             && *fileMinWriteSize <= fileBytesWritten))
     388        {
     389            diskWriterLock.lock();
     390            bufferHasData.wait(&diskWriterLock, 250);
     391            diskWriterLock.unlock();
     392            continue;
     393        }
     394
     395        uint  currWritten   = 0;
     396        char* localReadPtr  = bufferReadPtr;
     397        char* localWritePtr = bufferWritePtr;
     398        bool  wasWriteOk    = true;
     399
     400        while (wasWriteOk && bufferUsage > 0
     401               && ReadFwdFree(localReadPtr, localWritePtr) > 0)
     402        {
     403            long long contSize  = ReadFwdContinuousFree(localReadPtr, localWritePtr);
     404            long long chunkSize = (bufferUsage <= contSize) ? bufferUsage : contSize;
     405
     406            if (chunkSize > MAX_WRITE_SIZE && !isFlushing)
     407                chunkSize = MAX_WRITE_SIZE;
     408
     409            if (!isIgnoringWrites)
     410                chunkSize = safe_write(fileFD, localReadPtr, chunkSize, wasWriteOk);
     411
     412            bufferUsage  -= chunkSize;
     413            currWritten  += chunkSize;
     414            localReadPtr += chunkSize;
     415
     416            if (localReadPtr > bufferEnd)
     417                localReadPtr = buffer;
     418
     419            bufferReadPtr.fetchAndStoreOrdered(localReadPtr);
     420            bufferWroteData.wakeAll();
     421        }
     422
     423        if (!isIgnoringWrites)
     424        {
     425            if (!wasWriteOk && (EFBIG == errno))
     426            {
     427                QString msg =
     428                    "Maximum file size exceeded by '%1'"
     429                    "\n\t\t\t"
     430                    "You must either change the process ulimits, configure"
     431                    "\n\t\t\t"
     432                    "your operating system with \"Large File\" support, or use"
     433                    "\n\t\t\t"
     434                    "a filesystem which supports 64-bit or 128-bit files."
     435                    "\n\t\t\t"
     436                    "HINT: FAT32 is a 32-bit filesystem.";
     437
     438                VERBOSE(VB_IMPORTANT, msg.arg(fileName));
     439                isIgnoringWrites.fetchAndStoreOrdered(1);
     440            }
     441
     442            // if we wrote anything, make sure it gets uncached
     443            if (currWritten > 0)
     444            {
     445                posix_fadvise(fileFD, fileBytesWritten, currWritten, POSIX_FADV_DONTNEED);
     446
     447                fileBytesWritten += currWritten;
     448            }
     449        }
     450    }
     451}
     452
     453/** \fn ThreadedFileWriterLockless::BufUsed(void) const
     454 *  \brief Gets the buffer usage in bytes which are queued for disk write
     455 *
     456 *  \return Buffer usage in bytes
     457 */
     458uint ThreadedFileWriterLockless::BufUsed(void) const
     459{
     460    return (bufferSize-1) - BufFree();
     461}
     462
     463/** \fn ThreadedFileWriterLockless::BufFree(void) const
     464 *  \brief Gets the free buffer space in bytes
     465 *
     466 *  \return Free buffer space in bytes
     467 */
     468uint ThreadedFileWriterLockless::BufFree(void) const
     469{
     470    return WriteFwdFree(bufferReadPtr, bufferWritePtr);
     471}
     472
     473/** \fn ThreadedFileWriterLockless::WriteFwdFree(void) const
     474 *  \brief Gets the number of bytes available for write to the ring buffer
     475 *         from the write pointer with regards to the passed pointers.
     476 *
     477 *  \return Free buffer space in bytes for write.
     478 */
     479long long ThreadedFileWriterLockless::WriteFwdFree(const char* readPtr, const char* writePtr) const
     480{
     481    return (readPtr - writePtr) + ((readPtr <= writePtr) ? bufferSize : 0) - 1;
     482}
     483
     484/** \fn ThreadedFileWriterLockless::ReadFwdFree(void) const
     485 *  \brief Gets the number of bytes available for read from the ring buffer
     486 *         from the read pointer with regards to the passed pointers.
     487 *
     488 *  \return Bytes available for read from the buffer
     489 */
     490long long ThreadedFileWriterLockless::ReadFwdFree(const char *readPtr,
     491                                                  const char *writePtr) const
     492{
     493    return (writePtr - readPtr) + ((readPtr <= writePtr) ? 0 : bufferSize);
     494}
     495
     496/** \fn ThreadedFileWriterLockless::WriteFwdContinuousFree(void) const
     497 *  \brief Gets the number of connected bytes available for write to the ring buffer
     498 *         from the write pointer with regards to the passed pointers.
     499 *
     500 *  \return Free buffer space in bytes for write.
     501 */
     502long long ThreadedFileWriterLockless::WriteFwdContinuousFree(const char* readPtr,
     503                                                             const char* writePtr) const
     504{
     505    uint offset = (readPtr > buffer) ? 1 : 0;
     506
     507    return (readPtr <= writePtr) ? (bufferEnd - writePtr) + offset
     508                          : (readPtr - writePtr) - 1;
     509}
     510
     511/** \fn ThreadedFileWriterLockless::ReadFwdContinuousFree(void) const
     512 *  \brief Gets the number of connected bytes available for read from the ring
     513 *         buffer from the read pointer with regards to the passed pointers.
     514 *
     515 *  \return Bytes available for read from the buffer
     516 */
     517long long ThreadedFileWriterLockless::ReadFwdContinuousFree(const char* readPtr,
     518                                                            const char* writePtr) const
     519{
     520    return ((readPtr <= writePtr) ? writePtr : (bufferEnd + 1)) - readPtr;
     521}
     522
     523/** \fn ThreadedFileWriterLockless::SetupBuffer(void)
     524 *  \brief Helper function which sets up the buffer and all necessary pointers.
     525 *
     526 *  \param reqBufferSize Requested buffer size
     527 */
     528void ThreadedFileWriterLockless::SetupBuffer(uint reqBufferSize)
     529{
     530    if (buffer)
     531        delete [] (buffer - BUFFER_CUSHION);
     532
     533    buffer = new char[1 + reqBufferSize + 2 * BUFFER_CUSHION];
     534    bzero(buffer, reqBufferSize + 2 * BUFFER_CUSHION);
     535
     536    buffer    += BUFFER_CUSHION;
     537    bufferSize = reqBufferSize;
     538    bufferEnd  = buffer + (reqBufferSize-1);
     539
     540    bufferWritePtr.fetchAndStoreOrdered(buffer);
     541    bufferReadPtr.fetchAndStoreOrdered(buffer);
     542}
  • mythtv/libs/libmythtv/RingBuffer.cpp

     
    2323#include "RingBuffer.h"
    2424#include "remotefile.h"
    2525#include "remoteencoder.h"
     26
    2627#include "ThreadedFileWriter.h"
     28#include "ThreadedFileWriterLockless.h"
     29
    2730#include "livetvchain.h"
    2831#include "DVDRingBuffer.h"
    2932#include "util.h"
     
    132135
    133136    if (write)
    134137    {
     138#if QT_VERSION < 0x040400
    135139        tfw = new ThreadedFileWriter(
     140#else
     141        tfw = new ThreadedFileWriterLockless(
     142#endif
    136143            filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644);
    137144
    138145        if (!tfw->Open())
  • mythtv/libs/libmythtv/RingBuffer.h

     
    1616
    1717class RemoteFile;
    1818class RemoteEncoder;
     19
    1920class ThreadedFileWriter;
     21class ThreadedFileWriterLockless;
     22
    2023class DVDRingBufferPriv;
    2124class LiveTVChain;
    2225
     
    118121  private:
    119122    QString filename;
    120123
     124#if QT_VERSION < 0x040400
    121125    ThreadedFileWriter *tfw;
     126#else
     127    ThreadedFileWriterLockless *tfw;
     128#endif
    122129    int fd2;
    123130
    124131    bool writemode;