/// <summary> /// Removes thread exit callback that has been set with <see cref="SetThreadExitCallback"/>. /// NOTE: callback may be called as a result of this method call on some platforms. /// </summary> /// <param name="callbackId">Callback id returned from <see cref="SetThreadExitCallback"/>.</param> public static void RemoveThreadExitCallback(int callbackId) { if (Os.IsWindows) { var res = NativeMethodsWindows.FlsFree(callbackId); if (!res) { throw new InvalidOperationException("FlsFree failed: " + Marshal.GetLastWin32Error()); } } else if (Os.IsMacOs) { var res = NativeMethodsMacOs.pthread_key_delete(callbackId); NativeMethodsLinux.CheckResult(res); } else if (Os.IsLinux) { var res = Os.IsMono ? NativeMethodsMono.pthread_key_delete(callbackId) : NativeMethodsLinux.pthread_key_delete(callbackId); NativeMethodsLinux.CheckResult(res); } else { throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion); } }
/// <summary> /// Loads specified DLL. /// </summary> /// <returns>Null when successful; error message otherwise.</returns> public static string Load(string dllPath) { if (Os.IsWindows) { return(NativeMethodsWindows.LoadLibrary(dllPath) == IntPtr.Zero ? FormatWin32Error(Marshal.GetLastWin32Error()) ?? "Unknown error" : null); } if (Os.IsLinux) { if (Os.IsMono) { return(NativeMethodsMono.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero ? GetErrorText(NativeMethodsMono.dlerror()) : null); } if (Os.IsNetCore) { return(NativeMethodsCore.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero ? GetErrorText(NativeMethodsCore.dlerror()) : null); } return(NativeMethodsLinux.dlopen(dllPath, RtldGlobal | RtldLazy) == IntPtr.Zero ? GetErrorText(NativeMethodsLinux.dlerror()) : null); } throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion); }
/// <summary> /// Enables thread exit event for current thread. /// </summary> public static void EnableCurrentThreadExitEvent(int callbackId, IntPtr threadLocalValue) { Debug.Assert(threadLocalValue != IntPtr.Zero); // Store any value so that destructor callback is fired. if (Os.IsWindows) { var res = NativeMethodsWindows.FlsSetValue(callbackId, threadLocalValue); if (!res) { throw new InvalidOperationException("FlsSetValue failed: " + Marshal.GetLastWin32Error()); } } else if (Os.IsMacOs) { var res = NativeMethodsMacOs.pthread_setspecific(callbackId, threadLocalValue); NativeMethodsLinux.CheckResult(res); } else if (Os.IsLinux) { var res = Os.IsMono ? NativeMethodsMono.pthread_setspecific(callbackId, threadLocalValue) : NativeMethodsLinux.pthread_setspecific(callbackId, threadLocalValue); NativeMethodsLinux.CheckResult(res); } else { throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion); } }
/// <summary> /// Loads specified DLL. /// </summary> /// <returns>Library handle and error message.</returns> public static KeyValuePair <IntPtr, string> Load(string dllPath) { if (Os.IsWindows) { var ptr = NativeMethodsWindows.LoadLibrary(dllPath); return(new KeyValuePair <IntPtr, string>(ptr, ptr == IntPtr.Zero ? FormatWin32Error(Marshal.GetLastWin32Error()) ?? "Unknown error" : null)); } if (Os.IsMacOs) { var ptr = NativeMethodsMacOs.dlopen(dllPath, RtldGlobal | RtldLazy); return(new KeyValuePair <IntPtr, string>(ptr, ptr == IntPtr.Zero ? GetErrorText(NativeMethodsMacOs.dlerror()) : null)); } if (Os.IsLinux) { if (Os.IsMono) { var ptr = NativeMethodsMono.dlopen(dllPath, RtldGlobal | RtldLazy); return(new KeyValuePair <IntPtr, string>(ptr, ptr == IntPtr.Zero ? GetErrorText(NativeMethodsMono.dlerror()) : null)); } if (Os.IsNetCore) { var ptr = NativeMethodsCore.dlopen(dllPath, RtldGlobal | RtldLazy); return(new KeyValuePair <IntPtr, string>(ptr, ptr == IntPtr.Zero ? GetErrorText(NativeMethodsCore.dlerror()) : null)); } var lptr = NativeMethodsLinux.dlopen(dllPath, RtldGlobal | RtldLazy); return(new KeyValuePair <IntPtr, string>(lptr, lptr == IntPtr.Zero ? GetErrorText(NativeMethodsLinux.dlerror()) : null)); } throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion); }
/// <summary> /// Sets the thread exit callback, and returns an id to pass to <see cref="EnableCurrentThreadExitEvent"/>. /// </summary> /// <param name="callbackPtr"> /// Pointer to a callback function that matches <see cref="ThreadExitCallback"/>. /// Get this pointer with <see cref="Marshal.GetFunctionPointerForDelegate"/> method; make sure that passed /// delegate is not garbage-collected (put it to a static property, for example). /// </param> /// <returns>Callback ID.</returns> public static unsafe int SetThreadExitCallback(IntPtr callbackPtr) { if (callbackPtr == IntPtr.Zero) { throw new ArgumentException("Should not be Zero", nameof(callbackPtr)); } if (Os.IsWindows) { var res = NativeMethodsWindows.FlsAlloc(callbackPtr); if (res == NativeMethodsWindows.FLS_OUT_OF_INDEXES) { throw new InvalidOperationException("FlsAlloc failed: " + Marshal.GetLastWin32Error()); } return(res); } if (Os.IsMacOs) { int tlsIndex; var res = NativeMethodsMacOs.pthread_key_create(new IntPtr(&tlsIndex), callbackPtr); NativeMethodsLinux.CheckResult(res); return(tlsIndex); } if (Os.IsLinux) { int tlsIndex; var res = NativeMethodsLinux.pthread_key_create(new IntPtr(&tlsIndex), callbackPtr); NativeMethodsLinux.CheckResult(res); return(tlsIndex); } throw new InvalidOperationException("Unsupported OS: " + Environment.OSVersion); }