# HG changeset patch # User etisserant # Date 1231086552 -3600 # Node ID a2a8a52b0d4ff91f70268acf0f89b51690235bfc # Parent e5782a52dceae350c299f21d92c58fb6fb635588 Minor changes to get better cleanup of debug and python_eval threads, accross multiple debug sessions and PLC runs. diff -r e5782a52dcea -r a2a8a52b0d4f plugger.py --- a/plugger.py Sun Jan 04 17:25:22 2009 +0100 +++ b/plugger.py Sun Jan 04 17:29:12 2009 +0100 @@ -700,6 +700,8 @@ self.BuildPath = None self.PLCEditor = None self.PLCDebug = None + self.DebugThread = None + self.debug_break = False # copy PluginMethods so that it can be later customized self.PluginMethods = [dic.copy() for dic in self.PluginMethods] @@ -1309,6 +1311,8 @@ self.logger.write_error("Build directory already clean\n") self.ShowMethod("_showIECcode", False) self.EnableMethod("_Clean", False) + # kill the builder + self._builder = None self.CompareLocalAndRemotePLC() ############# Real PLC object access ############# @@ -1434,8 +1438,8 @@ """ # This lock is used to avoid flooding wx event stack calling callafter self.DebugThreadSlowDownLock = Semaphore(0) - _break = False - while not _break and self._connector is not None: + self.debug_break = False + while (not self.debug_break) and (self._connector is not None): debug_tick, debug_vars = self._connector.GetTraceVariables() #print debug_tick, debug_vars self.IECdebug_lock.acquire() @@ -1459,11 +1463,19 @@ pass else: wx.CallAfter(self.logger.write, "Debugger disabled\n") - _break = True + self.debug_break = True self.IECdebug_lock.release() wx.CallAfter(self.DebugThreadSlowDownLock.release) self.DebugThreadSlowDownLock.acquire() + def KillDebugThread(self): + self.debug_break = True + self.DebugThreadSlowDownLock.release() + self.DebugThread.join(timeout=1) + if self.DebugThread.isAlive(): + self.logger.write_warning("Debug Thread couldn't be killed") + self.DebugThread = None + def _Debug(self): """ Start PLC (Debug Mode) @@ -1485,6 +1497,7 @@ self.logger.write_error("Couldn't start PLC debug !\n") self.UpdateMethodsFromPLCStatus() + # def _Do_Test_Debug(self): # # debug code # self.temporary_non_weak_callable_refs = [] @@ -1506,6 +1519,10 @@ """ Stop PLC """ + if self.DebugThread is not None: + self.logger.write("Stopping debug\n") + self.KillDebugThread() + if self._connector.StopPLC(): self.logger.write("Stopping PLC\n") else: diff -r e5782a52dcea -r a2a8a52b0d4f runtime/PLCObject.py --- a/runtime/PLCObject.py Sun Jan 04 17:25:22 2009 +0100 +++ b/runtime/PLCObject.py Sun Jan 04 17:29:12 2009 +0100 @@ -61,6 +61,10 @@ self.PLCStatus = "Empty" self.CurrentPLCFilename=None + def StatusChange(self): + if self.statuschange is not None: + self.statuschange(self.PLCStatus) + def _GetMD5FileName(self): return os.path.join(self.workingdir, "lasttransferedPLC.md5") @@ -169,21 +173,30 @@ return False def PythonThreadProc(self): + print "PythonThreadProc started" + my_globs = globals().copy() pyfile = os.path.join(self.workingdir, "runtime.py") if os.path.exists(pyfile): # TODO handle exceptions in runtime.py - execfile(pyfile) - res = "" - print "PythonThreadProc started" + # pyfile may redefine _runtime_cleanup + # or even call _PythonThreadProc itself. + execfile(pyfile, my_globs) + res,cmd = "None","None" while self.PLCStatus == "Started": + print "_PythonIterator(", res, ")", cmd = self._PythonIterator(res) - #print "_PythonIterator(", res, ") -> ", cmd + print " -> ", cmd + if cmd is None: + break try : - res = eval(cmd) + res = str(eval(cmd,my_globs)) except Exception,e: res = "#EXCEPTION : "+str(e) print res - print "PythonThreadProc finished" + print "PythonThreadProc interrupted" + if my_globs.get("_runtime_cleanup",None) is not None: + my_globs["_runtime_cleanup"]() + print "PythonThreadProc cleaned up" def StartPLC(self, debug=False): print "StartPLC" @@ -193,8 +206,7 @@ if debug: self._resumeDebug() self.PLCStatus = "Started" - if self.statuschange is not None: - self.statuschange(self.PLCStatus) + self.StatusChange() self.PythonThread = Thread(target=self.PythonThreadProc) self.PythonThread.start() return True @@ -206,10 +218,12 @@ def _DoStopPLC(self): self._stopPLC() self.PLCStatus = "Stopped" - if self.statuschange is not None: - self.statuschange(self.PLCStatus) + self.PythonThread.join(timeout=1) + if self.PythonThread.isAlive(): + print "Python thread couldn't be killed" if self._FreePLC(): self.PLCStatus = "Dirty" + self.StatusChange() return True def StopPLC(self): @@ -327,25 +341,27 @@ """ Return a list of variables, corresponding to the list of requiered idx """ - tick = self._WaitDebugData() - if tick == -1: - res = None - else: - idx = ctypes.c_int() - typename = ctypes.c_char_p() - res = [] - - for given_idx in self._Idxs: - buffer=self._IterDebugData(ctypes.byref(idx), ctypes.byref(typename)) - c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) - if c_type is not None and given_idx == idx.value: - res.append(unpack_func(ctypes.cast(buffer, - ctypes.POINTER(c_type)).contents)) - else: - print "Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value) - res.append(None) - self._FreeDebugData() - return tick, res - - - + if self.PLCStatus == "Started": + tick = self._WaitDebugData() + if tick == -1: + res = None + else: + idx = ctypes.c_int() + typename = ctypes.c_char_p() + res = [] + + for given_idx in self._Idxs: + buffer=self._IterDebugData(ctypes.byref(idx), ctypes.byref(typename)) + c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None)) + if c_type is not None and given_idx == idx.value: + res.append(unpack_func(ctypes.cast(buffer, + ctypes.POINTER(c_type)).contents)) + else: + print "Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value) + res.append(None) + self._FreeDebugData() + return tick, res + return -1, None + + + diff -r e5782a52dcea -r a2a8a52b0d4f targets/plc_common_main.c --- a/targets/plc_common_main.c Sun Jan 04 17:25:22 2009 +0100 +++ b/targets/plc_common_main.c Sun Jan 04 17:29:12 2009 +0100 @@ -69,6 +69,7 @@ int res; config_init__(); __init_debug(); + __init_python(); %(init_calls)s return 0; } @@ -79,6 +80,7 @@ { %(cleanup_calls)s __cleanup_debug(); + __cleanup_python(); } diff -r e5782a52dcea -r a2a8a52b0d4f targets/plc_python.c --- a/targets/plc_python.c Sun Jan 04 17:25:22 2009 +0100 +++ b/targets/plc_python.c Sun Jan 04 17:29:12 2009 +0100 @@ -29,6 +29,7 @@ #define PYTHON_LOCKED_BY_PYTHON 0 #define PYTHON_LOCKED_BY_PLC 1 #define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 /* Each python_eval FunctionBlock have it own state */ #define PYTHON_FB_FREE 0 @@ -55,6 +56,8 @@ void __cleanup_python() { + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); } void __retrieve_python() @@ -173,7 +176,10 @@ { UnLockPython(); /* wait next FB to eval */ + //printf("PythonIterator wait\n"); WaitPythonCommands(); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; LockPython(); } /* Mark block as processing */