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