I wanted to test this "eggtimer-0.9.1" plugin with vdr-1.3.44 and it seems to work pretty well. But, when I have the eggtimer switch to a specific channel on a timer, I get the following error message when I try to change channels manually after the eggtimer switched the channel.
vdr: [13902] ERROR: Eggtimer thread 13902 won't end (waited 30 seconds) - canceling it...
Has anyone seen this error?
Best Regards,
C.Y.M wrote:
I wanted to test this "eggtimer-0.9.1" plugin with vdr-1.3.44 and it seems to work pretty well. But, when I have the eggtimer switch to a specific channel on a timer, I get the following error message when I try to change channels manually after the eggtimer switched the channel.
vdr: [13902] ERROR: Eggtimer thread 13902 won't end (waited 30 seconds) - canceling it...
Has anyone seen this error?
Best Regards,
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
I tried to reproduce the problem but things worked well on my 2-card-system. Eggtimer switched channel, I was able to zap to another transponder, start a recording there and then zapped to channel that was provided by a third transponder - worked so far.
I then started VDR with only one device and got the same error as mentioned by C.Y.M.
Do I have to lock/unlock the cDevice when switching to a channel?
I think the error must be within that code:
void cEggtimerThread::Stop(void) { #ifdef DEBUG printf("cEggtimerThread::Stop\n" ); #endif running = false; Cancel(30); }
void cEggtimerThread::Action(void) { #ifdef DEBUG printf("cEggtimerThread::Action\n" ); #endif
while ( running ) { // time is over ? if (eggtimer->TimeReached()) { switch (eggtimer->action) { case EGGTIMER_ACTION_SWITCH: { // switch to channel cChannel *chan = Channels.GetByNumber( eggtimer->channel ); cDevice *device = cDevice::ActualDevice();
if ( chan == NULL || device == NULL || !device->SwitchChannel(chan , true) ) { #if VDRVERSNUM < 10314 Interface->Error( tr("Eggtimer: could not switch channel") ); #else Skins.Message( mtError, tr("Eggtimer: could not switch channel") ); #endif }
Stop(); // Stop eggtimer thread } break;
case EGGTIMER_ACTION_MSG: { // OSD message time_t now = time(NULL); // for repeating messages we need // current time
// If 2.5 * MessageTime (VDR Setup) has expired => display again if (now - lastInfo >= (int) (2.5 * Setup.OSDMessageTime) ) { // Display a status msg for OSDMessageTime seconds #if VDRVERSNUM < 10307 Interface->Status( eggtimer->msg ); usleep( Setup.OSDMessageTime * 1000); Interface->Status( NULL ); #else Skins.Message( mtStatus, eggtimer->msg ); cCondWait::SleepMs( Setup.OSDMessageTime * 1000); Skins.Message( mtStatus, NULL ); #endif // remember time when message was displayed lastInfo = now; } } break; case EGGTIMER_ACTION_COMMAND: { // Execute command cCommand *command = Commands.Get( eggtimer->command );
if (command != NULL) { command->Execute(); } else #if VDRVERSNUM < 10314 Interface->Error( tr("Eggtimer: command not found") ); #else Skins.Message( mtError, tr("Eggtimer: command not found") ); #endif Stop(); } break; } }
// Sleep 0.5 seconds #if VDRVERSNUM < 10314 usleep(500000); #else cCondWait::SleepMs(500); #endif }
if (eggtimer != NULL) delete eggtimer; }
Thanks for any hints
On 24 Mar 2006 Peter Juszack vdr@unterbrecher.de wrote:
Do I have to lock/unlock the cDevice when switching to a channel?
I don't know this specific plugin, but looking at the code sniplet:
void cEggtimerThread::Stop(void) { #ifdef DEBUG printf("cEggtimerThread::Stop\n" ); #endif running = false; Cancel(30); }
void cEggtimerThread::Action(void) {
[...]
Stop(); // Stop eggtimer thread
I don't think that one should Cancel() (in this case via Stop()) a thread from inside the Action() function. This must lead to the observed dead-lock.
I guess you should set running=false and let the loop terminate itself (if needed you can break; out from the loop too). On exit from Action() the child thread is terminated.
Regards.
Stefan Huelswitt wrote:
On 24 Mar 2006 Peter Juszack vdr@unterbrecher.de wrote:
Do I have to lock/unlock the cDevice when switching to a channel?
I don't know this specific plugin, but looking at the code sniplet:
void cEggtimerThread::Stop(void) { #ifdef DEBUG printf("cEggtimerThread::Stop\n" ); #endif running = false; Cancel(30); }
void cEggtimerThread::Action(void) {
[...]
Stop(); // Stop eggtimer thread
I don't think that one should Cancel() (in this case via Stop()) a thread from inside the Action() function. This must lead to the observed dead-lock.
I guess you should set running=false and let the loop terminate itself (if needed you can break; out from the loop too). On exit from Action() the child thread is terminated.
Regards.
Thats the point. I already fixed it. I also removed the running variable because cThread already has a private member named running. I decided not to declare any running/active variables at all in my derived class but to use the Running() mehtod of cThread. To leave the action loop from within I just defined a variable leaveLoop locally in the Action method.
bool leaveLoop = false;
while (Running() && !leaveLoop) { ... do it
if ( threadShouldEnd ) leaveLoop = true; }
I know that it would be possible to leave the Action mehtod via return. But I want to implement some clean up at after the action loop so the method must finish in al cases.
I don't understand why it is not possible to set the cThread::running member to false from within the action loop or use any other cThread implemented mechnism to leave the action loop. Leaving this to the plugin developer is not the best idea beacause of duplicate running variables.
Regards Peter
On 24 Mar 2006 Peter Juszack vdr@unterbrecher.de wrote:
I know that it would be possible to leave the Action mehtod via return. But I want to implement some clean up at after the action loop so the method must finish in al cases.
In that case you could leave the action loop with break. No need for another flag normaly.
I don't understand why it is not possible to set the cThread::running member to false from within the action loop or use any other cThread implemented mechnism to leave the action loop. Leaving this to the plugin developer is not the best idea beacause of duplicate running variables.
Well, I don't see the problem.
If you want to stop a thread from outside i.e. from another thread you use Cancel(), as this envolves signaling the running thread that it should shut down.
If you're on the thread i.e. inside Action() there is no need for any kind of signaling, you must only drop out of the Action() function to shut down the thread.
Regards.
----- Original Message ----- From: "Stefan Huelswitt" s.huelswitt@gmx.de Newsgroups: local.linux.vdr To: vdr@linuxtv.org Sent: Friday, March 24, 2006 2:28 PM Subject: Re: [vdr] Eggtimer-0.9.1 thread won't end
On 24 Mar 2006 Peter Juszack vdr@unterbrecher.de wrote:
I know that it would be possible to leave the Action mehtod via return. But I want to implement some clean up at after the action loop so the method must finish in al cases.
In that case you could leave the action loop with break. No need for another flag normaly.
That's right, of course - but I have to leave the while from within a switch case block so I have to define an own loop variable.
I don't understand why it is not possible to set the cThread::running member to false from within the action loop or use any other cThread implemented mechnism to leave the action loop. Leaving this to the plugin developer is not the best idea beacause of duplicate running variables.
Well, I don't see the problem.
It's not a real problem. But I remember that I copied parts of my code from other plugins which have own class-wide running variables. I believe that starting and stopping the thread should be implemented in the base class cThread in a way that a plugin developer uses a scheme without own status vars.
If you want to stop a thread from outside i.e. from another thread you use Cancel(), as this envolves signaling the running thread that it should shut down.
I am not connected to my VDR now, but as far as I remember Cancel(int seconds) is a protected method and has to be wrapped for public access. Maybe there is a Cancel(void) method which I have not deiscovered yet. That's what I mean - I saw different ways of implementing thread handling in almost every plugin allthough developers derived from cThread.
If you're on the thread i.e. inside Action() there is no need for any kind of signaling, you must only drop out of the Action() function to shut down the thread.
Should I place cleanup stuff in a destructor?
Regards.
-- Stefan Huelswitt s.huelswitt@gmx.de | http://www.muempf.de/
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr