# HG changeset patch # User Edouard Tisserant # Date 1548940206 -3600 # Node ID ef327451d0675d73a4bc56bbbf742adee1a6ac0a # Parent 2318a7cde10185b510534d4d9546a1d49bcafa68 Add a debugger token to SetTraceVariables and GetTraceVariables to prevent crash an inconsistant data in case of multiple connections. Last connection now takes over existing connections's debug, and first connected IDE gets a wrning. diff -r 2318a7cde101 -r ef327451d067 BeremizIDE.py --- a/BeremizIDE.py Tue Jan 29 09:14:47 2019 +0100 +++ b/BeremizIDE.py Thu Jan 31 14:10:06 2019 +0100 @@ -209,10 +209,6 @@ def write_error(self, s): self.write(s, self.red_yellow) - def writeyield(self, s): - self.write(s) - wx.GetApp().Yield() - def flush(self): # Temporary deactivate read only mode on StyledTextCtrl for clearing # text. It seems that text modifications, even programmatically, are diff -r 2318a7cde101 -r ef327451d067 ProjectController.py --- a/ProjectController.py Tue Jan 29 09:14:47 2019 +0100 +++ b/ProjectController.py Thu Jan 31 14:10:06 2019 +0100 @@ -270,6 +270,8 @@ self.previous_plcstate = None # copy StatusMethods so that it can be later customized self.StatusMethods = [dic.copy() for dic in self.StatusMethods] + self.DebugToken = None + self.debug_status = PlcStatus.Stopped def __del__(self): if self.DebugTimer: @@ -1479,11 +1481,12 @@ self.UpdateMethodsFromPLCStatus() def SnapshotAndResetDebugValuesBuffers(self): - if self._connector is not None: - plc_status, Traces = self._connector.GetTraceVariables() + debug_status = PlcStatus.Disconnected + if self._connector is not None and self.DebugToken is not None: + debug_status, Traces = self._connector.GetTraceVariables(self.DebugToken) # print [dict.keys() for IECPath, (dict, log, status, fvalue) in # self.IECdebug_datas.items()] - if plc_status == PlcStatus.Started: + if debug_status == PlcStatus.Started: if len(Traces) > 0: for debug_tick, debug_buff in Traces: debug_vars = UnpackDebugBuffer( @@ -1509,14 +1512,14 @@ ticks, self.DebugTicks = self.DebugTicks, [] - return ticks, buffers + return debug_status, ticks, buffers def RegisterDebugVarToConnector(self): self.DebugTimer = None Idxs = [] self.TracedIECPath = [] self.TracedIECTypes = [] - if self._connector is not None: + if self._connector is not None and self.debug_status != PlcStatus.Broken: IECPathsToPop = [] for IECPath, data_tuple in self.IECdebug_datas.iteritems(): WeakCallableDict, _data_log, _status, fvalue, _buffer_list = data_tuple @@ -1545,11 +1548,12 @@ IdxsT = zip(*Idxs) self.TracedIECPath = IdxsT[3] self.TracedIECTypes = IdxsT[1] - self._connector.SetTraceVariablesList(zip(*IdxsT[0:3])) + self.DebugToken = self._connector.SetTraceVariablesList(zip(*IdxsT[0:3])) else: self.TracedIECPath = [] self._connector.SetTraceVariablesList([]) - self.SnapshotAndResetDebugValuesBuffers() + self.DebugToken = None + self.debug_status, _debug_ticks, _buffers = self.SnapshotAndResetDebugValuesBuffers() def IsPLCStarted(self): return self.previous_plcstate == PlcStatus.Started @@ -1665,7 +1669,7 @@ return self._connector.RemoteExec(script, **kwargs) def DispatchDebugValuesProc(self, event): - debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers() + self.debug_status, debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers() start_time = time.time() if len(self.TracedIECPath) == len(buffers): for IECPath, values in zip(self.TracedIECPath, buffers): @@ -1676,11 +1680,15 @@ self.CallWeakcallables( "__tick__", "NewDataAvailable", debug_ticks) - delay = time.time() - start_time - next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay) - if self.DispatchDebugValuesTimer is not None: - self.DispatchDebugValuesTimer.Start( - int(next_refresh * 1000), oneShot=True) + if self.debug_status == PlcStatus.Broken: + self.logger.write_warning( + _("Debug: token rejected - other debug took over - reconnect to recover\n")) + else: + delay = time.time() - start_time + next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay) + if self.DispatchDebugValuesTimer is not None: + self.DispatchDebugValuesTimer.Start( + int(next_refresh * 1000), oneShot=True) event.Skip() def KillDebugThread(self): @@ -1691,6 +1699,9 @@ self.previous_plcstate = None if self.AppFrame: self.AppFrame.ResetGraphicViewers() + + self.debug_status = PlcStatus.Started + self.RegisterDebugVarToConnector() if self.DispatchDebugValuesTimer is not None: self.DispatchDebugValuesTimer.Start( @@ -1727,7 +1738,6 @@ if connector is not None: if self.StatusTimer is not None: # Start the status Timer - wx.Yield() self.StatusTimer.Start(milliseconds=500, oneShot=False) else: if self.StatusTimer is not None: diff -r 2318a7cde101 -r ef327451d067 runtime/PLCObject.py --- a/runtime/PLCObject.py Tue Jan 29 09:14:47 2019 +0100 +++ b/runtime/PLCObject.py Thu Jan 31 14:10:06 2019 +0100 @@ -99,6 +99,7 @@ self.TraceThread = None self.TraceLock = Lock() self.Traces = [] + self.DebugToken = 0 self._init_blobs() @@ -567,11 +568,13 @@ pass return False + @RunInMain def SetTraceVariablesList(self, idxs): """ Call ctype imported function to append these indexes to registred variables in PLC debugger """ + self.DebugToken += 1 if idxs: # suspend but dont disable if self._suspendDebug(False) == 0: @@ -586,8 +589,10 @@ self._RegisterDebugVariable(idx, force) self._TracesSwap() self._resumeDebug() + return self.DebugToken else: self._suspendDebug(True) + return None def _TracesSwap(self): self.LastSwapTrace = time() @@ -601,8 +606,11 @@ return Traces @RunInMain - def GetTraceVariables(self): - return self.PLCStatus, self._TracesSwap() + def GetTraceVariables(self, DebugToken): + if (DebugToken is not None and + DebugToken == self.DebugToken): + return self.PLCStatus, self._TracesSwap() + return PlcStatus.Broken, [] def TraceThreadProc(self): """