Hello If I want to attach a Player to a device (for play a VDR Recording) but I have some Thread problems. I have looked at cSVDRP::CmdPLAY. But If I copy the Code to my Plugin, sometimes I get a Memory access error. Maybe I need to lock the the device? The Problem is that the cControl::Attach(void) starts befor the cDevice::AttachPlayer(myPlayer) is done. But I don't know how to lock the device.
This is a fragment of the cSVDRP::CmdPLAY Code:
cRecording *recording = Recordings.Get(3); if (recording) { ....... cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); ....... cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); //if I place a output here it will be shown cControl::Attach(); //if I place a output here it will not be shown if it freezes ........ }
How to create a lock for this?
I have created some more output which can be shown here: http://nopaste.debianforum.de/1801
On stdout was shown: ..... SetPlayMode: 0 SetAudioChannelDevice: 0 SetPlayMode: 1 Speicherzugriffsfehler
I have tested lots of thinks but I didn't find a solution.
Maybe this is the reason why klaus didn't put the svdrp in an own thread?
I don't understand the way to lock a device!
Is there an way to resolve my problem? I don't want to call the svdrp "PLAY", thats an very long winded way.
Patrick
Patrick Fischer schrieb:
Hello If I want to attach a Player to a device (for play a VDR Recording) but I have some Thread problems. I have looked at cSVDRP::CmdPLAY. But If I copy the Code to my Plugin, sometimes I get a Memory access error. Maybe I need to lock the the device? The Problem is that the cControl::Attach(void) starts befor the cDevice::AttachPlayer(myPlayer) is done. But I don't know how to lock the device.
This is a fragment of the cSVDRP::CmdPLAY Code:
cRecording *recording = Recordings.Get(3); if (recording) { ....... cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); ....... cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); //if I place a output here it will be shown cControl::Attach(); //if I place a output here it will not be shown if it freezes ........ }
How to create a lock for this?
I have created some more output which can be shown here: http://nopaste.debianforum.de/1801
On stdout was shown: ..... SetPlayMode: 0 SetAudioChannelDevice: 0 SetPlayMode: 1 Speicherzugriffsfehler
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
Patrick Fischer wrote:
I have tested lots of thinks but I didn't find a solution.
Maybe this is the reason why klaus didn't put the svdrp in an own thread?
I don't understand the way to lock a device!
You don't "lock a device".
Starting a replay is supposed to take place from the foreground thread.
Klaus
Is there an way to resolve my problem? I don't want to call the svdrp "PLAY", thats an very long winded way.
Patrick
Patrick Fischer schrieb:
Hello If I want to attach a Player to a device (for play a VDR Recording) but I have some Thread problems. I have looked at cSVDRP::CmdPLAY. But If I copy the Code to my Plugin, sometimes I get a Memory access error. Maybe I need to lock the the device? The Problem is that the cControl::Attach(void) starts befor the cDevice::AttachPlayer(myPlayer) is done. But I don't know how to lock the device.
This is a fragment of the cSVDRP::CmdPLAY Code:
cRecording *recording = Recordings.Get(3); if (recording) { ....... cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); ....... cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); //if I place a output here it will be shown cControl::Attach(); //if I place a output here it will not be shown if it freezes ........ }
How to create a lock for this?
I have created some more output which can be shown here: http://nopaste.debianforum.de/1801
On stdout was shown: ..... SetPlayMode: 0 SetAudioChannelDevice: 0 SetPlayMode: 1 Speicherzugriffsfehler
so I need to place the call at MainMenuAction or something similar? Thats not what I want. I start a Thread in Start() which is listen to a xmlrpc connection. If i get an "start Replay X" event from a xmlrpc Server, then I want to start a replay. In this case I have to put my sockets to a thread but from a thread I can't start a replay :-( Is the only way to use the svdrp? I can implement an own command which take my params, but this is a winded way, isn't it?
Patrick
Klaus Schmidinger wrote:
Patrick Fischer wrote:
I have tested lots of thinks but I didn't find a solution.
Maybe this is the reason why klaus didn't put the svdrp in an own thread?
I don't understand the way to lock a device!
You don't "lock a device".
Starting a replay is supposed to take place from the foreground thread.
Klaus
Is there an way to resolve my problem? I don't want to call the svdrp "PLAY", thats an very long winded way.
Patrick
Patrick Fischer schrieb:
Hello If I want to attach a Player to a device (for play a VDR Recording) but I have some Thread problems. I have looked at cSVDRP::CmdPLAY. But If I copy the Code to my Plugin, sometimes I get a Memory access error. Maybe I need to lock the the device? The Problem is that the cControl::Attach(void) starts befor the cDevice::AttachPlayer(myPlayer) is done. But I don't know how to lock the device.
This is a fragment of the cSVDRP::CmdPLAY Code:
cRecording *recording = Recordings.Get(3); if (recording) { ....... cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); ....... cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); //if I place a output here it will be shown cControl::Attach(); //if I place a output here it will not be shown if it freezes ........ }
How to create a lock for this?
I have created some more output which can be shown here: http://nopaste.debianforum.de/1801
On stdout was shown: ..... SetPlayMode: 0 SetAudioChannelDevice: 0 SetPlayMode: 1 Speicherzugriffsfehler
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
Patrick Fischer wrote:
so I need to place the call at MainMenuAction or something similar? Thats not what I want. I start a Thread in Start() which is listen to a xmlrpc connection. If i get an "start Replay X" event from a xmlrpc Server, then I want to start a replay. In this case I have to put my sockets to a thread but from a thread I can't start a replay :-( Is the only way to use the svdrp? I can implement an own command which take my params, but this is a winded way, isn't it?
Patrick
You could remove the
cControl::Attach();
call from your code (this is done in VDR's main loop in the foreground thread) and add a mutex to cControl that guards all calls to its member functions.
Klaus
You could remove the
cControl::Attach();
call from your code (this is done in VDR's main loop in the foreground thread) and add a mutex to cControl that guards all calls to its member functions.
Klaus
What did you mean by "add"? I can't find a mutex in cControl.
Did you mean this?: (myMutex is a private cMutex from cMyPlayer)
bool cMyPlayer::start(const char *path) { cMutexLock MutexLock(&myMutex); cRecording *recording = Recordings.GetByName(path); if (recording) { cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); cResumeFile resume(recording->FileName()); resume.Delete(); cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); // cControl::Attach(); //will done in the foreground thread return true; }else return false; }
In this case I only protect my own function. This will protect that my thread can't recall start until it is done. Thats OK. Or did you mean that I need to patch the cControl by adding a Mutex and protect all memberfunctions? If I do so, will you add this patch to upcoming vdr versions? I don't want to patch all upcoming versions.
Patrick
Patrick Fischer wrote:
You could remove the
cControl::Attach();
call from your code (this is done in VDR's main loop in the foreground thread) and add a mutex to cControl that guards all calls to its member functions.
Klaus
What did you mean by "add"? I can't find a mutex in cControl.
That's why I wrote "add" ;-)
Did you mean this?: (myMutex is a private cMutex from cMyPlayer)
bool cMyPlayer::start(const char *path) { cMutexLock MutexLock(&myMutex); cRecording *recording = Recordings.GetByName(path); if (recording) { cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); cResumeFile resume(recording->FileName()); resume.Delete(); cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); // cControl::Attach(); //will done in the foreground thread return true; }else return false; }
In this case I only protect my own function. This will protect that my thread can't recall start until it is done. Thats OK. Or did you mean that I need to patch the cControl by adding a Mutex and protect all memberfunctions?
Yes.
If I do so, will you add this patch to upcoming vdr versions? I don't want to patch all upcoming versions.
If it works, yes.
Klaus
I have implemanded a mutex but the problem might be the same.
Now I know the real problem.
If I make a cControl::Launch(new cReplayControl); from a thread, you told me that the main loop will Attach it. The Attach call is at the beginning of the main loop. But if my Thread will call the Launch(..) only a short time after the main loop has called the Attach(..), then the line 814 will call ProcessKey from my cReplayControl. But if this cReplayControl is not activ it will return osEnd and the main loop will call cControl::Shutdown() my ReplayControl.
Its an vicious circle :-( I can defuse it by calling cControl::Attach(); directly after cControl::Launch(new cReplayControl); but this will not fix the problem.
Tomorrow I will test if it works better if I inherit from cReplayControl and don't return osEnd from calling ProcessKey().
Cu Patrick
Klaus Schmidinger schrieb:
Patrick Fischer wrote:
You could remove the
cControl::Attach();
call from your code (this is done in VDR's main loop in the foreground thread) and add a mutex to cControl that guards all calls to its member functions.
Klaus
What did you mean by "add"? I can't find a mutex in cControl.
That's why I wrote "add" ;-)
Did you mean this?: (myMutex is a private cMutex from cMyPlayer)
bool cMyPlayer::start(const char *path) { cMutexLock MutexLock(&myMutex); cRecording *recording = Recordings.GetByName(path); if (recording) { cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); cResumeFile resume(recording->FileName()); resume.Delete(); cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); // cControl::Attach(); //will done in the foreground thread return true; }else return false; }
In this case I only protect my own function. This will protect that my thread can't recall start until it is done. Thats OK. Or did you mean that I need to patch the cControl by adding a Mutex and protect all memberfunctions?
Yes.
If I do so, will you add this patch to upcoming vdr versions? I don't want to patch all upcoming versions.
If it works, yes.
Klaus
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
now I have written a workaround and it works.
I have written cMyReplayControl inherit from cReplayControl.
//---------------cIvvonReplayControl.h------------------- class cIvvonReplayControl: public cReplayControl{ public: cIvvonReplayControl(); virtual ~cIvvonReplayControl(); eOSState ProcessKey(eKeys Key); }; //---------------cIvvonReplayControl.c------------------- cMyReplayControl::cMyReplayControl():cReplayControl(){}
cMyReplayControl::~cMyReplayControl(){}
eOSState cMyReplayControl::ProcessKey(eKeys Key){ if(!cReplayControl::Active()){ dsyslog("ReplayControl is not Active. Use workaround1"); cControl::Attach(); } eOSState tmp = cReplayControl::ProcessKey(Key); if(tmp==osEnd){ dsyslog("ReplayControl is not Active. Use workaround2"); cControl::Attach(); tmp = cReplayControl::ProcessKey(Key); } if(tmp==osEnd){ //only for debug dsyslog("cMyPlayerControl is still not attached and Active!!!!!"); exit(0); } return tmp; }
I think it would be nice if we have a function(e.g. main) in each Plugin, that will be called from the mail loop each time. In my case I could do this: -set an bool from the thread that signal that the thread want to attach a player -on the next call of the Plugin main function, my Plugin can check this bool and attach the player
I know that this will have side effects if the work in the plugins main function takes to long time. But this would be a nice way to sync threads with the main thread.
Patrick
Patrick Fischer schrieb:
I have implemanded a mutex but the problem might be the same.
Now I know the real problem.
If I make a cControl::Launch(new cReplayControl); from a thread, you told me that the main loop will Attach it. The Attach call is at the beginning of the main loop. But if my Thread will call the Launch(..) only a short time after the main loop has called the Attach(..), then the line 814 will call ProcessKey from my cReplayControl. But if this cReplayControl is not activ it will return osEnd and the main loop will call cControl::Shutdown() my ReplayControl.
Its an vicious circle :-( I can defuse it by calling cControl::Attach(); directly after cControl::Launch(new cReplayControl); but this will not fix the problem.
Tomorrow I will test if it works better if I inherit from cReplayControl and don't return osEnd from calling ProcessKey().
Cu Patrick
Klaus Schmidinger schrieb:
Patrick Fischer wrote:
You could remove the
cControl::Attach();
call from your code (this is done in VDR's main loop in the foreground thread) and add a mutex to cControl that guards all calls to its member functions.
Klaus
What did you mean by "add"? I can't find a mutex in cControl.
That's why I wrote "add" ;-)
Did you mean this?: (myMutex is a private cMutex from cMyPlayer)
bool cMyPlayer::start(const char *path) { cMutexLock MutexLock(&myMutex); cRecording *recording = Recordings.GetByName(path); if (recording) { cReplayControl::SetRecording(NULL, NULL); cControl::Shutdown(); cResumeFile resume(recording->FileName()); resume.Delete(); cReplayControl::SetRecording(recording->FileName(), recording->Title()); cControl::Launch(new cReplayControl); // cControl::Attach(); //will done in the foreground thread return true; }else return false; }
In this case I only protect my own function. This will protect that my thread can't recall start until it is done. Thats OK. Or did you mean that I need to patch the cControl by adding a Mutex and protect all memberfunctions?
Yes.
If I do so, will you add this patch to upcoming vdr versions? I don't want to patch all upcoming versions.
If it works, yes.
Klaus
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
vdr mailing list vdr@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr
After hours of tests I found a solution for my thread problems.
I use the workaround specified below and I need to patch the player.c and player.h to make it thread save. The patch is attached.
There were two problems: -if the mainloop will work with my ReplayControl before it is attached it will crash(fixed by workaround) -cControl were not thread safe (fixed by patch)
I hope it will help somebody and maybe Klaus will include my cControlThreadSavePatch.
Greeting Patrick
now I have written a workaround and it works.
I have written cMyReplayControl inherit from cReplayControl.
//---------------cIvvonReplayControl.h------------------- class cIvvonReplayControl: public cReplayControl{ public: cIvvonReplayControl(); virtual ~cIvvonReplayControl(); eOSState ProcessKey(eKeys Key); }; //---------------cIvvonReplayControl.c------------------- cMyReplayControl::cMyReplayControl():cReplayControl(){}
cMyReplayControl::~cMyReplayControl(){}
eOSState cMyReplayControl::ProcessKey(eKeys Key){ if(!cReplayControl::Active()){ dsyslog("ReplayControl is not Active. Use workaround1"); cControl::Attach(); } eOSState tmp = cReplayControl::ProcessKey(Key); if(tmp==osEnd){ dsyslog("ReplayControl is not Active. Use workaround2"); cControl::Attach(); tmp = cReplayControl::ProcessKey(Key); } if(tmp==osEnd){ //only for debug dsyslog("cMyPlayerControl is still not attached and Active!!!!!"); exit(0); } return tmp; }
--- ./vdr-1.3.35/player.c 2005-11-02 08:40:23.000000000 +0100 +++ ./vdr-1.3.37/player.c 2005-12-19 10:41:38.000000000 +0100 @@ -40,6 +40,7 @@ // --- cControl --------------------------------------------------------------
cControl *cControl::control = NULL; +cMutex cControl::mutex;
cControl::cControl(cPlayer *Player, bool Hidden) { @@ -61,12 +62,14 @@
void cControl::Launch(cControl *Control) { + cMutexLock MutexLock(&mutex); delete control; control = Control; }
void cControl::Attach(void) { + cMutexLock MutexLock(&mutex); if (control && !control->attached && control->player && !control->player->IsAttached()) { if (cDevice::PrimaryDevice()->AttachPlayer(control->player)) control->attached = true; @@ -79,6 +82,7 @@
void cControl::Shutdown(void) { + cMutexLock MutexLock(&mutex); cControl *c = control; // avoids recursions control = NULL; delete c;
--- ./vdr-1.3.35/player.h 2005-11-02 08:40:23.000000000 +0100 +++ ./vdr-1.3.37/player.h 2005-12-19 10:41:58.000000000 +0100 @@ -62,6 +62,7 @@ class cControl : public cOsdObject { private: static cControl *control; + static cMutex mutex; bool attached; bool hidden; protected: