66using System . Collections . Generic ;
77using System . IO ;
88using System . Threading ;
9+ using System . Threading . Tasks ;
910using System . Reflection ;
1011
1112namespace DBus
@@ -42,9 +43,11 @@ public class Connection
4243 public delegate void MonitorEventHandler ( Message msg ) ;
4344 public MonitorEventHandler Monitors ; // subscribe yourself to this list of observers if you want to get notified about each incoming message
4445
46+ private ManualResetEventSlim iterateEvent = MakeNewEventToNextIterate ( ) ;
47+ private readonly object iterateLocker = new object ( ) ;
48+
4549 protected Connection ( )
4650 {
47-
4851 }
4952
5053 internal Connection ( Transport transport )
@@ -183,11 +186,12 @@ internal uint GenerateSerial ()
183186
184187 internal Message SendWithReplyAndBlock ( Message msg , bool keepFDs )
185188 {
186- PendingCall pending = SendWithReply ( msg , keepFDs ) ;
187- return pending . Reply ;
189+ using ( PendingCall pending = SendWithPendingReply ( msg , keepFDs ) ) {
190+ return pending . Reply ;
191+ }
188192 }
189193
190- internal PendingCall SendWithReply ( Message msg , bool keepFDs )
194+ internal PendingCall SendWithPendingReply ( Message msg , bool keepFDs )
191195 {
192196 msg . ReplyExpected = true ;
193197
@@ -232,10 +236,30 @@ internal void DispatchSignals ()
232236
233237 public void Iterate ( )
234238 {
235- Message msg = transport . ReadMessage ( ) ;
239+ Iterate ( new CancellationToken ( false ) ) ;
240+ }
241+
242+ Task Task = null ;
243+ object TaskLock = new object ( ) ;
236244
237- HandleMessage ( msg ) ;
238- DispatchSignals ( ) ;
245+ public void Iterate ( CancellationToken stopWaitToken )
246+ {
247+ lock ( TaskLock ) {
248+ if ( Task == null || Task . IsCompleted ) {
249+ Task = Task . Run ( ( ) => {
250+ var msg = transport . ReadMessage ( ) ;
251+ HandleMessage ( msg ) ;
252+ DispatchSignals ( ) ;
253+ } ) ;
254+ }
255+ }
256+
257+ Task . Wait ( stopWaitToken ) ;
258+ }
259+
260+ private static ManualResetEventSlim MakeNewEventToNextIterate ( )
261+ {
262+ return new ManualResetEventSlim ( true ) ;
239263 }
240264
241265 internal virtual void HandleMessage ( Message msg )
@@ -251,21 +275,19 @@ internal virtual void HandleMessage (Message msg)
251275 try {
252276
253277 //TODO: Restrict messages to Local ObjectPath?
254-
255278 {
256- object field_value = msg . Header [ FieldCode . ReplySerial ] ;
279+ object field_value = msg . Header [ FieldCode . ReplySerial ] ;
257280 if ( field_value != null ) {
258281 uint reply_serial = ( uint ) field_value ;
259- PendingCall pending ;
260282
261283 lock ( pendingCalls ) {
284+ PendingCall pending ;
262285 if ( pendingCalls . TryGetValue ( reply_serial , out pending ) ) {
263- if ( pendingCalls . Remove ( reply_serial ) ) {
264- pending . Reply = msg ;
265- if ( pending . KeepFDs )
266- cleanupFDs = false ; // caller is responsible for closing FDs
267- }
268-
286+ if ( ! pendingCalls . Remove ( reply_serial ) )
287+ return ;
288+ pending . Reply = msg ;
289+ if ( pending . KeepFDs )
290+ cleanupFDs = false ; // caller is responsible for closing FDs
269291 return ;
270292 }
271293 }
@@ -391,17 +413,19 @@ internal void HandleMethodCall (MessageContainer method_call)
391413 //this is messy and inefficient
392414 List < string > linkNodes = new List < string > ( ) ;
393415 int depth = method_call . Path . Decomposed . Length ;
394- foreach ( ObjectPath pth in registeredObjects . Keys ) {
395- if ( pth . Value == ( method_call . Path . Value ) ) {
396- ExportObject exo = ( ExportObject ) registeredObjects [ pth ] ;
397- exo . WriteIntrospect ( intro ) ;
398- } else {
399- for ( ObjectPath cur = pth ; cur != null ; cur = cur . Parent ) {
400- if ( cur . Value == method_call . Path . Value ) {
401- string linkNode = pth . Decomposed [ depth ] ;
402- if ( ! linkNodes . Contains ( linkNode ) ) {
403- intro . WriteNode ( linkNode ) ;
404- linkNodes . Add ( linkNode ) ;
416+ lock ( registeredObjects ) {
417+ foreach ( ObjectPath pth in registeredObjects . Keys ) {
418+ if ( pth . Value == ( method_call . Path . Value ) ) {
419+ ExportObject exo = ( ExportObject ) registeredObjects [ pth ] ;
420+ exo . WriteIntrospect ( intro ) ;
421+ } else {
422+ for ( ObjectPath cur = pth ; cur != null ; cur = cur . Parent ) {
423+ if ( cur . Value == method_call . Path . Value ) {
424+ string linkNode = pth . Decomposed [ depth ] ;
425+ if ( ! linkNodes . Contains ( linkNode ) ) {
426+ intro . WriteNode ( linkNode ) ;
427+ linkNodes . Add ( linkNode ) ;
428+ }
405429 }
406430 }
407431 }
@@ -415,12 +439,14 @@ internal void HandleMethodCall (MessageContainer method_call)
415439 return ;
416440 }
417441
418- BusObject bo ;
419- if ( registeredObjects . TryGetValue ( method_call . Path , out bo ) ) {
420- ExportObject eo = ( ExportObject ) bo ;
421- eo . HandleMethodCall ( method_call ) ;
422- } else {
423- MaybeSendUnknownMethodError ( method_call ) ;
442+ lock ( registeredObjects ) {
443+ BusObject bo ;
444+ if ( registeredObjects . TryGetValue ( method_call . Path , out bo ) ) {
445+ ExportObject eo = ( ExportObject ) bo ;
446+ eo . HandleMethodCall ( method_call ) ;
447+ } else {
448+ MaybeSendUnknownMethodError ( method_call ) ;
449+ }
424450 }
425451 }
426452
@@ -459,17 +485,19 @@ public void Register (ObjectPath path, object obj)
459485 eo . Registered = true ;
460486
461487 //TODO: implement some kind of tree data structure or internal object hierarchy. right now we are ignoring the name and putting all object paths in one namespace, which is bad
462- registeredObjects [ path ] = eo ;
488+ lock ( registeredObjects )
489+ registeredObjects [ path ] = eo ;
463490 }
464491
465492 public object Unregister ( ObjectPath path )
466493 {
467494 BusObject bo ;
468495
469- if ( ! registeredObjects . TryGetValue ( path , out bo ) )
470- throw new Exception ( "Cannot unregister " + path + " as it isn't registered" ) ;
471-
472- registeredObjects . Remove ( path ) ;
496+ lock ( registeredObjects ) {
497+ if ( ! registeredObjects . TryGetValue ( path , out bo ) )
498+ throw new Exception ( "Cannot unregister " + path + " as it isn't registered" ) ;
499+ registeredObjects . Remove ( path ) ;
500+ }
473501
474502 ExportObject eo = ( ExportObject ) bo ;
475503 eo . Registered = false ;
0 commit comments