Hallo Profis,
beim Plugin-schreiben komme ich an folgender Hürde nicht vorbei
habe mal den vermutlich relevanten Teil des Codes incl. Enigma2-log angehängt und hoffe, mir kann da jemand genaueres erklären
Hallo Profis,
beim Plugin-schreiben komme ich an folgender Hürde nicht vorbei
habe mal den vermutlich relevanten Teil des Codes incl. Enigma2-log angehängt und hoffe, mir kann da jemand genaueres erklären
ob das jetzt alles vom relevanten Code ist, sei mal dahin gestellt.
Ich nehme mal an, du benutzt wirklich keine eTimer im Thread (.start o.ä.) . Ich habe allerdings auch die Erfahrung machen müssen, das solche FATAL!: addTimer Meldungen kommen, obwohl ich ganz sicher selber keinerlei Timer im Thread nutze. Auch nutze ich keine e2-Funktionen und genau das solltest du z.B. auch unterlassen. Es dürfen KEINE e2-Funktionen innerhalb eines Threads benutzt werden. Alles was mit from e..... import .... zu tun hat ist im Thread Tabu.
Ghost hat diese Meldung extra eingebaut, damit darauf hingewiesen wird. Die Wahrscheinlichkeit das irgendwo ein Crash entsteht (bei dieser Meldung) ist relativ hoch. Leider hilft die Meldung nicht wirklich die eigentliche Ursache zu zeigen, nur das sein eigenes Plugin irgendwie damit zusammenhängt. Leider bin ich nicht sehr hilfreich, ich weis ....
Zitatob das jetzt alles vom relevanten Code ist, sei mal dahin gestellt.
"im Thread eingebaut" betrifft nur den Thread oder auch das ausgelöste Handler? oder das was dann danach kommt?
alles was den Thread beschreibt habe ich gepostet, da habe ich nix weggelassen - doch, in autostart schreibe ich noch log mit open und write
im Thread selbst ist ja nichts derartiges (und nein, eTimer habe ich auch keine eigenen drin)
ZitatLeider bin ich nicht sehr hilfreich, ich weis
na du versuchst schon mal mir weiterzuhelfen, das ist doch was - evtl bringen ja meine Antworten auf deine Nachfragen jemand anderen dazu, mir den "du musst doch nur..." - Hinweis zu geben
ich könnte auch den ganze code geben falls es möglicherweise hilft, aber ich kann und darf ihn derzeit nicht veröffentlichen
da der ganze "Server" im Thread läuft, werden auch die Ereignisse/handle dort abgearbeitet (denke ich). Vielleicht solltest du die e2-Dinge aus dem Thread entfernen und irgendwie (Message-Queue oder was weis ich) an den E2-Main zurückgeben und dann dort ausführen.
ups, nu guck ich wie Schwein ins Uhrwerk
habe mal nach ePythonMessagePump gesucht aber die paar dinge haben mich nicht erleuchtet
im Handler wird ja eine Screen-Klasse aufgerufen, die funktioniert allein für sich problemlos - hat jedoch natürlich viele e2-Dinge drin
wenn das zum Thread gehört dann geht ja gar nichts mehr?
oder geht es nur um den Handler und danch "ist wieder alles gut" ?
also eine zusätzliche Klasse schaffen, welche der Handler aufruft und von dort alles ausführen?
und was/wie/wo mach ich mit ePythonMessagePump?
schau mal hier auf Schwerkraft. Schaut übersichtlich aus, ist auch ein Thread mit einem .send() und deren Abarbeitung. Aber Ahnung habe ich davon auch nicht, ist aber kurz und wenn man sich die "pump" Dinge anschaut, kann man das sogar verstehen
https://schwerkraft.elitedvb.n…totimer/src/AutoPoller.py
PS: das Beispiel ist aber für OE2.2 wegen der .connect-Syntax. Das ist im <oe2.2 anders..... aber so 100% verstehe ich den Code doch nicht
OE<2.2 Entsprechung : https://schwerkraft.elitedvb.n…ef970a1;hb=refs/heads/4.0
Edit: "er" benutzt eine Queue für die Übergabe von Werten, wie ich sehe.
Die Grundidee ist simpel: der Thread schreibt in eine Queue und über ePythonMessagePump() methoden wird die Queue in e2 wieder ausgelesen. So ist innerhalb deiner Thread Klasse als einzige e2 Klasse nur ePythonMessagePump() vorhanden.
ich steige nichtmal annähernd dahinter was ich tun muss
es ist ja kein gewöhnliches Thread-Prozedere, sondern z.B. SocketServer.ThreadingTCPServer
zudem benötige ich (besser weiß ichs nicht) ja statt der dort zu sehenden 2 Blöcke bei meiner Geschichte 4:
autostart
serverstart
MyThreadingServer
HLHandler
habe echt keinen Plan, wie ich da wo eingreifen soll
muss dazuschreiben, das Threading selbst habe ich wohl eh noch nicht kapiert, aber bisher mit Try and Error immer zum Ziel gefunden
mangels 7020/7080 kann ich jedoch nicht "rumprobieren"
edit.
ich nehm jetzt mal aus Handler alles raus was irgend möglich ist, session.open dürfte ja kein problem machen was dann in der Klasse kommt
ich würde erst einmal die pump definieren
self.__pump = ePythonMessagePump()
self.__pump.recv_msg.get().append(self.gotThreadMsg)
und in gotThreadMsg mal ein print "toll es geht" definieren.
und aus dem Thread ein
pump = self.__pump
pump.send(0)
das self.__pump muss irgendetwas sein, was in der gotThreadMsg und im Thread verfügbar ist. Im Beispiel wird ja der Thread innerhalb der Klasse gestartet und somit ist self "bekannt". Später noch die Queue für Werteübergabe ist dann nicht das Problem. Die "__" würde ich nicht nutzen, weil ich das nie nutze *renn* bedeutet ja, das man diese __ nur innerhalb der Klasse "rufen" kann
/me sich das so denkt.....
Hallo Shadowrider,
willst Du einen TCP Server aufsetzen? Was soll er machen?
MfG.
joergm6
ich probier da mal, das dumme ist auf den Boxen die ich habe läuft es ja bisher ohne Probleme, nur auf den genannten eben nicht - also sehe ich leider nicht ob/wie es sich auswirkt
Bobo71
wie ich oben schon schrieb kann/darf ich derzeit dazu nichts veröffentlichen
es ist ein tcp-server welcher auf dem Port lauscht und dann das eigentliche komplexe Plugin startet
Hallo Shadowrider,
unter Twisted kannst du ziemlich unkompliziert einen TCP Server aufsetzen. Und er ist asynchron. Kannst es dir ja mal anschauen.
Hier
Deinen Fehler mit Fatal... Hatte ich Anfang des Jahres auch. Der Bug sollte im OE 2.2 gefixt sein. Ist das Enigma2 deiner Testbox aktuell?
Vom Handy...
mein Server läuft absolut zuverlässig so wie gewünscht - leider offenbar nicht auf den OE 2.2 Boxen
(schau mir das andere aber gern auch an)
ich selbst habe leider keine entsprechende Box zum Testen, ich sende das Programm einem Laien, welcher dann bemüht ist mir hilfreiche Rückmeldungen zu geben
dort ist zwar gestern das Image vom 04.12.2014 geflasht worden und die Aktualisierungen durchgeführt, jedoch gibt es nun (ohne jegliche sonstige sytemveränderung) massive weitere Probleme mit irgendwelchen fehlenden png's lt. e2-Log
(sag ja, solange ich die Box vor Ort habe und flashen, einstellen und auch testen kann konnte ich Probleme bisher immer lösen, so ist das extrem kompliziert bis unmöglich)
edit: fängt schon damit an, dass das per telnet installierte Plugin zwar in den Erweiterungen erscheint und läuft, lt. Tester aber nicht deinstallierbar ist per menü
habe auch noch nicht herausgefunden, wie ein externes Plugin auf dem Original-Image ohne telnet installierbar wäre (webadmin beim Tester wohl installiert aber nicht im Browser abrufbar)
Wie rufst du das
auf, und wie closest du es?
Siehe http://<<Hier>></a> als evt. Lösungsansatz... Da hatte ich die selben Fehler.
Gruß.
P.S. Ich würde es auch testen wenn du es magst... Ich habe eine 7080.
Also... Ich bin Grad nicht zu Hause werde aber spätestens Morgen noch mehr dazu schreiben. Das Problem ist, dass es auf egal welchem Stand von enigma2 schon Immer tödlich war core Funktionen einfach aus einem anderen Thread zu rufen. Der Core ist nicht Thread safe. Und da so etwas i.d.R für absolut unerklärliche abstürze sorgt, haben wir dann irgendwann diesen relativ harten Check eingebaut. Das Image deines Testers ist übrigens hoffnungslos veraltet, er sollte unbedingt mal ein Update machen.
Ich werde dir Morgen ein paar Beispiele Posten wie man Dinge korrekt in einem Thread abarbeiten kann.
Danke
alsi eigentlich ist nichts mehr in den threads was stören könnte
auch das dialog-schließen ist raus und selbstverständich lösche ich den mit session.deleteDialog(melde_screen)
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
class HLHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024)#.strip()
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write(time.strftime("%d.%m.%Y %H:%M:%S :"))
f.write("magic-data empfangen\n")
f.write("komplett: "+str(self.data)+"\n")
f.write("client_address: "+str(self.client_address[0])+"\n")
f.close()
try:
req = urllib2.Request("http://"+str(self.client_address[0])+":80/v_info.txt" )
response = urllib2.urlopen(req)
global v
v_info = response.readlines()
except Exception, e:
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write("error v-info einlesen:\n : "+str(e)+"\n")
f.close()
video_info=()
global webserver
webserver = str(self.client_address[0])
if "test-provider" in str(self.data):
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write(">> 'test-provider' in magic-data gefunden\n")
f.close()
if not hl_screen:
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write(">> plugin wird gestartet\n")
f.close()
global hl_screen
hl_screen = session.open(test_Provider_P)
hl_screen.start_play()
class MyThreadingServer( SocketServer.ThreadingTCPServer ):
allow_reuse_address = 1
def server_bind(self):
SocketServer.ThreadingTCPServer.server_bind(self)
host, port = self.socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
def serverstart(hl_PORT):
if not HLserver:
global HLserver
ThreadingTCPServer.allow_reuse_address = True
HLserver = MyThreadingServer(("",hl_PORT), HLHandler)
HLserver.serve_forever()
def autostart(reason, **kwargs):
global session
if "session" in kwargs:
session = kwargs["session"]
print "HL server start"
th1=Thread(target=serverstart, args=[hl_PORT])
th1.setDaemon(True)
th1.start()
if debug_on:
f=open("/tmp/test_Provider_debug","w")
f.write("test_Provider_Player Vers. "+my_version+"\n")
f.write("debug-log\n(log schreiben an/aus in den Einstellungen)\n")
f.write(time.strftime("%d.%m.%Y %H:%M:%S :"))
f.write("server gestartet\n")
f.close()
def main(session, **kwargs):
if not hl_screen and not melde_screen:
if not webserver:
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write(time.strftime("%d.%m.%Y %H:%M:%S :"))
f.write("not provider, zeige meldung\n")
f.close()
global melde_screen
melde_screen = session.instantiateDialog(No_Provider)
melde_screen.show()
if not hl_player_screen:
if debug_on:
f=open("/tmp/test_Provider_debug","a")
f.write(time.strftime("%d.%m.%Y %H:%M:%S :"))
f.write("plugin off -> starten\n")
f.close()
global hl_screen
hl_screen = session.open(test_Provider_P)
Alles anzeigen
so, image beim Tester aktualisiert per Webinterface
aus meinen Threads eigentlich alles ausgelagert, gleiches problem
Reichi: bin wohl aufgeschmissen wenn du mir nicht das Brett vom Kopf tust
(kann dir auch gerne das Plugin per PN senden wenn es hilft)
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
class HLHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)#.strip()
req = urllib2.Request("http://"+str(self.client_address[0])+":8181/v_info.txt" )
response = urllib2.urlopen(req)
global v_info
v_info = response.readlines()
global webserver
webserver = str(self.client_address[0])
pack_ok(data)
class MyThreadingServer( SocketServer.ThreadingTCPServer ):
allow_reuse_address = 1
def server_bind(self):
SocketServer.ThreadingTCPServer.server_bind(self)
host, port = self.socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
def serverstart(hl_PORT):
if not HLserver:
global HLserver
ThreadingTCPServer.allow_reuse_address = True
HLserver = MyThreadingServer(("",hl_PORT), HLHandler)
HLserver.serve_forever()
######################################
FATAL!: addTimer must be called from thread 310 but is called from thread 386
Python stack trace:
/usr/lib/enigma2/python/Screens/InfoBarGenerics.py(157): __init__
/usr/lib/enigma2/python/Plugins/Extensions/test_Provider_P/plugin.py(224): __init__
/usr/lib/enigma2/python/mytest.py(340): create
/usr/lib/enigma2/python/mytest.py(361): doInstantiateDialog
/usr/lib/enigma2/python/mytest.py(350): instantiateDialog
/usr/lib/enigma2/python/mytest.py(420): open
/usr/lib/enigma2/python/Plugins/Extensions/test_Provider_P/plugin.py(173): pack_ok
/usr/lib/enigma2/python/Plugins/Extensions/test_Provider_P/plugin.py(110): handle
/usr/lib/python2.7/SocketServer.py(632): __init__
/usr/lib/python2.7/SocketServer.py(321): finish_request
/usr/lib/python2.7/SocketServer.py(575): process_request_thread
/usr/lib/python2.7/threading.py(501): run
/usr/lib/python2.7/threading.py(533): __bootstrap_inner
/usr/lib/python2.7/threading.py(510): __bootstrap
PC: 74c0d218
00000000 00000001 00000000 7fff0000
00000136 00000182 00000006 00000000
2f202020 2f727375 2f62696c 68747970
2e326e6f 6f532f37 74656b63 76726553
60b068d0 74d62654 74d68000 60afcf88
0239f940 64a01250 00f0f600 00000003
0000001b 74c0d1d0 00000000 00000000
74d68e20 60afced8 014081b4 74c12300
As a final action, i will try to dump a bit of code.
I just hope that this won't crash.
74c0d218: 0c 00 e0 14 00 00 00 00 04 00 b0 8f 08 00 e0 03 08 00 bd 27 f8 ff 80 1c ff 7f 03 3c ff ff 63 34 (end)
Alles anzeigen
Jetzt mal rein davon ausgehend wie ich das im Logfile verstehe ist das Problem recht klar.
Du öffnest den neuen Dialog in "pack_ok", aber alles was in "handle" passiert ist in einem eigenen Thread.
Wenn du also eine deiner Methoden aus "handle" heraus rufst bist du immer noch im request-thread, nicht im Main-Thread!
In deinem Fall rufst du also session.open und genau das darfst du auf keinen Fall.
Das Problem mit dem Threading lässt aber mit HIlfe von ein paar twisted (in dem Fall genau einem) Helfern super simpel lösen z.B. so:
from twisted.internet import reactor
class HLHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)#.strip()
req = urllib2.Request("http://"+str(self.client_address[0])+":8181/v_info.txt" )
response = urllib2.urlopen(req)
global v_info
v_info = response.readlines()
global webserver
webserver = str(self.client_address[0])
reactor.callFromThread(pack_ok,data)
Alles anzeigen
Die "v_info / webserver global" würde ich möglichst entfernen und auch über pack_ok mitschicken.