/// <nodoc /> public void Store(OperationContext context, ShortHash hash, ContentLocationEntry entry) { using (_exchangeLock.AcquireReadLock()) { _cache[hash] = entry; } }
/// <summary> /// Tries to resolve <see cref="MachineLocation"/> by a machine id (<paramref name="machine"/>). /// </summary> public bool TryResolve(MachineId machine, out MachineLocation machineLocation) { using (_lock.AcquireReadLock()) { if (machine.Index < _locationByIdMap.Length) { machineLocation = _locationByIdMap[machine.Index]; return(machineLocation.Data != null); } machineLocation = default; return(false); } }
[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] // allows catching exceptions from unmanaged code public Possible <TResult> Use <TState, TResult>(Func <IBuildXLKeyValueStore, TState, TResult> use, TState state) { using (m_rwl.AcquireReadLock()) { // All RocksDb usages are checked for exceptions and handled according to a user-provided handler. // The handler decides whether the store should be permanently invalidated or not. It also has the // opportunity to do whatever side-effects the user needs. If the store is invalidated, the // invalidation handler is called after the store has been invalidated. // The default policy is to always invalidate the store if an exception happens, as it is the safest // option. if (Disabled) { return(DisposedOrDisabledFailure); } try { return(use(m_store, state)); } catch (Exception ex) { var result = HandleException(ex, out var rethrow); if (rethrow) { throw; } return(result); } } }
protected void TogglePauseChooseWorkerQueue(bool pause, RunnablePip blockedPip = null) { Contract.Requires(pause == (blockedPip != null), "Must specify blocked pip if and only if pausing the choose worker queue"); if (pause) { using (m_chooseWorkerTogglePauseLock.AcquireWriteLock()) { // Compare with the captured sequence number before the pip re-entered the queue // to avoid race conditions where pip cannot acquire worker resources become available then queue is paused // potentially indefinitely (not likely but theoretically possilbe) if (Volatile.Read(ref WorkerEnableSequenceNumber) == blockedPip.ChooseWorkerSequenceNumber) { SetQueueMaxParallelDegree(0); } } } else { using (m_chooseWorkerTogglePauseLock.AcquireReadLock()) { // Update the sequence number. This essentially is called for every increase in resources // and successful acquisition of workers to track changes in resource state that invalidate // decision to pause choose worker queue. Interlocked.Increment(ref WorkerEnableSequenceNumber); // Unpause the queue SetQueueMaxParallelDegree(MaxParallelDegree); } } }
[System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] // allows catching exceptions from unmanaged code public Possible <TResult> Use <TState, TResult>(Func <IBuildXLKeyValueStore, TState, TResult> use, TState state) { using (m_rwl.AcquireReadLock()) { try { if (Disabled) { return(DisposedOrDisabledFailure); } return(use(m_store, state)); } catch (RocksDbSharpException ex) { return(HandleException(ex)); } // The SEHException class handles SEH (structured exception handling) errors that are thrown from unmanaged code, // but that have not been mapped to another .NET Framework exception. The SEHException class also corresponds to the HRESULT E_FAIL (0x80004005). catch (System.Runtime.InteropServices.SEHException ex) { return(HandleException(ex)); } // Provide an opportunity for caller to handle any unknown exception type, including unmanaged ones, then rethrow catch (Exception ex) { HandleException(ex); throw; } } }
public bool TryAcquireCacheLookup(ProcessRunnablePip runnablePip, bool force) { using (EarlyReleaseLock.AcquireReadLock()) { if (!IsAvailable) { return(false); } if (force) { Interlocked.Increment(ref m_acquiredCacheLookupSlots); runnablePip.AcquiredResourceWorker = this; return(true); } // Atomically acquire a cache lookup slot, being sure to not increase above the limit while (true) { int acquiredCacheLookupSlots = AcquiredCacheLookupSlots; if (acquiredCacheLookupSlots < TotalCacheLookupSlots) { if (Interlocked.CompareExchange(ref m_acquiredCacheLookupSlots, acquiredCacheLookupSlots + 1, acquiredCacheLookupSlots) == acquiredCacheLookupSlots) { OnWorkerResourcesChanged(WorkerResource.AvailableCacheLookupSlots, increased: false); runnablePip.AcquiredResourceWorker = this; return(true); } else { // Failed to update value. Retry. } } else { return(false); } } } }
private (JobObject, uint[]) GetJobObjectWithChildProcessIds() { using (m_queryJobDataLock.AcquireReadLock()) { var detouredProcess = m_detouredProcess; if (detouredProcess == null || !detouredProcess.HasStarted || detouredProcess.HasExited || m_disposeStarted) { return(null, null); } var jobObject = detouredProcess.GetJobObject(); if (jobObject == null || !jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds) || childProcessIds.Length == 0)
/// <inheritdoc /> /// <remarks> /// Gets the peak memory usage for the job object associated with the detoured process while the process is active. /// </remarks> public ulong?GetActivePeakMemoryUsage() { using (m_queryJobDataLock.AcquireReadLock()) { var detouredProcess = m_detouredProcess; if (detouredProcess == null || !detouredProcess.HasStarted || detouredProcess.HasExited || m_disposeStarted) { return(null); } return(detouredProcess.GetJobObject()?.GetPeakMemoryUsage()); } }
/// <summary> /// Iterates through the job object processes executing an action for each one. /// </summary> public VisitJobObjectResult TryVisitJobObjectProcesses(Action <SafeProcessHandle, uint> actionForProcess) { Contract.Requires(HasStarted); // Accessing jobObject needs to be protected by m_queryJobDataLock. // After we collected the child process ids, we might dispose the job object and the child process might be invalid. // Acquiring the reader lock will prevent the job object from disposing. using (m_queryJobDataLock.AcquireReadLock()) { var jobObject = GetJobObject(); if (m_killed) { // Terminated before starting the operation return(VisitJobObjectResult.TerminatedBeforeVisitation); } if (!jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds))
/// <inheritdoc /> public ulong?GetActivePeakWorkingSet() { using (m_queryJobDataLock.AcquireReadLock()) { var detouredProcess = m_detouredProcess; if (detouredProcess == null || !detouredProcess.HasStarted || detouredProcess.HasExited || m_disposeStarted) { return(null); } ulong?currentPeakWorkingSet = null; ulong?currentPeakPagefileUsage = null; var jobObject = detouredProcess.GetJobObject(); if (jobObject == null || !jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds) || childProcessIds.Length == 0)
/// <inheritdoc /> public EmptyWorkingSetResult TryEmptyWorkingSet(bool isSuspend) { // Accessing jobObject needs to be protected by m_queryJobDataLock. // After we collected the child process ids, we might dispose the job object and the child process might be invalid. // Acquiring the reader lock will prevent the job object from disposing. using (m_queryJobDataLock.AcquireReadLock()) { (JobObject jobObject, uint[] childProcesses) = GetJobObjectWithChildProcessIds(); if (jobObject == null) { return(EmptyWorkingSetResult.None); } EmptyWorkingSetResult result = EmptyWorkingSetResult.Success; VisitJobObjectProcesses(jobObject, childProcesses, (processHandle, pid) => { if (isSuspend) { bool isSuspendFailed = false; try { isSuspendFailed = !Interop.Windows.Process.Suspend(System.Diagnostics.Process.GetProcessById((int)pid)); } #pragma warning disable ERP022 catch (Exception) { isSuspendFailed = true; } #pragma warning restore ERP022 if (isSuspendFailed) { // If suspending the process fails, no need to continue going through the other processes. result |= EmptyWorkingSetResult.SuspendFailed; } } if (!Interop.Windows.Memory.EmptyWorkingSet(processHandle.DangerousGetHandle())) { result |= EmptyWorkingSetResult.EmptyWorkingSetFailed; } if (EngineEnvironmentSettings.SetMaxWorkingSetToMin) { if (!Interop.Windows.Memory.SetProcessWorkingSetSizeEx( processHandle.DangerousGetHandle(), s_defaultMin, // the default on systems with 4k pages s_defaultMin, Interop.Windows.Memory.WorkingSetSizeFlags.MaxEnable | Interop.Windows.Memory.WorkingSetSizeFlags.MinDisable)) { result |= EmptyWorkingSetResult.SetMaxWorkingSetFailed; } } }); return(result); } }
/// <inheritdoc /> public ulong?GetActivePeakWorkingSet() { using (m_queryJobDataLock.AcquireReadLock()) { var detouredProcess = m_detouredProcess; if (detouredProcess == null || !detouredProcess.HasStarted || detouredProcess.HasExited || m_disposeStarted) { return(null); } ulong?currentPeakWorkingSet = null; ulong?currentPeakPagefileUsage = null; var jobObject = detouredProcess.GetJobObject(); if (jobObject == null || !jobObject.TryGetProcessIds(out uint[] childProcessIds) || childProcessIds.Length == 0) { return(null); } foreach (uint processId in childProcessIds) { using (SafeProcessHandle processHandle = ProcessUtilities.OpenProcess( ProcessSecurityAndAccessRights.PROCESS_QUERY_INFORMATION, false, processId)) { if (processHandle.IsInvalid) { // we are too late: could not open process continue; } if (!jobObject.ContainsProcess(processHandle)) { // we are too late: process id got reused by another process continue; } int exitCode; if (!ProcessUtilities.GetExitCodeProcess(processHandle, out exitCode)) { // we are too late: process id got reused by another process continue; } var memoryUsage = Interop.Dispatch.GetMemoryUsageCounters(processHandle.DangerousGetHandle()); if (memoryUsage != null) { currentPeakWorkingSet = (currentPeakWorkingSet ?? 0) + memoryUsage.PeakWorkingSetSize; currentPeakPagefileUsage = (currentPeakPagefileUsage ?? 0) + memoryUsage.PeakPagefileUsage; } } } m_peakWorkingSet.RegisterSample(currentPeakWorkingSet ?? 0); m_peakPagefileUsage.RegisterSample(currentPeakPagefileUsage ?? 0); return(currentPeakWorkingSet); } }
/// <inheritdoc /> public EmptyWorkingSetResult TryEmptyWorkingSet(bool isSuspend) { // Accessing jobObject needs to be protected by m_queryJobDataLock. // After we collected the child process ids, we might dispose the job object and the child process might be invalid. // Acquiring the reader lock will prevent the job object from disposing. using (m_queryJobDataLock.AcquireReadLock()) { if (!IsDetouredProcessUsable()) { return(EmptyWorkingSetResult.None); } var result = EmptyWorkingSetResult.Success; var suspendSuccess = true; var emptyWorkingSetSuccess = true; var visited = m_detouredProcess.TryVisitJobObjectProcesses((processHandle, pid) => { emptyWorkingSetSuccess &= Interop.Windows.Memory.EmptyWorkingSet(processHandle.DangerousGetHandle()); if (isSuspend) { try { suspendSuccess &= Interop.Windows.Process.Suspend(System.Diagnostics.Process.GetProcessById((int)pid)); } catch (Exception e) { suspendSuccess = false; Tracing.Logger.Log.ResumeOrSuspendException(m_loggingContext, "Suspend", e.ToStringDemystified()); } } }); if (!visited) { // Couldn't visit result |= EmptyWorkingSetResult.EmptyWorkingSetFailed; if (isSuspend) { result |= EmptyWorkingSetResult.SuspendFailed; } return(result); } if (!emptyWorkingSetSuccess) { result |= EmptyWorkingSetResult.EmptyWorkingSetFailed; } if (isSuspend) { if (suspendSuccess) { m_detouredProcess.OnSuspensionStart(); } else { result |= EmptyWorkingSetResult.SuspendFailed; } } return(result); } }