Ticket #603: mythmedia_locking.diff

File mythmedia_locking.diff, 8.0 KB (added by Aaron McCarthy <mccarthy.aaron@…>, 13 years ago)
  • libs/libmythui/mythmainwindow.cpp

     
    11261126                iscatched = activedialog->onMediaEvent(pDev);
    11271127            if (!iscatched)
    11281128            {
    1129                 while (itr != d->mediaHandlerMap.end())
     1129                MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
     1130                if (mon && mon->ValidateAndLock(pDev))
    11301131                {
    1131                    if ((itr.data().MediaType & (int)pDev->getMediaType()))
    1132                    {
    1133                        VERBOSE(VB_IMPORTANT, "Found a handler");
    1134                        d->exitingtomain = true;
    1135                        d->exitmenumediadevicecallback = itr.data().callback;
    1136                        d->mediadeviceforcallback = pDev;
    1137                        QApplication::postEvent(this, new ExitToMainMenuEvent());
    1138                        break;
    1139                    }
    1140                    itr++;
     1132                    while (itr != d->mediaHandlerMap.end())
     1133                    {
     1134                       if ((itr.data().MediaType & (int)pDev->getMediaType()))
     1135                       {
     1136                           VERBOSE(VB_IMPORTANT, "Found a handler");
     1137                           d->exitingtomain = true;
     1138                           d->exitmenumediadevicecallback = itr.data().callback;
     1139                           d->mediadeviceforcallback = pDev;
     1140                           QApplication::postEvent(this, new ExitToMainMenuEvent());
     1141                           mon->Unlock(pDev);
     1142                           break;
     1143                       }
     1144                       itr++;
     1145                    }
     1146                    mon->Unlock(pDev);
    11411147                }
    11421148            }
    11431149        }
  • libs/libmyth/mythmediamonitor.h

     
    4343    unsigned long m_Interval;
    4444};
    4545
    46 class MediaMonitor;
    47 
    4846class MediaMonitor : public QObject
    4947{
    5048    Q_OBJECT
     
    6462
    6563    static MediaMonitor *GetMediaMonitor(void);
    6664
    67     // this is not safe.. device could get deleted...
    68     QValueList <MythMediaDevice*> GetMedias(MediaType mediatype);
     65    bool ValidateAndLock(MythMediaDevice *pMedia);
     66    void Unlock(MythMediaDevice *pMedia);
    6967
     68    // To safely dereference the pointers returned by this function
     69    // first validate the pointer with ValidateAndLock(), if true is returned
     70    // it is safe to dereference the pointer. When finished call Unlock()
     71    QValueList<MythMediaDevice*> GetMedias(MediaType mediatype);
     72
    7073  public slots:
    7174    void mediaStatusChanged(MediaStatus oldStatus, MythMediaDevice* pMedia);
    7275
     
    8790    static QStringList GetCDROMBlockDevices(void);
    8891
    8992  protected:
     93    QMutex                       m_DevicesLock;
    9094    QValueList<MythMediaDevice*> m_Devices;
     95    QValueList<MythMediaDevice*> m_RemovedDevices;
     96    QMap<MythMediaDevice*, int>  m_UseCount;
     97
    9198    bool                         m_Active;
    9299    MonitorThread                m_Thread;
    93100    bool                         m_AllowEject;
  • libs/libmyth/mythmediamonitor.cpp

     
    107107{
    108108    MythMediaDevice *selected = NULL;
    109109
     110    QMutexLocker locker(&m_DevicesLock);
     111
    110112    if (m_Devices.count() == 1)
    111113    {
    112114        if (m_Devices.first()->getAllowEject())
     
    194196
    195197MediaMonitor::MediaMonitor(QObject* par, unsigned long interval,
    196198                           bool allowEject)
    197     : QObject(par), m_Active(false), m_Thread(NULL, interval),
     199    : QObject(par), m_Active(false), m_Thread(this, interval),
    198200      m_AllowEject(allowEject), m_fifo(-1)
    199201{
    200202}
     
    348350// Given a media deivce add it to our collection.
    349351void MediaMonitor::AddDevice(MythMediaDevice* pDevice)
    350352{
     353    QMutexLocker locker(&m_DevicesLock);
     354
    351355    connect(pDevice, SIGNAL(statusChanged(MediaStatus, MythMediaDevice*)),
    352356            this, SLOT(mediaStatusChanged(MediaStatus, MythMediaDevice*)));
    353357    m_Devices.push_back( pDevice );
     358    m_UseCount[pDevice] = 0;
    354359}
    355360
    356361// Given a fstab entry to a media device determine what type of device it is
     
    575580 */
    576581bool MediaMonitor::RemoveDevice(const QString &dev)
    577582{
     583    QMutexLocker locker(&m_DevicesLock);
     584
    578585    QValueList<MythMediaDevice*>::iterator it;
    579586    for (it = m_Devices.begin(); it != m_Devices.end(); it++)
    580587    {
    581588        if ((*it)->getDevicePath() == dev)
    582589        {
    583             m_Devices.remove(it);
     590            if (m_UseCount[*it] == 0)
     591            {
     592                delete *it;
     593                m_Devices.remove(it);
     594                m_UseCount.remove(*it);
     595            }
     596            else
     597            {
     598                // Other threads are still using this device
     599                // postpone actual delete until they finish.
     600                disconnect(*it);
     601                m_RemovedDevices.append(*it);
     602                m_Devices.remove(it);
     603            }
     604
    584605            return true;
    585606        }
    586607    }
     608
    587609    return false;
    588610}
    589611
     
    681703    m_Thread.wait();
    682704}
    683705
    684 // Ask for available media
    685 // this is not safe.. device could get deleted...
    686 QValueList <MythMediaDevice*> MediaMonitor::GetMedias(MediaType mediatype)
     706/** \fn MediaMonitor::ValidateAndLock(MythMediaDevice *pMedia)
     707 *  \brief Validates the MythMediaDevice and increments its reference count
     708 *
     709 *  Returns true if pMedia device is valid, otherwise returns false.
     710 *  If this function returns false the caller should gracefully recover.
     711 *
     712 *  NOTE: This function can block.
     713 *
     714 *  \sa Unlock(MythMediaDevice *pMedia), GetMedias(MediaType mediatype)
     715 */
     716bool MediaMonitor::ValidateAndLock(MythMediaDevice *pMedia)
    687717{
    688     QValueList <MythMediaDevice*> medias;
     718    QMutexLocker locker(&m_DevicesLock);
    689719
    690     QValueList <MythMediaDevice*>::iterator it = m_Devices.begin();
     720    if (!m_Devices.contains(pMedia))
     721        return false;
     722
     723    m_UseCount[pMedia]++;
     724
     725    return true;
     726}
     727
     728/** \fn MediaMonitor::Unlock(MythMediaDevice *pMedia)
     729 *  \brief decrements the MythMediaDevices reference count
     730 *
     731 *  \sa ValidateAndLock(MythMediaDevice *pMedia), GetMedias(MediaType mediatype)
     732 */
     733void MediaMonitor::Unlock(MythMediaDevice *pMedia)
     734{
     735    QMutexLocker locker(&m_DevicesLock);
     736
     737    if (!m_UseCount.contains(pMedia))
     738        return;
     739
     740    m_UseCount[pMedia]--;
     741
     742    if (m_UseCount[pMedia] == 0 && m_RemovedDevices.contains(pMedia))
     743    {
     744        delete pMedia;
     745        m_RemovedDevices.remove(pMedia);
     746        m_UseCount.remove(pMedia);
     747    }
     748}
     749
     750/** \fn MediaMonitor::GetMedias(MediaType mediatype)
     751 *  \brief Ask for available media
     752 *
     753 *  GetMedias returns a list of MythMediaDevice pointers which match the given mediatype.
     754 *
     755 *  It is potentially unsafe to use the pointers returned by this function. The devices
     756 *  may be removed and their associated MythMediaDevice objects destroyed. It is the
     757 *  responsibility of the caller to ensure that the pointers are validated and
     758 *  and the reference count is incremented by calling MediaMonitor::ValidateAndLock()
     759 *  before the the returned pointer is dereferenced and MediaMonitor::Unlock() when
     760 *  done.
     761 *
     762 * \sa ValidateAndLock(MythMediaDevice *pMedia), Unlock(MythMediaDevice *pMedia)
     763 */
     764QValueList<MythMediaDevice*> MediaMonitor::GetMedias(MediaType mediatype)
     765{
     766    QMutexLocker locker(&m_DevicesLock);
     767
     768    QValueList<MythMediaDevice*> medias;
     769
     770    QValueList<MythMediaDevice*>::iterator it = m_Devices.begin();
    691771    for (;it != m_Devices.end(); it++)
    692772    {
    693773        if (((*it)->getMediaType() == mediatype) &&
     
    701781
    702782    return medias;
    703783}
     784
    704785// Signal handler.
    705786void MediaMonitor::mediaStatusChanged(MediaStatus oldStatus,
    706787                                      MythMediaDevice* pMedia)