1
1
using System ;
2
- using System . IO ;
3
2
using System . Collections ;
4
- using System . Collections . Specialized ;
3
+ using System . IO ;
4
+ using System . Collections . Concurrent ;
5
5
using System . Collections . Generic ;
6
6
using System . Diagnostics ;
7
7
using System . Reflection ;
8
- using System . Reflection . Emit ;
8
+ using System . Threading ;
9
9
10
10
namespace Python . Runtime
11
11
{
@@ -15,12 +15,16 @@ namespace Python.Runtime
15
15
/// </summary>
16
16
internal class AssemblyManager
17
17
{
18
- static Dictionary < string , Dictionary < Assembly , string > > namespaces ;
18
+ // modified from event handlers below, potentially triggered from different .NET threads
19
+ // therefore this should be a ConcurrentDictionary
20
+ static ConcurrentDictionary < string , ConcurrentDictionary < Assembly , string > > namespaces ;
19
21
//static Dictionary<string, Dictionary<string, string>> generics;
20
22
static AssemblyLoadEventHandler lhandler ;
21
23
static ResolveEventHandler rhandler ;
24
+ // updated only under GIL?
22
25
static Dictionary < string , int > probed ;
23
- static List < Assembly > assemblies ;
26
+ // modified from event handlers below, potentially triggered from different .NET threads
27
+ static AssemblyList assemblies ;
24
28
internal static List < string > pypath ;
25
29
26
30
private AssemblyManager ( )
@@ -36,10 +40,10 @@ private AssemblyManager()
36
40
internal static void Initialize ( )
37
41
{
38
42
namespaces = new
39
- Dictionary < string , Dictionary < Assembly , string > > ( 32 ) ;
43
+ ConcurrentDictionary < string , ConcurrentDictionary < Assembly , string > > ( ) ;
40
44
probed = new Dictionary < string , int > ( 32 ) ;
41
45
//generics = new Dictionary<string, Dictionary<string, string>>();
42
- assemblies = new List < Assembly > ( 16 ) ;
46
+ assemblies = new AssemblyList ( 16 ) ;
43
47
pypath = new List < string > ( 16 ) ;
44
48
45
49
AppDomain domain = AppDomain . CurrentDomain ;
@@ -105,9 +109,8 @@ static void AssemblyLoadHandler(Object ob, AssemblyLoadEventArgs args)
105
109
static Assembly ResolveHandler ( Object ob , ResolveEventArgs args )
106
110
{
107
111
string name = args . Name . ToLower ( ) ;
108
- for ( int i = 0 ; i < assemblies . Count ; i ++ )
112
+ foreach ( Assembly a in assemblies )
109
113
{
110
- Assembly a = ( Assembly ) assemblies [ i ] ;
111
114
string full = a . FullName . ToLower ( ) ;
112
115
if ( full . StartsWith ( name ) )
113
116
{
@@ -266,9 +269,8 @@ public static Assembly LoadAssemblyFullPath(string name)
266
269
267
270
public static Assembly FindLoadedAssembly ( string name )
268
271
{
269
- for ( int i = 0 ; i < assemblies . Count ; i ++ )
272
+ foreach ( Assembly a in assemblies )
270
273
{
271
- Assembly a = ( Assembly ) assemblies [ i ] ;
272
274
if ( a . GetName ( ) . Name == name )
273
275
{
274
276
return a ;
@@ -295,15 +297,15 @@ public static bool LoadImplicit(string name, bool warn = true)
295
297
bool loaded = false ;
296
298
string s = "" ;
297
299
Assembly lastAssembly = null ;
298
- HashSet < Assembly > assemblies = null ;
300
+ HashSet < Assembly > assembliesSet = null ;
299
301
for ( int i = 0 ; i < names . Length ; i ++ )
300
302
{
301
303
s = ( i == 0 ) ? names [ 0 ] : s + "." + names [ i ] ;
302
304
if ( ! probed . ContainsKey ( s ) )
303
305
{
304
- if ( assemblies == null )
306
+ if ( assembliesSet == null )
305
307
{
306
- assemblies = new HashSet < Assembly > ( AppDomain . CurrentDomain . GetAssemblies ( ) ) ;
308
+ assembliesSet = new HashSet < Assembly > ( AppDomain . CurrentDomain . GetAssemblies ( ) ) ;
307
309
}
308
310
Assembly a = FindLoadedAssembly ( s ) ;
309
311
if ( a == null )
@@ -314,7 +316,7 @@ public static bool LoadImplicit(string name, bool warn = true)
314
316
{
315
317
a = LoadAssembly ( s ) ;
316
318
}
317
- if ( a != null && ! assemblies . Contains ( a ) )
319
+ if ( a != null && ! assembliesSet . Contains ( a ) )
318
320
{
319
321
loaded = true ;
320
322
lastAssembly = a ;
@@ -362,16 +364,13 @@ internal static void ScanAssembly(Assembly assembly)
362
364
for ( int n = 0 ; n < names . Length ; n ++ )
363
365
{
364
366
s = ( n == 0 ) ? names [ 0 ] : s + "." + names [ n ] ;
365
- if ( ! namespaces . ContainsKey ( s ) )
366
- {
367
- namespaces . Add ( s , new Dictionary < Assembly , string > ( ) ) ;
368
- }
367
+ namespaces . TryAdd ( s , new ConcurrentDictionary < Assembly , string > ( ) ) ;
369
368
}
370
369
}
371
370
372
- if ( ns != null && ! namespaces [ ns ] . ContainsKey ( assembly ) )
371
+ if ( ns != null )
373
372
{
374
- namespaces [ ns ] . Add ( assembly , String . Empty ) ;
373
+ namespaces [ ns ] . TryAdd ( assembly , String . Empty ) ;
375
374
}
376
375
377
376
if ( ns != null && t . IsGenericTypeDefinition )
@@ -383,14 +382,12 @@ internal static void ScanAssembly(Assembly assembly)
383
382
384
383
public static AssemblyName [ ] ListAssemblies ( )
385
384
{
386
- AssemblyName [ ] names = new AssemblyName [ assemblies . Count ] ;
387
- Assembly assembly ;
388
- for ( int i = 0 ; i < assemblies . Count ; i ++ )
385
+ List < AssemblyName > names = new List < AssemblyName > ( assemblies . Count ) ;
386
+ foreach ( Assembly assembly in assemblies )
389
387
{
390
- assembly = assemblies [ i ] ;
391
- names . SetValue ( assembly . GetName ( ) , i ) ;
388
+ names . Add ( assembly . GetName ( ) ) ;
392
389
}
393
- return names ;
390
+ return names . ToArray ( ) ;
394
391
}
395
392
396
393
//===================================================================
@@ -471,9 +468,8 @@ public static List<string> GetNames(string nsname)
471
468
472
469
public static Type LookupType ( string qname )
473
470
{
474
- for ( int i = 0 ; i < assemblies . Count ; i ++ )
471
+ foreach ( Assembly assembly in assemblies )
475
472
{
476
- Assembly assembly = ( Assembly ) assemblies [ i ] ;
477
473
Type type = assembly . GetType ( qname ) ;
478
474
if ( type != null )
479
475
{
@@ -482,5 +478,92 @@ public static Type LookupType(string qname)
482
478
}
483
479
return null ;
484
480
}
481
+
482
+ /// <summary>
483
+ /// Wrapper around List<Assembly> for thread safe access
484
+ /// </summary>
485
+ private class AssemblyList : IEnumerable < Assembly > {
486
+ private readonly List < Assembly > _list ;
487
+ private readonly ReaderWriterLockSlim _lock ;
488
+
489
+ public AssemblyList ( int capacity ) {
490
+ _list = new List < Assembly > ( capacity ) ;
491
+ _lock = new ReaderWriterLockSlim ( ) ;
492
+ }
493
+
494
+ public int Count
495
+ {
496
+ get
497
+ {
498
+ _lock . EnterReadLock ( ) ;
499
+ try {
500
+ return _list . Count ;
501
+ }
502
+ finally {
503
+ _lock . ExitReadLock ( ) ;
504
+ }
505
+ }
506
+ }
507
+
508
+ public void Add ( Assembly assembly ) {
509
+ _lock . EnterWriteLock ( ) ;
510
+ try
511
+ {
512
+ _list . Add ( assembly ) ;
513
+ }
514
+ finally
515
+ {
516
+ _lock . ExitWriteLock ( ) ;
517
+ }
518
+ }
519
+
520
+ public IEnumerator GetEnumerator ( )
521
+ {
522
+ return ( ( IEnumerable < Assembly > ) this ) . GetEnumerator ( ) ;
523
+ }
524
+
525
+ /// <summary>
526
+ /// Enumerator wrapping around <see cref="AssemblyList._list"/>'s enumerator.
527
+ /// Acquires and releases a read lock on <see cref="AssemblyList._lock"/> during enumeration
528
+ /// </summary>
529
+ private class Enumerator : IEnumerator < Assembly >
530
+ {
531
+ private readonly AssemblyList _assemblyList ;
532
+
533
+ private readonly IEnumerator < Assembly > _listEnumerator ;
534
+
535
+ public Enumerator ( AssemblyList assemblyList )
536
+ {
537
+ _assemblyList = assemblyList ;
538
+ _assemblyList . _lock . EnterReadLock ( ) ;
539
+ _listEnumerator = _assemblyList . _list . GetEnumerator ( ) ;
540
+ }
541
+
542
+ public void Dispose ( )
543
+ {
544
+ _listEnumerator . Dispose ( ) ;
545
+ _assemblyList . _lock . ExitReadLock ( ) ;
546
+ }
547
+
548
+ public bool MoveNext ( )
549
+ {
550
+ return _listEnumerator . MoveNext ( ) ;
551
+ }
552
+
553
+ public void Reset ( )
554
+ {
555
+ _listEnumerator . Reset ( ) ;
556
+ }
557
+
558
+ public Assembly Current { get { return _listEnumerator . Current ; } }
559
+
560
+ object IEnumerator . Current { get { return Current ; } }
561
+ }
562
+
563
+ IEnumerator < Assembly > IEnumerable < Assembly > . GetEnumerator ( )
564
+ {
565
+ return new Enumerator ( this ) ;
566
+ }
567
+ }
485
568
}
486
569
}
0 commit comments