Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] Re: vdr-1.3.17: thread issues with vdr-xine and vdr-osdteletext



Reinhard Nissl wrote:
Klaus Schmidinger wrote:

Reinhard Nissl wrote:

Hi,

Reinhard Nissl wrote:

after applying all osdteletext patches and poisening VDR there still seems to remain a race condtion when havily zapping between channels.

From /var/log/messages:



...

At this point VDR crashed. Strange is that there are two receivers (1417 , 1419) and two TS buffers (1420, 1421) but only a single transfer thread (1416).



My guess would be that the osdteletext uses the other receiver.



Would you expect that there are two receivers at that time?



Damn words! The Thread description you choose was leading me into the wrong direction. Actually it's a "cDevice" that is started twice!

From device.c: --------------------------------------------

cDevice::cDevice(void)
{
cardIndex = nextCardIndex++;

SetDescription("receiver on device %d", CardIndex() + 1);

-----------------------------------------------------------

I don't think that two receivers are necessary as I've added debug output to osdteletext's Receive() function and it gets also called when there is only one receiver that typically feeds the transfer thread.



You'll definitely need to cReceiver instances: one for transfer thread and one for teletext.

BTW: I've meanwhile realized that each time VDR crashes there were two receivers created.



The race condition is in cDevice::AttachReceiver() and or cThread::Start():

bool cDevice::AttachReceiver(cReceiver *Receiver)
{
if (!Receiver)
return false;
if (Receiver->device == this)
return true;
if (!HasLock(TUNER_LOCK_TIMEOUT)) {
esyslog("ERROR: device %d has no lock, can't attach receiver!", CardIndex() + 1);
return false;
}
for (int i = 0; i < MAXRECEIVERS; i++) {
if (!receiver[i]) {
for (int n = 0; n < MAXRECEIVEPIDS; n++) {
if (!AddPid(Receiver->pids[n])) {
for ( ; n-- > 0; )
DelPid(Receiver->pids[n]);
return false;
}
}
Receiver->Activate(true);
Lock();
Receiver->device = this;
receiver[i] = Receiver;
Unlock();
Start(); // <================
return true;
}
}
esyslog("ERROR: no free receiver slot!");
return false;
}

The above marked Start() is called for adding each receiver. It now depends on the time between two of these calls, whether one or two threads are created. From thread.c:

bool cThread::Start(void)
{
if (!childTid) { // <================// <================
parentTid = pthread_self();
pthread_t Tid;
pthread_create(&Tid, NULL, (void *(*) (void *))&StartThread, (void *)this);
pthread_detach(Tid); // auto-reap
pthread_setschedparam(Tid, SCHED_RR, 0);
}
return true; //XXX return value of pthread_create()???
}

If the time is too short then childTid will be 0 for both calls resulting in two threads where one is expected.

Well, looks like I should never have changed anything in thread.c (1.3.16),
because back then everything actually did work... :-(

Attached you'll find a suggested fix. It works for me here.

Bye.

It works for me too! Thank you so much. I have applied this patch to the latest thread.[ch] and streamdev works like a charm again. :)

Excellent work.




Home | Main Index | Thread Index