diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index ee2c9d4e..fa1028fc 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2014 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -138,7 +138,7 @@ namespace MathNet.Numerics /// /// Gets or sets a value indicating whether to use thread safe random number generators (RNG). - /// Thread safe RNG about two and half time slower than non-thread safe RNG. + /// Thread safe RNG about two and half time slower than non-thread safe RNG. /// /// /// true to use thread safe random number generators ; otherwise, false. @@ -148,7 +148,7 @@ namespace MathNet.Numerics /// /// Optional path to try to load native provider binaries from. /// - public static DirectoryInfo NativeProviderPath { get; set; } + public static string NativeProviderPath { get; set; } /// /// Gets or sets the linear algebra provider. Consider to use UseNativeMKL or UseManaged instead. diff --git a/src/Numerics/Providers/NativeProviderLoader.cs b/src/Numerics/Providers/NativeProviderLoader.cs index f9e19c40..0f4824b4 100644 --- a/src/Numerics/Providers/NativeProviderLoader.cs +++ b/src/Numerics/Providers/NativeProviderLoader.cs @@ -34,6 +34,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Security; +using System.Threading; #if NATIVE @@ -44,69 +45,29 @@ namespace MathNet.Numerics.Providers /// internal static class NativeProviderLoader { - static Lazy> _ArchitectureDirectories - = new Lazy>( - () => new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "x86", "x86" }, - { "AMD64", "x64" }, - { "IA64", "ia64" }, - { "ARM", "arm" } - }, - true); - - /// - /// Default directories for each architecture. - /// - static Dictionary ArchitectureDirectories - { - get { return _ArchitectureDirectories.Value; } - } + static readonly object StaticLock = new Object(); - static Lazy> _nativeHandles = new Lazy>(true); + const string X86 = "x86"; + const string X64 = "x64"; + const string IA64 = "ia64"; + const string ARM = "arm"; + const string ARM64 = "arm64"; /// /// Dictionary of handles to previously loaded libraries, /// - static Dictionary NativeHandles - { - get { return _nativeHandles.Value; } - } - - static string _ArchDirectory = null; + static readonly Lazy> NativeHandles = new Lazy>(LazyThreadSafetyMode.PublicationOnly); /// /// Gets a string indicating the architecture and bitness of the current process. /// - static string ArchDirectory - { - get - { - if (string.IsNullOrEmpty(_ArchDirectory)) - { - string architecture; - if (IsUnix) - { - // Only support x86 and amd64 on Unix as there isn't a reliable way to detect the architecture - architecture = Environment.Is64BitProcess ? "AMD64" : "x86"; - } - else - { - architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); - if (!Environment.Is64BitProcess && string.Equals(architecture, "AMD64", StringComparison.OrdinalIgnoreCase)) - { - architecture = "x86"; - } - } - - // Fallback to using the architecture name if unknown - if (!ArchitectureDirectories.TryGetValue(architecture, out _ArchDirectory)) - _ArchDirectory = architecture; - } + static readonly Lazy ArchitectureKey = new Lazy(EvaluateArchitectureKey, LazyThreadSafetyMode.PublicationOnly); - return _ArchDirectory; - } - } + /// + /// If the last native library failed to load then gets the corresponding exception + /// which occurred or null if the library was successfully loaded. + /// + public static Exception LastException { get; private set; } static bool IsUnix { @@ -117,13 +78,40 @@ namespace MathNet.Numerics.Providers } } - /// - /// If the last native library failed to load then gets the corresponding exception - /// which occurred or null if the library was successfully loaded. - /// - public static Exception LastException { get; private set; } + static string EvaluateArchitectureKey() + { + if (IsUnix) + { + // Only support x86 and amd64 on Unix as there isn't a reliable way to detect the architecture + return Environment.Is64BitProcess ? X64 : X86; + } - static readonly object StaticLock = new Object(); + var architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); + + if (string.Equals(architecture, "x86", StringComparison.OrdinalIgnoreCase)) + { + return X86; + } + + if (string.Equals(architecture, "amd64", StringComparison.OrdinalIgnoreCase) + || string.Equals(architecture, "x64", StringComparison.OrdinalIgnoreCase)) + { + return Environment.Is64BitProcess ? X64 : X86; + } + + if (string.Equals(architecture, "ia64", StringComparison.OrdinalIgnoreCase)) + { + return IA64; + } + + if (string.Equals(architecture, "arm", StringComparison.OrdinalIgnoreCase)) + { + return Environment.Is64BitProcess ? ARM64 : ARM; + } + + // Fallback if unknown + return architecture; + } /// /// Load the native library with the given filename. @@ -138,21 +126,19 @@ namespace MathNet.Numerics.Providers } // If we have an extra path provided by the user, look there first - var userDir = Control.NativeProviderPath; - if (userDir != null && userDir.Exists && TryLoad(fileName, userDir)) + if (TryLoad(fileName, Control.NativeProviderPath)) { return true; } // Look under the current AppDomain's base directory - if (TryLoad(fileName, new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory))) + if (TryLoad(fileName, AppDomain.CurrentDomain.BaseDirectory)) { return true; } // Look at this assembly's directory - var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - if (!string.IsNullOrEmpty(assemblyDir) && TryLoad(fileName, new DirectoryInfo(assemblyDir))) + if (TryLoad(fileName, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))) { return true; } @@ -166,22 +152,24 @@ namespace MathNet.Numerics.Providers /// and process mode if there is a matching subfolder. /// /// True if the library was successfully loaded or if it has already been loaded. - public static bool TryLoad(string fileName, DirectoryInfo directory) + public static bool TryLoad(string fileName, string directory) { - if (!directory.Exists) + if (!Directory.Exists(directory)) { return false; } + directory = Path.GetFullPath(directory); + // If we have a know architecture, try the matching subdirectory first - var architecture = ArchDirectory; - if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory.FullName, architecture, fileName)))) + var architecture = ArchitectureKey.Value; + if (!string.IsNullOrEmpty(architecture) && TryLoadFile(new FileInfo(Path.Combine(directory, architecture, fileName)))) { return true; } // Otherwise try to load directly from the provided directory - return TryLoadFile(new FileInfo(Path.Combine(directory.FullName, fileName))); + return TryLoadFile(new FileInfo(Path.Combine(directory, fileName))); } /// @@ -193,7 +181,7 @@ namespace MathNet.Numerics.Providers lock (StaticLock) { IntPtr libraryHandle; - if (NativeHandles.TryGetValue(file.Name, out libraryHandle)) + if (NativeHandles.Value.TryGetValue(file.Name, out libraryHandle)) { return true; } @@ -201,7 +189,7 @@ namespace MathNet.Numerics.Providers if (!file.Exists) { // If the library isn't found within an architecture specific folder then return false - // to allow normal P/Invoke searching behaviour when the library is called + // to allow normal P/Invoke searching behavior when the library is called return false; } @@ -216,7 +204,7 @@ namespace MathNet.Numerics.Providers else { LastException = null; - NativeHandles[file.Name] = libraryHandle; + NativeHandles.Value[file.Name] = libraryHandle; } return libraryHandle != IntPtr.Zero;