public bool Start(uint frequencyInMsec, uint durationInMsec, ISampleSink sampleSink, INativeMethods nativeMethods) { _shutdownEvent.Reset(); //atomic compare and set - if _workerRunning was a zero, it's now a 1 and create worker will be true bool createWorker = 0 == Interlocked.CompareExchange(ref _workerRunning, 1, 0); if (createWorker) { _samplingWorker = new Thread(() => InternalPolling_WaitCallback(frequencyInMsec, durationInMsec, sampleSink, nativeMethods)) { IsBackground = true }; _samplingWorker.Start(); } //return whether or not we created a session return(createWorker); }
/// <summary> /// Polls for profiled threads. /// </summary> private void InternalPolling_WaitCallback(uint frequencyInMsec, uint durationInMsec, ISampleSink sampleSink, INativeMethods nativeMethods) { int samples = 0; var lastTickOfSamplingPeriod = DateTime.UtcNow.AddMilliseconds(durationInMsec).Ticks; try { while (!_shutdownEvent.Wait((int)frequencyInMsec)) { if (DateTime.UtcNow.Ticks > lastTickOfSamplingPeriod) { _shutdownEvent.Set(); Log.Debug("InternalPolling_WaitCallback: Duration Elapsed -- Stopping Sampler"); break; } try { var threadSnapshots = GetProfileWithRelease(out int result); if (result >= 0) { ++samples; sampleSink.SampleAcquired(threadSnapshots); } else { Log.Error($"Thread Profile sampling failed. ({result:X})"); } } catch (Exception ex) { Log.Error(ex); } } } catch (Exception ex) { Log.Error(ex); } finally { Log.Info($"samples ({samples})"); sampleSink.SamplingComplete(); nativeMethods.ShutdownNativeThreadProfiler(); _workerRunning = 0; } }