Ticket #1871: 1871-v2.patch

File 1871-v2.patch, 19.3 KB (added by danielk, 18 years ago)

A more radical fix (please attach a full backtrace with this patch applied)

  • libs/libmythtv/videobuffers.h

     
    137137  private:
    138138    frame_queue_t         *queue(BufferType type);
    139139    const frame_queue_t   *queue(BufferType type) const;
     140    VideoFrame            *GetNextFreeFrameInternal(
     141        bool with_lock, bool allow_unsafe, BufferType enqueue_to);
    140142
    141143    frame_queue_t          available, used, limbo, pause, displayed, decode;
    142144    vbuffer_map_t          vbufferMap; // videobuffers to buffer's index
     
    160162    uint                   vpos;
    161163
    162164    mutable QMutex         global_lock;
    163     QMutex                 inheritence_lock;
    164165
    165166    bool                   use_frame_locks;
    166167    QMutex                 frame_lock;
  • libs/libmythtv/videobuffers.cpp

     
    8484    : numbuffers(0), needfreeframes(0), needprebufferframes(0),
    8585      needprebufferframes_normal(0), needprebufferframes_small(0),
    8686      keepprebufferframes(0), need_extra_for_pause(false), rpos(0), vpos(0),
    87       global_lock(true), inheritence_lock(false), use_frame_locks(true),
     87      global_lock(true), use_frame_locks(true),
    8888      frame_lock(true)
    8989{
    9090}
     
    123123                        uint needprebuffer_small, uint keepprebuffer,
    124124                        bool enable_frame_locking)
    125125{
    126     global_lock.lock();
     126    QMutexLocker locker(&global_lock);
    127127
    128128    Reset();
    129129
     
    154154
    155155    for (uint i = 0; i < numdecode; i++)
    156156        enqueue(kVideoBuffer_avail, at(i));
    157    
    158     global_lock.unlock();
    159157}
    160158
    161159/**
     
    164162 */
    165163void VideoBuffers::Reset()
    166164{
    167     global_lock.lock();
     165    QMutexLocker locker(&global_lock);
    168166
    169167    // Delete ffmpeg VideoFrames so we can create
    170168    // a different number of buffers below
     
    185183    displayed.clear();
    186184    parents.clear();
    187185    children.clear();
    188 
    189186    vbufferMap.clear();
    190 
    191     global_lock.unlock();
    192187}
    193188
    194189/**
     
    197192 */
    198193void VideoBuffers::SetPrebuffering(bool normal)
    199194{
    200     global_lock.lock();
    201 
     195    QMutexLocker locker(&global_lock);
    202196    needprebufferframes = (normal) ?
    203197        needprebufferframes_normal : needprebufferframes_small;
    204 
    205     global_lock.unlock();
    206198};
    207199
     200VideoFrame *VideoBuffers::GetNextFreeFrameInternal(
     201    bool with_lock, bool allow_unsafe, BufferType enqueue_to)
     202{
     203    QMutexLocker locker(&global_lock);
     204    VideoFrame *frame = available.dequeue();
     205
     206    // Try to get a frame not being used by the decoder
     207    for (uint i = 0; i <= available.size() && decode.contains(frame); i++)
     208    {
     209        if (!available.contains(frame))
     210            available.enqueue(frame);
     211        frame = available.dequeue();
     212    }
     213
     214    while (frame && used.contains(frame))
     215    {
     216        VERBOSE(VB_IMPORTANT,
     217                QString("GetNextFreeFrame() served a busy frame %1. "
     218                        "Dropping. %2")
     219                .arg(DebugString(frame, true)).arg(GetStatus()));
     220        frame = available.dequeue();
     221    }
     222
     223    // only way this should be triggered if we're in unsafe mode
     224    if (!frame && allow_unsafe)
     225    {
     226        VERBOSE(VB_PLAYBACK,
     227                QString("GetNextFreeFrame() is getting a busy frame %1. "
     228                        "      %2")
     229                .arg(DebugString(frame, true)).arg(GetStatus()));
     230        frame = used.dequeue();
     231        if (EnoughFreeFrames())
     232            available_wait.wakeAll();
     233    }
     234
     235    if (frame)
     236    {
     237        safeEnqueue(enqueue_to, frame);
     238
     239        bool success = true;
     240        if (with_lock)
     241            success = TryLockFrame(frame, "GetNextFreeFrame");
     242
     243        if (!success)
     244        {
     245            safeEnqueue(kVideoBuffer_avail, frame);
     246            VERBOSE(VB_IMPORTANT,
     247                QString("GetNextFreeFrame() unable to lock frame %1. "
     248                        "Dropping %2. w/lock(%3) unsafe(%4)")
     249                    .arg(DebugString(frame)).arg(GetStatus())
     250                    .arg(with_lock).arg(allow_unsafe));
     251            DiscardFrame(frame);
     252            frame = NULL;
     253        }
     254    }
     255
     256    return frame;
     257}
     258
    208259/**
    209260 * \fn VideoBuffers::GetNextFreeFrame(bool,bool,BufferType)
    210261 *  Gets a frame from available buffers list.
     
    219270                                           bool allow_unsafe,
    220271                                           BufferType enqueue_to)
    221272{
    222     VideoFrame *frame = NULL;
    223     uint tries = 0;
    224     bool success = false;
    225     while (!success)
     273    for (uint tries = 1; true; tries++)
    226274    {
    227         success = false;
    228         global_lock.lock();
    229         frame = available.dequeue();
     275        VideoFrame *frame = VideoBuffers::GetNextFreeFrameInternal(
     276            with_lock, allow_unsafe, enqueue_to);
    230277
    231         // Try to get a frame not being used by the decoder
    232         for (uint i = 0; i <= available.size() && decode.contains(frame); i++)
    233         {
    234             if (!available.contains(frame))
    235                 available.enqueue(frame);
    236             frame = available.dequeue();
    237         }
     278        if (frame)
     279            return frame;
    238280
    239         while (frame && used.contains(frame))
     281        if (tries >= TRY_LOCK_SPINS)
    240282        {
    241             VERBOSE(VB_IMPORTANT,
    242                     QString("GetNextFreeFrame() served a busy frame %1. "
    243                             "Dropping. %2")
    244                     .arg(DebugString(frame, true)).arg(GetStatus()));
    245             frame = available.dequeue();
     283            VERBOSE(VB_IMPORTANT,
     284                    QString("GetNextFreeFrame() unable to "
     285                            "lock frame %1 times. Discarding Frames.")
     286                    .arg(TRY_LOCK_SPINS));
     287            DiscardFrames(true);
     288            continue;
    246289        }
    247290
    248         // only way this should be triggered if we're in unsafe mode
    249         if (!frame && allow_unsafe)
     291        if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING))
    250292        {
    251293            VERBOSE(VB_PLAYBACK,
    252                     QString("GetNextFreeFrame() is getting a busy frame %1. "
    253                             "      %2")
    254                     .arg(DebugString(frame, true)).arg(GetStatus()));
    255             frame = used.dequeue();
    256             if (EnoughFreeFrames())
    257                 available_wait.wakeAll();
     294                    QString("GetNextFreeFrame() TryLock has "
     295                            "spun %1 times, this is a lot.").arg(tries));
    258296        }
    259         if (frame)
    260         {
    261             safeEnqueue(enqueue_to, frame);
    262 
    263             success = true;
    264             if (with_lock)
    265                 success = TryLockFrame(frame, "GetNextFreeFrame");
    266             if (!success)
    267                 safeEnqueue(kVideoBuffer_avail, frame);
    268         }
    269 
    270         global_lock.unlock();
    271 
    272         if (!success)
    273         {
    274             if (frame)
    275             {
    276                 VERBOSE(VB_IMPORTANT,
    277                         QString("GetNextFreeFrame() unable to lock frame %1. "
    278                                 "Dropping %2. w/lock(%3) unsafe(%4)")
    279                         .arg(DebugString(frame)).arg(GetStatus())
    280                         .arg(with_lock).arg(allow_unsafe));
    281                 DiscardFrame(frame);
    282             }
    283             ++tries;
    284             if (tries<TRY_LOCK_SPINS)
    285             {
    286                 if (tries && !(tries % TRY_LOCK_SPINS_BEFORE_WARNING))
    287                     VERBOSE(VB_PLAYBACK, "GetNextFreeFrame() TryLock has "
    288                             "spun "<<tries<<" times, this is a lot.");
    289                 usleep(TRY_LOCK_SPIN_WAIT);
    290             }
    291             else
    292             {
    293                 VERBOSE(VB_IMPORTANT,
    294                         QString("GetNextFreeFrame() unable to "
    295                         "lock frame %1 times. Discarding Frames.")
    296                         .arg(TRY_LOCK_SPINS));
    297                 DiscardFrames(true);
    298             }
    299         }
     297        usleep(TRY_LOCK_SPIN_WAIT);
    300298    }
    301299
    302     return frame;
     300    return NULL;
    303301}
    304302
    305303/**
     
    310308 */
    311309void VideoBuffers::ReleaseFrame(VideoFrame *frame)
    312310{
    313     global_lock.lock();
     311    QMutexLocker locker(&global_lock);
     312
    314313    vpos = vbufferMap[frame];
    315314    limbo.remove(frame);
    316315    decode.enqueue(frame);
    317316    used.enqueue(frame);
    318     global_lock.unlock();
    319317}
    320318
    321319/**
     
    325323 */
    326324void VideoBuffers::DeLimboFrame(VideoFrame *frame)
    327325{
    328     global_lock.lock();
     326    QMutexLocker locker(&global_lock);
    329327    if (limbo.contains(frame))
    330328    {
    331329        limbo.remove(frame);
    332330        available.enqueue(frame);
    333331    }
    334332    decode.remove(frame);
    335     global_lock.unlock();
    336333}
    337334
    338335/**
     
    341338 */
    342339void VideoBuffers::StartDisplayingFrame(void)
    343340{
    344     global_lock.lock();
     341    QMutexLocker locker(&global_lock);
    345342    rpos = vbufferMap[used.head()];
    346     global_lock.unlock();
    347343}
    348344
    349345/**
     
    352348 */
    353349void VideoBuffers::DoneDisplayingFrame(void)
    354350{
    355     global_lock.lock();
     351    QMutexLocker locker(&global_lock);
    356352
    357353    VideoFrame *buf = used.dequeue();
    358354    if (buf)
     
    361357        if (EnoughFreeFrames())
    362358            available_wait.wakeAll();
    363359    }
    364 
    365     global_lock.unlock();
    366360}
    367361
    368362/**
     
    372366 */
    373367void VideoBuffers::DiscardFrame(VideoFrame *frame)
    374368{
    375     global_lock.lock();
     369    QMutexLocker locker(&global_lock);
     370
    376371    bool ok = TryLockFrame(frame, "DiscardFrame A");
    377372    for (uint i=0; i<5 && !ok; i++)
    378373    {
     
    393388                                      "Unable to obtain lock on %1, %2")
    394389                .arg(DebugString(frame, true)).arg(GetStatus()));
    395390    }
    396     global_lock.unlock();
    397391}
    398392
    399393frame_queue_t *VideoBuffers::queue(BufferType type)
    400394{
     395    QMutexLocker locker(&global_lock);
     396
    401397    frame_queue_t *q = NULL;
    402398
    403     global_lock.lock();
    404399    if (type == kVideoBuffer_avail)
    405400        q = &available;
    406401    else if (type == kVideoBuffer_used)
     
    413408        q = &pause;
    414409    else if (type == kVideoBuffer_decode)
    415410        q = &decode;
    416     global_lock.unlock();
    417411
    418412    return q;
    419413}
    420414
    421415const frame_queue_t *VideoBuffers::queue(BufferType type) const
    422416{
     417    QMutexLocker locker(&global_lock);
     418
    423419    const frame_queue_t *q = NULL;
    424420
    425     global_lock.lock();
    426421    if (type == kVideoBuffer_avail)
    427422        q = &available;
    428423    else if (type == kVideoBuffer_used)
     
    435430        q = &pause;
    436431    else if (type == kVideoBuffer_decode)
    437432        q = &decode;
    438     global_lock.unlock();
    439433
    440434    return q;
    441435}
    442436
    443437VideoFrame *VideoBuffers::dequeue(BufferType type)
    444438{
     439    QMutexLocker locker(&global_lock);
     440
    445441    frame_queue_t *q = queue(type);
    446     if (q)
    447     {
    448         global_lock.lock();
    449         VideoFrame *frame = q->dequeue();
    450         global_lock.unlock();
    451         return frame;
    452     }
    453     return NULL;
     442
     443    if (!q)
     444        return NULL;
     445
     446    return q->dequeue();
    454447}
    455448
    456449VideoFrame *VideoBuffers::head(BufferType type)
    457450{
     451    QMutexLocker locker(&global_lock);
     452
    458453    frame_queue_t *q = queue(type);
    459     if (q)
    460     {
    461         QMutexLocker locker(&global_lock);
    462         if (q->size())
    463             return q->head();
    464     }
     454
     455    if (!q)
     456        return NULL;
     457
     458    if (q->size())
     459        return q->head();
     460
    465461    return NULL;
    466462}
    467463
    468464VideoFrame *VideoBuffers::tail(BufferType type)
    469465{
     466    QMutexLocker locker(&global_lock);
     467
    470468    frame_queue_t *q = queue(type);
    471     if (q)
    472     {
    473         QMutexLocker locker(&global_lock);
    474         if (q->size())
    475             return q->tail();
    476     }
     469
     470    if (!q)
     471        return NULL;
     472
     473    if (q->size())
     474        return q->tail();
     475
    477476    return NULL;
    478477}
    479478
    480479void VideoBuffers::enqueue(BufferType type, VideoFrame *frame)
    481480{
    482     if (frame)
    483     {
    484         frame_queue_t *q = queue(type);
    485         if (q)
    486         {
    487             global_lock.lock();
    488             q->remove(frame);
    489             q->enqueue(frame);
    490             global_lock.unlock();
    491             if (q == &available && EnoughFreeFrames())
    492                 available_wait.wakeAll();
    493         }
    494     }
     481    if (!frame)
     482        return;
     483
     484    frame_queue_t *q = queue(type);
     485    if (!q)
     486        return;
     487
     488    global_lock.lock();
     489    q->remove(frame);
     490    q->enqueue(frame);
     491    global_lock.unlock();
     492
     493    if (q == &available && EnoughFreeFrames())
     494        available_wait.wakeAll();
     495
     496    return;
    495497}
    496498
    497499void VideoBuffers::remove(BufferType type, VideoFrame *frame)
    498500{
    499     if (frame)
    500     {
    501         global_lock.lock();
    502         if ((type & kVideoBuffer_avail) == kVideoBuffer_avail)
    503             available.remove(frame);
    504         if ((type & kVideoBuffer_used) == kVideoBuffer_used)
    505             used.remove(frame);
    506         if ((type & kVideoBuffer_displayed) == kVideoBuffer_displayed)
    507             displayed.remove(frame);
    508         if ((type & kVideoBuffer_limbo) == kVideoBuffer_limbo)
    509             limbo.remove(frame);
    510         if ((type & kVideoBuffer_pause) == kVideoBuffer_pause)
    511             pause.remove(frame);
    512         if ((type & kVideoBuffer_decode) == kVideoBuffer_decode)
    513             decode.remove(frame);
    514         global_lock.unlock();
    515     }
     501    if (!frame)
     502        return;
     503
     504    QMutexLocker locker(&global_lock);
     505
     506    if ((type & kVideoBuffer_avail) == kVideoBuffer_avail)
     507        available.remove(frame);
     508    if ((type & kVideoBuffer_used) == kVideoBuffer_used)
     509        used.remove(frame);
     510    if ((type & kVideoBuffer_displayed) == kVideoBuffer_displayed)
     511        displayed.remove(frame);
     512    if ((type & kVideoBuffer_limbo) == kVideoBuffer_limbo)
     513        limbo.remove(frame);
     514    if ((type & kVideoBuffer_pause) == kVideoBuffer_pause)
     515        pause.remove(frame);
     516    if ((type & kVideoBuffer_decode) == kVideoBuffer_decode)
     517        decode.remove(frame);
    516518}
    517519
    518520void VideoBuffers::requeue(BufferType dst, BufferType src, int num)
    519521{
    520     global_lock.lock();
     522    QMutexLocker locker(&global_lock);
     523
    521524    num = (num <= 0) ? size(src) : num;
    522525    for (uint i=0; i<(uint)num; i++)
    523526    {
     
    525528        if (frame)
    526529            enqueue(dst, frame);
    527530    }
    528     global_lock.unlock();
    529531}
    530532
    531533void VideoBuffers::safeEnqueue(BufferType dst, VideoFrame* frame)
    532534{
    533     if (frame)
    534     {
    535         global_lock.lock();
    536         remove(kVideoBuffer_all, frame);
    537         enqueue(dst, frame);
    538         global_lock.unlock();
    539     }
     535    if (!frame)
     536        return;
     537
     538    QMutexLocker locker(&global_lock);
     539
     540    remove(kVideoBuffer_all, frame);
     541    enqueue(dst, frame);
    540542}
    541543
    542544frame_queue_t::iterator VideoBuffers::begin_lock(BufferType type)
     
    551553
    552554frame_queue_t::iterator VideoBuffers::end(BufferType type)
    553555{
    554     global_lock.lock();
     556    QMutexLocker locker(&global_lock);
     557
    555558    frame_queue_t::iterator it;
    556559    frame_queue_t *q = queue(type);
    557560    if (q)
    558561        it = q->end();
    559562    else
    560563        it = available.end();
    561     global_lock.unlock();
     564
    562565    return it;
    563566}
    564567
    565568uint VideoBuffers::size(BufferType type) const
    566569{
    567     uint s = 0;
     570    QMutexLocker locker(&global_lock);
     571
    568572    const frame_queue_t *q = queue(type);
    569573    if (q)
    570     {
    571         global_lock.lock();
    572         s = q->size();
    573         global_lock.unlock();
    574     }
    575     return s;
     574        return q->size();
     575
     576    return 0;
    576577}
    577578
    578579bool VideoBuffers::contains(BufferType type, VideoFrame *frame) const
    579580{
    580     bool c = false;
     581    QMutexLocker locker(&global_lock);
     582
    581583    const frame_queue_t *q = queue(type);
    582584    if (q)
    583     {
    584         global_lock.lock();
    585         c = q->contains(frame);
    586         global_lock.unlock();
    587     }
    588     return c;
     585        return q->contains(frame);
     586
     587    return false;
    589588}
    590589
    591590VideoFrame *VideoBuffers::GetScratchFrame(void)
     
    595594        VERBOSE(VB_IMPORTANT,
    596595                "GetScratchFrame() called, but not allocated");
    597596    }
     597
     598    QMutexLocker locker(&global_lock);
    598599    return at(allocSize()-1);
    599600}
    600601
     
    605606        VERBOSE(VB_IMPORTANT,
    606607                "GetScratchFrame() called, but not allocated");
    607608    }
     609
     610    QMutexLocker locker(&global_lock);
    608611    return at(allocSize()-1);
    609612}
    610613
     
    692695
    693696void VideoBuffers::ClearAfterSeek(void)
    694697{
    695     global_lock.lock();
     698    {
     699        QMutexLocker locker(&global_lock);
    696700
    697     for (uint i = 0; i < size(); i++)
    698         at(i)->timecode = 0;
     701        for (uint i = 0; i < size(); i++)
     702            at(i)->timecode = 0;
    699703
    700     while (used.count() > 1)
    701     {
    702         VideoFrame *buffer = used.dequeue();
    703         available.enqueue(buffer);
    704     }
     704        while (used.count() > 1)
     705        {
     706            VideoFrame *buffer = used.dequeue();
     707            available.enqueue(buffer);
     708        }
    705709
    706     if (used.count() > 0)
    707     {
    708         VideoFrame *buffer = used.dequeue();
    709         available.enqueue(buffer);
    710         vpos = vbufferMap[buffer];
    711         rpos = vpos;
     710        if (used.count() > 0)
     711        {
     712            VideoFrame *buffer = used.dequeue();
     713            available.enqueue(buffer);
     714            vpos = vbufferMap[buffer];
     715            rpos = vpos;
     716        }
     717        else
     718        {
     719            vpos = rpos = 0;
     720        }
    712721    }
    713     else
    714     {
    715         vpos = rpos = 0;
    716     }
    717722
    718723    if (EnoughFreeFrames())
    719724        available_wait.wakeAll();
    720725
    721     global_lock.unlock();
    722726}
    723727
    724728void VideoBuffers::LockFrame(const VideoFrame *frame, const char* owner)
     
    865869{
    866870    (void)frame;
    867871#ifdef USING_XVMC
    868     inheritence_lock.lock();
     872    QMutexLocker locker(&global_lock);
    869873   
    870874    frame_map_t::iterator it = parents.find(frame);
    871875    if (it == parents.end())
     
    909913        for (; it != new_parents.end(); ++it)
    910914            children[*it].push_back((VideoFrame*)frame);
    911915    }
    912 
    913     inheritence_lock.unlock();
    914916#endif // USING_XVMC
    915917}
    916918
    917919void VideoBuffers::RemoveInheritence(const VideoFrame *frame)
    918920{
    919     inheritence_lock.lock();
     921    QMutexLocker locker(&global_lock);
    920922
    921923    frame_map_t::iterator it = parents.find(frame);
    922924    if (it == parents.end())
    923     {
    924         inheritence_lock.unlock();
    925925        return;
    926     }
    927926
    928927    frame_queue_t new_parents;
    929928    frame_queue_t &p = it->second;
     
    952951            VERBOSE(VB_IMPORTANT, QString("Parent #%1: %2")
    953952                    .arg(i).arg(DebugString(*pit)));
    954953    }
    955 
    956     inheritence_lock.unlock();
    957954}
    958955
    959956frame_queue_t VideoBuffers::Children(const VideoFrame *frame)
    960957{
     958    QMutexLocker locker(&global_lock);
     959
    961960    frame_queue_t c;
    962961    frame_map_t::iterator it = children.find(frame);
    963962    if (it != children.end())
     
    967966
    968967bool VideoBuffers::HasChildren(const VideoFrame *frame)
    969968{
     969    QMutexLocker locker(&global_lock);
     970
    970971    frame_map_t::iterator it = children.find(frame);
    971972    if (it != children.end())
    972973        return !(it->second.empty());
     
    10331034
    10341035void VideoBuffers::SetOSDFrame(VideoFrame *frame, VideoFrame *osd)
    10351036{
    1036     if (frame==osd)
     1037    if (frame == osd)
    10371038    {
    10381039        VERBOSE(VB_IMPORTANT, QString("SetOSDFrame() -- frame==osd %1")
    10391040                .arg(GetStatus()));
     
    10441045    xvmc_render_state_t* r = GetRender(frame);
    10451046    if (r)
    10461047    {
    1047         global_lock.lock();
     1048        QMutexLocker locker(&global_lock);
    10481049
    10491050        VideoFrame* old_osd = (VideoFrame*) r->p_osd_target_surface_render;
    10501051        if (old_osd)
     
    10541055
    10551056        if (osd)
    10561057            xvmc_osd_parent[osd] = frame;
    1057 
    1058         global_lock.unlock();
    10591058    }
     1059
    10601060    UnlockFrame(frame, "SetOSDFrame");
    10611061}
    10621062
    10631063VideoFrame* VideoBuffers::GetOSDParent(const VideoFrame *osd)
    10641064{
    1065     global_lock.lock();
    1066     VideoFrame *parent = xvmc_osd_parent[osd];
    1067     global_lock.unlock();
    1068     return parent;
     1065    QMutexLocker locker(&global_lock);
     1066    return xvmc_osd_parent[osd];
    10691067}
    10701068
    10711069#endif