6
6
using System . Collections . Generic ;
7
7
using System . IO ;
8
8
using System . Threading ;
9
+ using System . Threading . Tasks ;
9
10
using System . Reflection ;
10
11
11
12
namespace DBus
@@ -38,22 +39,23 @@ public class Connection
38
39
Dictionary < uint , PendingCall > pendingCalls = new Dictionary < uint , PendingCall > ( ) ;
39
40
Queue < Message > inbound = new Queue < Message > ( ) ;
40
41
Dictionary < ObjectPath , BusObject > registeredObjects = new Dictionary < ObjectPath , BusObject > ( ) ;
42
+ private readonly ReadMessageTask readMessageTask ;
41
43
42
44
public delegate void MonitorEventHandler ( Message msg ) ;
43
45
public MonitorEventHandler Monitors ; // subscribe yourself to this list of observers if you want to get notified about each incoming message
44
46
45
47
protected Connection ( )
46
48
{
47
-
49
+ readMessageTask = new ReadMessageTask ( this ) ;
48
50
}
49
51
50
- internal Connection ( Transport transport )
52
+ internal Connection ( Transport transport ) : this ( )
51
53
{
52
54
this . transport = transport ;
53
55
transport . Connection = this ;
54
56
}
55
57
56
- internal Connection ( string address )
58
+ internal Connection ( string address ) : this ( )
57
59
{
58
60
OpenPrivate ( address ) ;
59
61
Authenticate ( ) ;
@@ -183,11 +185,12 @@ internal uint GenerateSerial ()
183
185
184
186
internal Message SendWithReplyAndBlock ( Message msg , bool keepFDs )
185
187
{
186
- PendingCall pending = SendWithReply ( msg , keepFDs ) ;
187
- return pending . Reply ;
188
+ using ( PendingCall pending = SendWithPendingReply ( msg , keepFDs ) ) {
189
+ return pending . Reply ;
190
+ }
188
191
}
189
192
190
- internal PendingCall SendWithReply ( Message msg , bool keepFDs )
193
+ internal PendingCall SendWithPendingReply ( Message msg , bool keepFDs )
191
194
{
192
195
msg . ReplyExpected = true ;
193
196
@@ -215,27 +218,23 @@ internal virtual uint Send (Message msg)
215
218
return msg . Header . Serial ;
216
219
}
217
220
218
- //temporary hack
219
- internal void DispatchSignals ( )
221
+ public void Iterate ( )
220
222
{
221
- lock ( inbound ) {
222
- while ( inbound . Count != 0 ) {
223
- Message msg = inbound . Dequeue ( ) ;
224
- try {
225
- HandleSignal ( msg ) ;
226
- } finally {
227
- msg . Dispose ( ) ;
228
- }
229
- }
230
- }
223
+ Iterate ( new CancellationToken ( false ) ) ;
231
224
}
232
225
233
- public void Iterate ( )
226
+ public void Iterate ( CancellationToken stopWaitToken )
234
227
{
235
- Message msg = transport . ReadMessage ( ) ;
236
-
237
- HandleMessage ( msg ) ;
238
- DispatchSignals ( ) ;
228
+ if ( TryGetStoredSignalMessage ( out Message inboundMsg ) ) {
229
+ try {
230
+ HandleSignal ( inboundMsg ) ;
231
+ } finally {
232
+ inboundMsg . Dispose ( ) ;
233
+ }
234
+ } else {
235
+ var msg = readMessageTask . MakeSureTaskRunAndWait ( stopWaitToken ) ;
236
+ HandleMessage ( msg ) ;
237
+ }
239
238
}
240
239
241
240
internal virtual void HandleMessage ( Message msg )
@@ -251,21 +250,19 @@ internal virtual void HandleMessage (Message msg)
251
250
try {
252
251
253
252
//TODO: Restrict messages to Local ObjectPath?
254
-
255
253
{
256
- object field_value = msg . Header [ FieldCode . ReplySerial ] ;
254
+ object field_value = msg . Header [ FieldCode . ReplySerial ] ;
257
255
if ( field_value != null ) {
258
256
uint reply_serial = ( uint ) field_value ;
259
- PendingCall pending ;
260
257
261
258
lock ( pendingCalls ) {
259
+ PendingCall pending ;
262
260
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
-
261
+ if ( ! pendingCalls . Remove ( reply_serial ) )
262
+ return ;
263
+ pending . Reply = msg ;
264
+ if ( pending . KeepFDs )
265
+ cleanupFDs = false ; // caller is responsible for closing FDs
269
266
return ;
270
267
}
271
268
}
@@ -285,8 +282,7 @@ internal virtual void HandleMessage (Message msg)
285
282
break ;
286
283
case MessageType . Signal :
287
284
//HandleSignal (msg);
288
- lock ( inbound )
289
- inbound . Enqueue ( msg ) ;
285
+ StoreInboundSignalMessage ( msg ) ; //temporary hack
290
286
cleanupFDs = false ; // FDs are closed after signal is handled
291
287
break ;
292
288
case MessageType . Error :
@@ -391,17 +387,19 @@ internal void HandleMethodCall (MessageContainer method_call)
391
387
//this is messy and inefficient
392
388
List < string > linkNodes = new List < string > ( ) ;
393
389
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 ) ;
390
+ lock ( registeredObjects ) {
391
+ foreach ( ObjectPath pth in registeredObjects . Keys ) {
392
+ if ( pth . Value == ( method_call . Path . Value ) ) {
393
+ ExportObject exo = ( ExportObject ) registeredObjects [ pth ] ;
394
+ exo . WriteIntrospect ( intro ) ;
395
+ } else {
396
+ for ( ObjectPath cur = pth ; cur != null ; cur = cur . Parent ) {
397
+ if ( cur . Value == method_call . Path . Value ) {
398
+ string linkNode = pth . Decomposed [ depth ] ;
399
+ if ( ! linkNodes . Contains ( linkNode ) ) {
400
+ intro . WriteNode ( linkNode ) ;
401
+ linkNodes . Add ( linkNode ) ;
402
+ }
405
403
}
406
404
}
407
405
}
@@ -415,12 +413,14 @@ internal void HandleMethodCall (MessageContainer method_call)
415
413
return ;
416
414
}
417
415
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 ) ;
416
+ lock ( registeredObjects ) {
417
+ BusObject bo ;
418
+ if ( registeredObjects . TryGetValue ( method_call . Path , out bo ) ) {
419
+ ExportObject eo = ( ExportObject ) bo ;
420
+ eo . HandleMethodCall ( method_call ) ;
421
+ } else {
422
+ MaybeSendUnknownMethodError ( method_call ) ;
423
+ }
424
424
}
425
425
}
426
426
@@ -459,17 +459,19 @@ public void Register (ObjectPath path, object obj)
459
459
eo . Registered = true ;
460
460
461
461
//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 ;
462
+ lock ( registeredObjects )
463
+ registeredObjects [ path ] = eo ;
463
464
}
464
465
465
466
public object Unregister ( ObjectPath path )
466
467
{
467
468
BusObject bo ;
468
469
469
- if ( ! registeredObjects . TryGetValue ( path , out bo ) )
470
- throw new Exception ( "Cannot unregister " + path + " as it isn't registered" ) ;
471
-
472
- registeredObjects . Remove ( path ) ;
470
+ lock ( registeredObjects ) {
471
+ if ( ! registeredObjects . TryGetValue ( path , out bo ) )
472
+ throw new Exception ( "Cannot unregister " + path + " as it isn't registered" ) ;
473
+ registeredObjects . Remove ( path ) ;
474
+ }
473
475
474
476
ExportObject eo = ( ExportObject ) bo ;
475
477
eo . Registered = false ;
@@ -486,6 +488,25 @@ internal protected virtual void RemoveMatch (string rule)
486
488
{
487
489
}
488
490
491
+ private void StoreInboundSignalMessage ( Message msg )
492
+ {
493
+ lock ( inbound ) {
494
+ inbound . Enqueue ( msg ) ;
495
+ }
496
+ }
497
+
498
+ private bool TryGetStoredSignalMessage ( out Message msg )
499
+ {
500
+ msg = null ;
501
+ lock ( inbound ) {
502
+ if ( inbound . Count != 0 ) {
503
+ msg = inbound . Dequeue ( ) ;
504
+ return true ;
505
+ }
506
+ }
507
+ return false ;
508
+ }
509
+
489
510
static UUID ReadMachineId ( string fname )
490
511
{
491
512
byte [ ] data = File . ReadAllBytes ( fname ) ;
@@ -494,5 +515,31 @@ static UUID ReadMachineId (string fname)
494
515
495
516
return UUID . Parse ( System . Text . Encoding . ASCII . GetString ( data , 0 , 32 ) ) ;
496
517
}
518
+
519
+ private class ReadMessageTask
520
+ {
521
+ private readonly Connection ownerConnection ;
522
+ private Task < Message > task = null ;
523
+ private object taskLock = new object ( ) ;
524
+
525
+ public ReadMessageTask ( Connection connection )
526
+ {
527
+ ownerConnection = connection ;
528
+ }
529
+
530
+ public Message MakeSureTaskRunAndWait ( CancellationToken stopWaitToken )
531
+ {
532
+ Task < Message > catchedTask = null ;
533
+
534
+ lock ( taskLock ) {
535
+ if ( task == null || task . IsCompleted ) {
536
+ task = Task < Message > . Run ( ( ) => ownerConnection . transport . ReadMessage ( ) ) ;
537
+ }
538
+ catchedTask = task ;
539
+ }
540
+ catchedTask . Wait ( stopWaitToken ) ;
541
+ return catchedTask . Result ;
542
+ }
543
+ }
497
544
}
498
545
}
0 commit comments