internal RegisteredWaitHandle(SafeWaitHandle waitHandle, _ThreadPoolWaitOrTimerCallback callbackHelper, uint millisecondsTimeout, bool repeating) { _lock = new Lock(); // Protect the handle from closing while we are waiting on it (VSWhidbey 285642) waitHandle.DangerousAddRef(); _waitHandle = waitHandle; _callbackHelper = callbackHelper; _millisecondsTimeout = millisecondsTimeout; _repeating = repeating; // Allocate _gcHandle and _tpWait as the last step and make sure they are never leaked _gcHandle = GCHandle.Alloc(this); _tpWait = Interop.mincore.CreateThreadpoolWait( AddrofIntrinsics.AddrOf <Interop.mincore.WaitCallback>(RegisteredWaitCallback), (IntPtr)_gcHandle, IntPtr.Zero); if (_tpWait == IntPtr.Zero) { _gcHandle.Free(); throw new OutOfMemoryException(); } }
public static ThreadPoolBoundHandle BindHandle(SafeHandle handle) { if (handle == null) { throw new ArgumentNullException(nameof(handle)); } if (handle.IsClosed || handle.IsInvalid) { throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle)); } IntPtr callback = AddrofIntrinsics.AddrOf <Interop.NativeIoCompletionCallback>(OnNativeIOCompleted); SafeThreadPoolIOHandle threadPoolHandle = Interop.mincore.CreateThreadpoolIo(handle, callback, IntPtr.Zero, IntPtr.Zero); if (threadPoolHandle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == Interop.Errors.ERROR_INVALID_HANDLE) // Bad handle { throw new ArgumentException(SR.Argument_InvalidHandle, nameof(handle)); } if (errorCode == Interop.Errors.ERROR_INVALID_PARAMETER) // Handle already bound or sync handle { throw new ArgumentException(SR.Argument_AlreadyBoundOrSyncHandle, nameof(handle)); } throw Win32Marshal.GetExceptionForWin32Error(errorCode); } return(new ThreadPoolBoundHandle(handle, threadPoolHandle)); }
// Enumerate all system cultures and then try to find out which culture has // region name match the requested region name private static CultureData GetCultureDataFromRegionName(String regionName) { Debug.Assert(regionName != null); const uint LOCALE_SUPPLEMENTAL = 0x00000002; const uint LOCALE_SPECIFICDATA = 0x00000020; EnumLocaleData context = new EnumLocaleData(); context.cultureName = null; context.regionName = regionName; GCHandle contextHandle = GCHandle.Alloc(context); try { IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, uint, IntPtr, Interop.BOOL> >(EnumSystemLocalesProc); Interop.mincore.EnumSystemLocalesEx(callback, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, (IntPtr)contextHandle, IntPtr.Zero); } finally { contextHandle.Free(); } if (context.cultureName != null) { // we got a matched culture return(GetCultureData(context.cultureName, true)); } return(null); }
private static CultureInfo[] EnumCultures(CultureTypes types) { Debug.Assert(!GlobalizationMode.Invariant); uint flags = 0; #pragma warning disable 618 if ((types & (CultureTypes.FrameworkCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.ReplacementCultures)) != 0) { flags |= Interop.Kernel32.LOCALE_NEUTRALDATA | Interop.Kernel32.LOCALE_SPECIFICDATA; } #pragma warning restore 618 if ((types & CultureTypes.NeutralCultures) != 0) { flags |= Interop.Kernel32.LOCALE_NEUTRALDATA; } if ((types & CultureTypes.SpecificCultures) != 0) { flags |= Interop.Kernel32.LOCALE_SPECIFICDATA; } if ((types & CultureTypes.UserCustomCulture) != 0) { flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; } if ((types & CultureTypes.ReplacementCultures) != 0) { flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; } EnumData context = new EnumData(); context.strings = new StringList(); GCHandle contextHandle = GCHandle.Alloc(context); try { #if CORECLR Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, (IntPtr)contextHandle, IntPtr.Zero); #else IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, uint, IntPtr, Interop.BOOL> >(EnumAllSystemLocalesProc); Interop.Kernel32.EnumSystemLocalesEx(callback, flags, (IntPtr)contextHandle, IntPtr.Zero); #endif } finally { contextHandle.Free(); } CultureInfo [] cultures = new CultureInfo[context.strings.Count]; for (int i = 0; i < cultures.Length; i++) { cultures[i] = new CultureInfo(context.strings[i]); } return(cultures); }
private static unsafe String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride) { const uint LOCALE_SSHORTTIME = 0x00000079; const uint LOCALE_STIMEFORMAT = 0x00001003; EnumData data = new EnumData(); data.strings = new StringList(); GCHandle dataHandle = GCHandle.Alloc(data); try { #if CORECLR Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, (IntPtr)dataHandle); #else // Now call the enumeration API. Work is done by our callback function IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, IntPtr, Interop.BOOL> >(EnumTimeCallback); Interop.Kernel32.EnumTimeFormatsEx(callback, localeName, (uint)dwFlags, (IntPtr)dataHandle); #endif } finally { dataHandle.Free(); } if (data.strings.Count > 0) { // Now we need to allocate our stringarray and populate it string[] results = data.strings.ToArray(); if (!useUserOverride && data.strings.Count > 1) { // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override // The override is the first entry if it is overriden. // We can check if we have overrides by checking the GetLocaleInfo with no override // If we do have an override, we don't know if it is a user defined override or if the // user has just selected one of the predefined formats so we can't just remove it // but we can move it down. uint lcType = (dwFlags == TIME_NOSECONDS) ? LOCALE_SSHORTTIME : LOCALE_STIMEFORMAT; string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride); if (timeFormatNoUserOverride != "") { string firstTimeFormat = results[0]; if (timeFormatNoUserOverride != firstTimeFormat) { results[0] = results[1]; results[1] = firstTimeFormat; } } } return(results); } return(null); }
internal static void QueueLongRunningWork(Action callback) { GCHandle gcHandle = GCHandle.Alloc(callback); if (!Interop.Sys.RuntimeThread_CreateThread(IntPtr.Zero /*use default stack size*/, AddrofIntrinsics.AddrOf <Interop.Sys.ThreadProc>(LongRunningWorkCallback), GCHandle.ToIntPtr(gcHandle))) { gcHandle.Free(); throw new OutOfMemoryException(); } }
// Call native side to figure out which calendars are allowed internal static int GetCalendars(String localeName, bool useUserOverride, CalendarId[] calendars) { Debug.Assert(!GlobalizationMode.Invariant); EnumCalendarsData data = new EnumCalendarsData(); data.userOverride = 0; data.calendars = new IntList(); // First call GetLocaleInfo if necessary if (useUserOverride) { // They want user overrides, see if the user calendar matches the input calendar int userCalendar = CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If we got a default, then use it as the first calendar if (userCalendar != 0) { data.userOverride = userCalendar; data.calendars.Add(userCalendar); } } GCHandle contextHandle = GCHandle.Alloc(data); try { // Now call the enumeration API. Work is done by our callback function #if CORECLR Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle); #else IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, uint, IntPtr, IntPtr, Interop.BOOL> >(EnumCalendarsCallback); Interop.Kernel32.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle); #endif } finally { contextHandle.Free(); } // Copy to the output array for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++) { calendars[i] = (CalendarId)data.calendars[i]; } // Now we have a list of data, return the count return(data.calendars.Count); }
internal static unsafe void QueueLongRunningWork(Action callback) { var environ = default(Interop.mincore.TP_CALLBACK_ENVIRON); environ.Initialize(); environ.SetLongFunction(); IntPtr nativeCallback = AddrofIntrinsics.AddrOf <Interop.mincore.SimpleCallback>(LongRunningWorkCallback); GCHandle gcHandle = GCHandle.Alloc(callback); if (!Interop.mincore.TrySubmitThreadpoolCallback(nativeCallback, GCHandle.ToIntPtr(gcHandle), &environ)) { gcHandle.Free(); throw new OutOfMemoryException(); } }
private bool CreateThread(GCHandle thisThreadHandle) { // Create the Stop event before starting the thread to make sure // it is ready to be signaled at thread shutdown time. // This also avoids OOM after creating the thread. _stopped = new ManualResetEvent(false); if (!Interop.Sys.RuntimeThread_CreateThread((IntPtr)_maxStackSize, AddrofIntrinsics.AddrOf <Interop.Sys.ThreadProc>(ThreadEntryPoint), (IntPtr)thisThreadHandle)) { return(false); } // CoreCLR ignores OS errors while setting the priority, so do we SetPriorityLive(_priority); return(true); }
private unsafe void SetTimer(uint actualDuration) { if (_nativeTimer == IntPtr.Zero) { IntPtr nativeCallback = AddrofIntrinsics.AddrOf <Interop.mincore.TimerCallback>(TimerCallback); _nativeTimer = Interop.mincore.CreateThreadpoolTimer(nativeCallback, IntPtr.Zero, IntPtr.Zero); if (_nativeTimer == IntPtr.Zero) { throw new OutOfMemoryException(); } } // Negative time indicates the amount of time to wait relative to the current time, in 100 nanosecond units long dueTime = -10000 * (long)actualDuration; Interop.mincore.SetThreadpoolTimer(_nativeTimer, &dueTime, 0, 0); }
/// <summary> /// This method is called to request a new thread pool worker to handle pending work. /// </summary> internal static void QueueDispatch() { // For simplicity of the state management, we pre-create all thread pool workers on the first // request and then use the semaphore to release threads as new requests come in. if ((s_workerCount == 0) && Interlocked.Exchange(ref s_workerCount, MaxThreadCount) == 0) { for (int i = 0; i < MaxThreadCount; i++) { if (!Interop.Sys.RuntimeThread_CreateThread(IntPtr.Zero /*use default stack size*/, AddrofIntrinsics.AddrOf <Interop.Sys.ThreadProc>(ThreadPoolDispatchCallback), IntPtr.Zero)) { throw new OutOfMemoryException(); } } } // Release one thread to handle the new request s_semaphore.Release(1); }
// Call native side to figure out which calendars are allowed internal static int GetCalendars(String localeName, bool useUserOverride, CalendarId[] calendars) { EnumCalendarsData data = new EnumCalendarsData(); data.userOverride = 0; data.calendars = new LowLevelList <int>(); // First call GetLocaleInfo if necessary if (useUserOverride) { // They want user overrides, see if the user calendar matches the input calendar int userCalendar = Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If we got a default, then use it as the first calendar if (userCalendar != 0) { data.userOverride = userCalendar; data.calendars.Add(userCalendar); } } GCHandle contextHandle = GCHandle.Alloc(data); try { // Now call the enumeration API. Work is done by our callback function IntPtr callback = AddrofIntrinsics.AddrOf <Interop.mincore.EnumCalendarInfoProcExEx>(EnumCalendarsCallback); Interop.mincore.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle); } finally { contextHandle.Free(); } // Copy to the output array for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++) { calendars[i] = (CalendarId)data.calendars[i]; } // Now we have a list of data, return the count return(data.calendars.Count); }
internal static void QueueDispatch() { if (s_work == IntPtr.Zero) { IntPtr nativeCallback = AddrofIntrinsics.AddrOf <Interop.mincore.WorkCallback>(DispatchCallback); IntPtr work = Interop.mincore.CreateThreadpoolWork(nativeCallback, IntPtr.Zero, IntPtr.Zero); if (work == IntPtr.Zero) { throw new OutOfMemoryException(); } if (Interlocked.CompareExchange(ref s_work, work, IntPtr.Zero) != IntPtr.Zero) { Interop.mincore.CloseThreadpoolWork(work); } } Interop.mincore.SubmitThreadpoolWork(s_work); }
private bool CreateThread(GCHandle thisThreadHandle) { const int AllocationGranularity = 0x10000; // 64 KiB int stackSize = _maxStackSize; if ((0 < stackSize) && (stackSize < AllocationGranularity)) { // If StackSizeParamIsAReservation flag is set and the reserve size specified by CreateThread's // dwStackSize parameter is less than or equal to the initially committed stack size specified in // the executable header, the reserve size will be set to the initially committed size rounded up // to the nearest multiple of 1 MiB. In all cases the reserve size is rounded up to the nearest // multiple of the system's allocation granularity (typically 64 KiB). // // To prevent overreservation of stack memory for small stackSize values, we increase stackSize to // the allocation granularity. We assume that the SizeOfStackCommit field of IMAGE_OPTIONAL_HEADER // is strictly smaller than the allocation granularity (the field's default value is 4 KiB); // otherwise, at least 1 MiB of memory will be reserved. Note that the desktop CLR increases // stackSize to 256 KiB if it is smaller than that. stackSize = AllocationGranularity; } uint threadId; _osHandle = Interop.Kernel32.CreateThread(IntPtr.Zero, (IntPtr)stackSize, AddrofIntrinsics.AddrOf <Interop.Kernel32.ThreadProc>(ThreadEntryPoint), (IntPtr)thisThreadHandle, Interop.Kernel32.CREATE_SUSPENDED | Interop.Kernel32.STACK_SIZE_PARAM_IS_A_RESERVATION, out threadId); if (_osHandle.IsInvalid) { return(false); } // CoreCLR ignores OS errors while setting the priority, so do we SetPriorityLive(_priority); Interop.Kernel32.ResumeThread(_osHandle); return(true); }
private void StartCore(object parameter) { using (LockHolder.Hold(_lock)) { if (!GetThreadStateBit(ThreadState.Unstarted)) { throw new ThreadStateException(SR.ThreadState_AlreadyStarted); } // TODO: OOM hardening, _maxStackSize GCHandle threadHandle = GCHandle.Alloc(this); _threadStartArg = parameter; try { uint threadId; _osHandle = new SafeWaitHandle(Interop.mincore.CreateThread(IntPtr.Zero, IntPtr.Zero, AddrofIntrinsics.AddrOf <Interop.mincore.ThreadProc>(StartThread), (IntPtr)threadHandle, 0, out threadId), ownsHandle: true); // Ignore errors (as in CoreCLR) SetPriority(_priority); // Wait until the new thread is started (as in CoreCLR) while (GetThreadStateBit(ThreadState.Unstarted)) { Yield(); } } finally { if (_osHandle == null) { threadHandle.Free(); _threadStartArg = null; } } } }
private void StartCore(object parameter) { using (LockHolder.Hold(_lock)) { if (!GetThreadStateBit(ThreadState.Unstarted)) { throw new ThreadStateException(SR.ThreadState_AlreadyStarted); } const int AllocationGranularity = (int)0x10000; // 64k int stackSize = _maxStackSize; if ((0 < stackSize) && (stackSize < AllocationGranularity)) { // If StackSizeParamIsAReservation flag is set and the reserve size specified by CreateThread's // dwStackSize parameter is less than or equal to the initially committed stack size specified in // the executable header, the reserve size will be set to the initially committed size rounded up // to the nearest multiple of 1 MiB. In all cases the reserve size is rounded up to the nearest // multiple of the system's allocation granularity (typically 64 KiB). // // To prevent overreservation of stack memory for small stackSize values, we increase stackSize to // the allocation granularity. We assume that the SizeOfStackCommit field of IMAGE_OPTIONAL_HEADER // is strictly smaller than the allocation granularity (the field's default value is 4 KiB); // otherwise, at least 1 MiB of memory will be reserved. Note that the desktop CLR increases // stackSize to 256 KiB if it is smaller than that. stackSize = AllocationGranularity; } bool waitingForThreadStart = false; GCHandle threadHandle = GCHandle.Alloc(this); _threadStartArg = parameter; uint threadId; try { _osHandle = Interop.mincore.CreateThread(IntPtr.Zero, (IntPtr)stackSize, AddrofIntrinsics.AddrOf <Interop.mincore.ThreadProc>(StartThread), (IntPtr)threadHandle, (uint)(Interop.Constants.CreateSuspended | Interop.Constants.StackSizeParamIsAReservation), out threadId); // CoreCLR ignores OS errors while setting the priority, so do we SetPriority(_priority); Interop.mincore.ResumeThread(_osHandle); // Skip cleanup if any asynchronous exception happens while waiting for the thread start waitingForThreadStart = true; // Wait until the new thread either dies or reports itself as started while (GetThreadStateBit(ThreadState.Unstarted) && !HasFinishedExecution()) { Yield(); } waitingForThreadStart = false; } finally { Debug.Assert(!waitingForThreadStart, "Leaked threadHandle"); if (!waitingForThreadStart) { threadHandle.Free(); _threadStartArg = null; } } if (GetThreadStateBit(ThreadState.Unstarted)) { // Lack of memory is the only expected reason for thread creation failure throw new ThreadStartException(new OutOfMemoryException()); } } }
private void PlatformSpecificInitialize() { _waitInfo = new WaitSubsystem.ThreadWaitInfo(this); RuntimeImports.RhSetThreadExitCallback(AddrofIntrinsics.AddrOf <Action>(OnThreadExit)); }
private void PlatformSpecificInitialize() { RuntimeImports.RhSetThreadExitCallback(AddrofIntrinsics.AddrOf <Action>(OnThreadExit)); }
private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[] data) { EnumData context = new EnumData(); context.userOverride = null; context.strings = new StringList(); // First call GetLocaleInfo if necessary if (((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0)) && // Get user locale, see if it matches localeName. // Note that they should match exactly, including letter case GetUserDefaultLocaleName() == localeName) { // They want user overrides, see if the user calendar matches the input calendar CalendarId userCalendar = (CalendarId)CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); // If the calendars were the same, see if the locales were the same if (userCalendar == calendar) { // They matched, get the user override since locale & calendar match string res = CultureData.GetLocaleInfoEx(localeName, lcType); // if it succeeded remember the override for the later callers if (res != "") { // Remember this was the override (so we can look for duplicates later in the enum function) context.userOverride = res; // Add to the result strings. context.strings.Add(res); } } } GCHandle contextHandle = GCHandle.Alloc(context); try { #if CORECLR Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle); #else // Now call the enumeration API. Work is done by our callback function IntPtr callback = AddrofIntrinsics.AddrOf <Func <IntPtr, uint, IntPtr, IntPtr, Interop.BOOL> >(EnumCalendarInfoCallback); Interop.Kernel32.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle); #endif // CORECLR } finally { contextHandle.Free(); } // Now we have a list of data, fail if we didn't find anything. if (context.strings.Count == 0) { data = null; return(false); } string[] output = context.strings.ToArray(); if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING) { // Eras are enumerated backwards. (oldest era name first, but // Japanese calendar has newest era first in array, and is only // calendar with multiple eras) Array.Reverse(output, 0, output.Length); } data = output; return(true); }