@@ -28,6 +28,7 @@ func NewPMCProcess(runID int, eventHandler *event.EventHandler, clockType string
2828 configFileName : fmt .Sprintf ("ptp4l.%d.config" , runID ),
2929 messageTag : fmt .Sprintf ("[ptp4l.%d.config:{level}]" , runID ),
3030 monitorParentData : true ,
31+ parentDSCh : make (chan protocol.ParentDataSet , 10 ),
3132 eventHandler : eventHandler ,
3233 clockType : clockType ,
3334 }
@@ -43,6 +44,7 @@ type PMCProcess struct {
4344 monitorParentData bool
4445 monitorCMLDS bool
4546 parentDS * protocol.ParentDataSet
47+ parentDSCh chan protocol.ParentDataSet
4648 exitCh chan struct {}
4749 clockType string
4850 c net.Conn
@@ -73,10 +75,8 @@ func (pmc *PMCProcess) getAndSetStopped(val bool) bool {
7375// CmdStop signals the process to stop.
7476func (pmc * PMCProcess ) CmdStop () {
7577 pmc .getAndSetStopped (true )
76- // Close the channel to broadcast stop signal to all receivers
7778 select {
7879 case <- pmc .exitCh :
79- // Already closed
8080 default :
8181 close (pmc .exitCh )
8282 }
@@ -127,16 +127,6 @@ func (pmc *PMCProcess) EmitClockClassLogs(c net.Conn) {
127127 go pmc .eventHandler .EmitClockClass (pmc .configFileName , pmc .c )
128128}
129129
130- // Poll polls the parent data set from PMC.
131- func (pmc * PMCProcess ) Poll () error {
132- parentDS , err := pmcPkg .RunPMCExpGetParentDS (pmc .configFileName )
133- if err != nil {
134- return err
135- }
136- pmc .handleParentDS (parentDS )
137- return nil
138- }
139-
140130// CmdRun starts the PMC monitoring process.
141131func (pmc * PMCProcess ) CmdRun (stdToSocket bool ) {
142132 isStopped := pmc .getAndSetStopped (false )
@@ -161,26 +151,41 @@ func (pmc *PMCProcess) CmdRun(stdToSocket bool) {
161151 }
162152 monitorErr := pmc .Monitor (c )
163153 if monitorErr == nil && pmc .Stopped () {
164- // No error completed gracefully
165154 return
166155 }
167156 }
168157 }()
169158}
170159
171- func (pmc * PMCProcess ) monitor (conn net.Conn ) error {
172- if conn != nil {
173- pmc .c = conn
160+ // workerSignal represents a signal from the expectWorker to the main monitor loop
161+ type workerSignal struct {
162+ err error
163+ restartProcess bool
164+ }
165+
166+ // Poll runs a Poll operation in a goroutine and sends the result to the struct's ParentDataSet channel
167+ func (pmc * PMCProcess ) Poll () {
168+ select {
169+ case <- pmc .exitCh :
170+ return
171+ default :
174172 }
175173
176- err := pmc . Poll () // Set/Anounce current value to initialise or incase message was missed.
174+ parentDS , err := pmcPkg . RunPMCExpGetParentDS ( pmc . configFileName , false )
177175 if err != nil {
178- glog .Error ("Failed to initialise clock class" )
176+ return
177+ }
178+
179+ pmc .parentDSCh <- parentDS
180+ }
181+
182+ func (pmc * PMCProcess ) monitor (conn net.Conn ) error {
183+ if conn != nil {
184+ pmc .c = conn
179185 }
180186
181187 exp , r , err := pmcPkg .GetPMCMontior (pmc .configFileName )
182188 if err != nil {
183- // Clean up the spawned process if initialization failed
184189 if exp != nil {
185190 utils .CloseExpect (exp , r )
186191 }
@@ -191,42 +196,68 @@ func (pmc *PMCProcess) monitor(conn net.Conn) error {
191196 subscribeCmd := pmc .getMonitorSubcribeCommand ()
192197 glog .Infof ("Sending '%s' to pmc" , subscribeCmd )
193198 exp .Send (subscribeCmd + "\n " )
199+
200+ workerCh := make (chan workerSignal , 5 )
201+
202+ go pmc .expectWorker (exp , pmc .parentDSCh , workerCh )
203+
194204 for {
195- _ , matches , expectErr := exp .Expect (pmcPkg .GetMonitorRegex (pmc .monitorParentData ), pollTimeout )
196205 select {
197206 case <- r :
198207 glog .Warningf ("PMC monitoring process exited" )
199208 return fmt .Errorf ("PMC needs to restart" )
200209 case <- pmc .exitCh :
201- return nil // TODO close gracefully
202- default :
203- if expectErr != nil {
204- if _ , ok := expectErr .(expect.TimeoutError ); ok {
205- continue
206- } else if strings .Contains (expectErr .Error (), "EOF" ) || strings .Contains (expectErr .Error (), "exit" ) {
207- glog .Warningf ("PMC process exited (%v)" , expectErr )
208- return fmt .Errorf ("PMC needs to restart" )
209- }
210- glog .Errorf ("Error waiting for notification: %v" , expectErr )
211- continue
210+ return nil
211+ case parentDS := <- pmc .parentDSCh :
212+ go pmc .handleParentDS (parentDS )
213+ case signal := <- workerCh :
214+ if signal .restartProcess {
215+ glog .Warningf ("PMC process exited (%v)" , signal .err )
216+ return fmt .Errorf ("PMC needs to restart" )
212217 }
213- if len (matches ) == 0 {
218+ }
219+ }
220+ }
221+
222+ func (pmc * PMCProcess ) expectWorker (exp * expect.GExpect , parentDSCh chan <- protocol.ParentDataSet , signalCh chan <- workerSignal ) {
223+ for {
224+ select {
225+ case <- pmc .exitCh :
226+ return
227+ default :
228+ }
229+
230+ go pmc .Poll () // Check if anything changed while handling the last message
231+ _ , matches , expectErr := exp .Expect (pmcPkg .GetMonitorRegex (pmc .monitorParentData ), - 1 )
232+
233+ if expectErr != nil {
234+ if _ , ok := expectErr .(expect.TimeoutError ); ok {
214235 continue
236+ } else if strings .Contains (expectErr .Error (), "EOF" ) || strings .Contains (expectErr .Error (), "exit" ) {
237+ signalCh <- workerSignal {err : expectErr , restartProcess : true }
238+ return
215239 }
216- if strings .Contains (matches [0 ], "PARENT_DATA_SET" ) {
217- processedMessage , procErr := protocol.ProcessMessage [protocol.ParentDataSet ](matches )
218- if procErr != nil {
219- glog .Warningf ("failed to process message for PARENT_DATA_SET: %s" , procErr )
220- // maybe we should attempt a poll here?
221- continue
222- }
223- go pmc .handleParentDS (* processedMessage )
240+ continue
241+ }
242+
243+ if len (matches ) > 0 && strings .Contains (matches [0 ], "PARENT_DATA_SET" ) {
244+ processedMessage , procErr := protocol.ProcessMessage [protocol.ParentDataSet ](matches )
245+ if procErr != nil {
246+ glog .Warningf ("failed to process message for PARENT_DATA_SET: %s" , procErr )
247+ } else {
248+ parentDSCh <- * processedMessage
224249 }
225250 }
251+
226252 }
227253}
228254
229255func (pmc * PMCProcess ) handleParentDS (parentDS protocol.ParentDataSet ) {
256+ if pmc .parentDS != nil && pmc .parentDS .Equal (& parentDS ) {
257+ glog .Infof ("ParentDataSet unchanged, skipping processing for %s" , pmc .configFileName )
258+ return
259+ }
260+
230261 glog .Info (parentDS )
231262 oldParentDS := pmc .parentDS
232263 pmc .parentDS = & parentDS
@@ -252,13 +283,11 @@ func (pmc *PMCProcess) Monitor(c net.Conn) error {
252283 for {
253284 err := pmc .monitor (c )
254285 if err != nil {
255- // Check if we should stop before restarting
256286 select {
257287 case <- pmc .exitCh :
258288 glog .Info ("PMC Monitor stopping gracefully" )
259289 return nil
260290 default :
261- // If there is an error we need to restart
262291 glog .Info ("pmc process hit an issue (%s). restarting..." , err )
263292 continue
264293 }
0 commit comments