public void TestClipSetValid() { AtemMockServerWrapper.Each(_output, _pool, SetValidCommandHandler, DeviceTestCases.MediaPlayerClips, helper => { for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); IBMDSwitcherClip clip = GetClip(helper, index); string name = Guid.NewGuid().ToString(); uint frameCount = Randomiser.RangeInt(5) + 3; var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); var clipState = stateBefore.MediaPool.Clips[(int)index]; clipState.IsUsed = true; clipState.Name = name; clipState.FrameCount = frameCount; helper.SendAndWaitForChange(stateBefore, () => { clip.SetValid(name, frameCount); }); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
public void TestLockAndUnlock() { AtemMockServerWrapper.Each(_output, _pool, UploadJobWorker.LockCommandHandler, DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; int clipCount = helper.Helper.BuildLibState().MediaPool.Clips.Count; for (int index = 0; index < clipCount; index++) { IBMDSwitcherClip clip = GetClip(helper, (uint)index); AtemState stateBefore = helper.Helper.BuildLibState(); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); helper.Helper.CheckStateChanges(stateBefore); uint timeBefore = helper.Server.CurrentTime; helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); // It should have sent a response, but we dont expect any comparable data Assert.NotEqual(timeBefore, helper.Server.CurrentTime); helper.Helper.CheckStateChanges(stateBefore); } }); }
public void TestLockAndUnlock() { AtemMockServerWrapper.Each(_output, _pool, UploadJobWorker.LockCommandHandler, DeviceTestCases.MediaPlayer, helper => { IBMDSwitcherStills stills = GetStillsPool(helper); AtemState stateBefore = helper.Helper.BuildLibState(); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { stills.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); helper.Helper.CheckStateChanges(stateBefore); uint timeBefore = helper.Server.CurrentTime; helper.SendAndWaitForChange(stateBefore, () => { stills.Unlock(cb); }); // It should have sent a response, but we dont expect any comparable data Assert.NotEqual(timeBefore, helper.Server.CurrentTime); helper.Helper.CheckStateChanges(stateBefore); }); }
public void TestAudioUpload() { UploadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; var pidCmd = helper.Server.GetParsedDataDump().OfType <ProductIdentifierCommand>().Single(); IBMDSwitcherMediaPool pool = GetMediaPool(helper); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); IBMDSwitcherClip clip = GetClip(helper, index); uint sampleCount = 10000; string name = Guid.NewGuid().ToString(); worker = new UploadJobWorker(sampleCount * 4, _output, index + 1, 0, DataTransferUploadRequestCommand.TransferMode.Write2, false); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); byte[] bytes = MediaPoolUtil.RandomFrame(sampleCount); pool.CreateAudio((uint)bytes.Length, out IBMDSwitcherAudio frame); MediaPoolUtil.FillSdkAudio(frame, bytes); var clipState = stateBefore.MediaPool.Clips[(int)index]; clipState.Audio.IsUsed = true; clipState.Audio.Name = name; var uploadCb = new TransferCallback(); clip.AddCallback(uploadCb); clip.UploadAudio(name, frame); helper.HandleUntil(uploadCb.Wait, 5000); Assert.True(uploadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, uploadCb.Result); // TODO - this needs a better rule that can be properly exposed via the lib byte[] flippedBytes = pidCmd.Model >= ModelId.PS4K ? MediaPoolUtil.FlipAudio(bytes) : bytes; Assert.Equal(BitConverter.ToString(flippedBytes), BitConverter.ToString(worker.Buffer)); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
public void WithLock(LockCallback callback) { IntPtr pixels; int pitch; Lock(out pixels, out pitch); callback(pixels, pitch); Unlock(); }
private void DoUpload(int iterations, int timeout, Func <uint, uint, byte[]> frameBytes) { UploadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayer, helper => { helper.DisposeSdkClient = true; IBMDSwitcherMediaPool pool = GetMediaPool(helper); IBMDSwitcherStills stills = GetStillsPool(helper); for (int i = 0; i < iterations; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); Tuple <uint, uint> resolution = stateBefore.Settings.VideoMode.GetResolution().GetSize(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Stills.Count); string name = Guid.NewGuid().ToString(); worker = new UploadJobWorker(resolution.Item1 * resolution.Item2 * 4, _output, (uint)MediaPoolFileType.Still, index, DataTransferUploadRequestCommand.TransferMode.Write); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { stills.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); pool.CreateFrame(_BMDSwitcherPixelFormat.bmdSwitcherPixelFormat10BitYUVA, resolution.Item1, resolution.Item2, out IBMDSwitcherFrame frame); byte[] bytes = frameBytes(resolution.Item1, resolution.Item2); if (bytes.Length > 0) { MediaPoolUtil.FillSdkFrame(frame, bytes); } var stillState = stateBefore.MediaPool.Stills[(int)index]; stillState.IsUsed = true; stillState.Filename = name; var uploadCb = new TransferCallback(); stills.AddCallback(uploadCb); stills.Upload(index, name, frame); helper.HandleUntil(uploadCb.Wait, timeout); Assert.True(uploadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, uploadCb.Result); Assert.Equal(BitConverter.ToString(bytes), BitConverter.ToString(worker.Buffer)); helper.SendAndWaitForChange(stateBefore, () => { stills.Unlock(cb); }); } }); }
private async Task runTest(int count) { var nodes = new WriteLock[count]; var lockCallback = new LockCallback(); for (int i = 0; i < count; i++) { ZooKeeper keeper = await createClient(); WriteLock leader = new WriteLock(keeper, "/test", null); leader.setLockListener(lockCallback); nodes[i] = leader; await leader.Lock(); } // lets wait for any previous leaders to die and one of our new // nodes to become the new leader Assert.assertTrue(await lockCallback.TaskCompletionSource.Task.WithTimeout(30 * 1000)); WriteLock first = nodes[0]; dumpNodes(nodes, count); // lets assert that the first election is the leader Assert.assertTrue("The first znode should be the leader " + first.Id, first.Owner); for (int i = 1; i < count; i++) { WriteLock node = nodes[i]; Assert.assertFalse("Node should not be the leader " + node.Id, node.Owner); } if (count > 1) { LOG.debug("Now killing the leader"); // now lets kill the leader lockCallback.TaskCompletionSource = new TaskCompletionSource <bool>(); await first.unlock(); Assert.assertTrue(await lockCallback.TaskCompletionSource.Task.WithTimeout(30 * 1000)); WriteLock second = nodes[1]; dumpNodes(nodes, count); // lets assert that the first election is the leader Assert.assertTrue("The second znode should be the leader " + second.Id, second.Owner); for (int i = 2; i < count; i++) { WriteLock node = nodes[i]; Assert.assertFalse("Node should not be the leader " + node.Id, node.Owner); } } }
private void Lock(Control target, bool enable) { if (this.InvokeRequired) { LockCallback lockCallback = new LockCallback(Lock); this.Invoke(lockCallback, target, enable); } else { target.Enabled = enable; } }
public void TestClipFrameUpload() { UploadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; IBMDSwitcherMediaPool pool = GetMediaPool(helper); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); Tuple <uint, uint> resolution = stateBefore.Settings.VideoMode.GetResolution().GetSize(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); uint frameIndex = Randomiser.RangeInt(stateBefore.MediaPool.Clips[(int)index].MaxFrames); IBMDSwitcherClip clip = GetClip(helper, index); worker = new UploadJobWorker(resolution.Item1 * resolution.Item2 * 4, _output, index + 1, frameIndex, DataTransferUploadRequestCommand.TransferMode.Write); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); pool.CreateFrame(_BMDSwitcherPixelFormat.bmdSwitcherPixelFormat10BitYUVA, resolution.Item1, resolution.Item2, out IBMDSwitcherFrame frame); byte[] bytes = MediaPoolUtil.SolidColour(resolution.Item1 * resolution.Item2, 100, 0, 0, 255); MediaPoolUtil.FillSdkFrame(frame, bytes); var clipState = stateBefore.MediaPool.Clips[(int)index]; clipState.Frames[(int)frameIndex].IsUsed = true; //clipState.Audio.Name = name; var uploadCb = new TransferCallback(); clip.AddCallback(uploadCb); clip.UploadFrame(frameIndex, frame); helper.HandleUntil(uploadCb.Wait, 5000); Assert.True(uploadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, uploadCb.Result); Assert.Equal(BitConverter.ToString(bytes), BitConverter.ToString(worker.Buffer)); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
public void TestAbortingAudioUpload() { AbortedUploadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; IBMDSwitcherMediaPool pool = GetMediaPool(helper); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); IBMDSwitcherClip clip = GetClip(helper, index); uint sampleCount = 10000; string name = Guid.NewGuid().ToString(); worker = new AbortedUploadJobWorker(_output); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); byte[] bytes = MediaPoolUtil.RandomFrame(sampleCount); pool.CreateAudio((uint)bytes.Length, out IBMDSwitcherAudio frame); MediaPoolUtil.FillSdkAudio(frame, bytes); var uploadCb = new TransferCallback(); clip.AddCallback(uploadCb); clip.UploadAudio(name, frame); // Short bit of work before the abort helper.HandleUntil(uploadCb.Wait, 1000); clip.CancelTransfer(); helper.HandleUntil(uploadCb.Wait, 1000); Assert.True(uploadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCancelled, uploadCb.Result); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
static public void SyncStart(string message, LockCallback callback, object state) { if (SyncLockedGUIForm == null) { SyncLockedGUIForm = new FreeCL.Forms.LockedGuiForm(); SyncLockedGUIForm.Init(); } SyncLockedGUIForm.savedCallBack = callback; SyncLockedGUIForm.savedState = state; SyncLockedGUIForm.tCallback.Enabled = true; SyncLockedGUIForm.StartWaiting(message); Application.DoEvents(); }
public void TestAbortingStillUpload() { AbortedUploadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerStillTransfer, helper => { helper.DisposeSdkClient = true; IBMDSwitcherMediaPool pool = GetMediaPool(helper); IBMDSwitcherStills stills = GetStillsPool(helper); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); Tuple <uint, uint> resolution = stateBefore.Settings.VideoMode.GetResolution().GetSize(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Stills.Count); string name = Guid.NewGuid().ToString(); worker = new AbortedUploadJobWorker(_output); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { stills.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); pool.CreateFrame(_BMDSwitcherPixelFormat.bmdSwitcherPixelFormat10BitYUVA, resolution.Item1, resolution.Item2, out IBMDSwitcherFrame frame); MediaPoolUtil.FillSdkFrame(frame, MediaPoolUtil.RandomFrame(resolution.Item1 * resolution.Item2)); var uploadCb = new TransferCallback(); stills.AddCallback(uploadCb); stills.Upload(index, name, frame); // Short bit of work before the abort helper.HandleUntil(uploadCb.Wait, 1000); stills.CancelTransfer(); helper.HandleUntil(uploadCb.Wait, 1000); Assert.True(uploadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCancelled, uploadCb.Result); helper.SendAndWaitForChange(stateBefore, () => { stills.Unlock(cb); }); } }); }
/// <summary> /// /// </summary> /// <param name="handle"></param> /// <returns></returns> public bool TryEnterLock(LockCallback handle) { using (var l = Lock()) { if (l != null && l.TryEnterLock()) { if (handle != null) { handle(); } } else { TraceLog.WriteError("Monitor lock timeout:{0}", _timeOut); } return l != null && l.IsLocked; } }
/// <summary> /// /// </summary> /// <param name="handle"></param> /// <returns></returns> public bool TryEnterLock(LockCallback handle) { using (var l = Lock()) { if (l != null && l.TryEnterLock()) { if (handle != null) { handle(); } } else { TraceLog.WriteError("Monitor lock timeout:{0}", _timeOut); } return(l != null && l.IsLocked); } }
public void SyncLock(string message, LockCallback callback, object state) { if (callback == null) { throw new ArgumentNullException("callback"); } locked = true; if (FreeCL.UI.Application.MainForm != null) { FreeCL.Forms.LockedGuiForm.SyncStart( message, new FreeCL.Forms.LockCallback(SyncLockCallback), new LockCallbackData(callback, state)); } else { callback(state); } locked = false; }
public static void SyncStart(string message, LockCallback callback, object state) { if(SyncLockedGUIForm == null) { SyncLockedGUIForm = new FreeCL.Forms.LockedGuiForm(); SyncLockedGUIForm.Init(); } SyncLockedGUIForm.savedCallBack = callback; SyncLockedGUIForm.savedState = state; SyncLockedGUIForm.tCallback.Enabled = true; SyncLockedGUIForm.StartWaiting(message); Application.DoEvents(); }
public void TestClipFrameDownload() { DownloadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; IBMDSwitcherMediaPool pool = GetMediaPool(helper); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); Tuple <uint, uint> resolution = stateBefore.Settings.VideoMode.GetResolution().GetSize(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); uint frameIndex = Randomiser.RangeInt(stateBefore.MediaPool.Clips[(int)index].MaxFrames); IBMDSwitcherClip clip = GetClip(helper, index); { var frameState = stateBefore.MediaPool.Clips[(int)index].Frames[(int)frameIndex]; frameState.IsUsed = true; frameState.Hash = new byte[16]; helper.SendFromServerAndWaitForChange(stateBefore, new MediaPoolFrameDescriptionCommand { Bank = (MediaPoolFileType)index + 1, Filename = "", Index = frameIndex, IsUsed = true }); } stateBefore = helper.Helper.BuildLibState(); byte[] bytes = new byte[resolution.Item1 * resolution.Item2 * 4]; worker = new DownloadJobWorker(_output, index + 1, frameIndex, FrameEncodingUtil.EncodeRLE(bytes)); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); var downloadCb = new TransferCallback(); clip.AddCallback(downloadCb); clip.DownloadFrame(frameIndex); helper.HandleUntil(downloadCb.Wait, 5000); Assert.True(downloadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, downloadCb.Result); Assert.NotNull(downloadCb.Frame); Assert.Null(downloadCb.Audio); byte[] sdkBytes = MediaPoolUtil.GetSdkFrameBytes(downloadCb.Frame); Assert.Equal(BitConverter.ToString(bytes), BitConverter.ToString(sdkBytes)); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
private void DoDownload(int iterations, int timeout, Func <uint, uint, Tuple <byte[], byte[]> > rawBytesGen) { DownloadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerStillTransfer, helper => { helper.DisposeSdkClient = true; IBMDSwitcherStills stills = GetStillsPool(helper); for (int i = 0; i < iterations; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); Tuple <uint, uint> resolution = stateBefore.Settings.VideoMode.GetResolution().GetSize(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Stills.Count); { var stillState = stateBefore.MediaPool.Stills[(int)index]; stillState.Filename = "Some file"; stillState.IsUsed = true; stillState.Hash = new byte[16]; helper.SendFromServerAndWaitForChange(stateBefore, new MediaPoolFrameDescriptionCommand { Bank = MediaPoolFileType.Still, Filename = "Some file", Index = index, IsUsed = true }); } stateBefore = helper.Helper.BuildLibState(); Tuple <byte[], byte[]> rawBytes = rawBytesGen(resolution.Item1, resolution.Item2); worker = new DownloadJobWorker(_output, (uint)MediaPoolFileType.Still, index, rawBytes.Item2); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { stills.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); var downloadCb = new TransferCallback(); stills.AddCallback(downloadCb); stills.Download(index); helper.HandleUntil(downloadCb.Wait, timeout); Assert.True(downloadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, downloadCb.Result); Assert.NotNull(downloadCb.Frame); Assert.Equal(_BMDSwitcherPixelFormat.bmdSwitcherPixelFormat10BitYUVA, downloadCb.Frame.GetPixelFormat()); Assert.Equal(resolution.Item1, (uint)downloadCb.Frame.GetWidth()); Assert.Equal(resolution.Item2, (uint)downloadCb.Frame.GetHeight()); byte[] sdkBytes = MediaPoolUtil.GetSdkFrameBytes(downloadCb.Frame); Assert.Equal(BitConverter.ToString(rawBytes.Item1), BitConverter.ToString(sdkBytes)); helper.SendAndWaitForChange(stateBefore, () => { stills.Unlock(cb); }); } }); }
public LockCallbackData(LockCallback callBack, object state) { Callback = callBack; State = state; }
public void TestAudioDownload() { DownloadJobWorker worker = null; AtemMockServerWrapper.Each(_output, _pool, (a, b) => worker?.HandleCommand(a, b), DeviceTestCases.MediaPlayerClips, helper => { helper.DisposeSdkClient = true; var pidCmd = helper.Server.GetParsedDataDump().OfType <ProductIdentifierCommand>().Single(); for (int i = 0; i < 3; i++) { AtemState stateBefore = helper.Helper.BuildLibState(); uint index = Randomiser.RangeInt((uint)stateBefore.MediaPool.Clips.Count); IBMDSwitcherClip clip = GetClip(helper, index); uint sampleCount = 10000; { var clipState = stateBefore.MediaPool.Clips[(int)index]; clipState.Audio.Name = "Some file"; clipState.Audio.IsUsed = true; clipState.Audio.Hash = new byte[16]; helper.SendFromServerAndWaitForChange(stateBefore, new MediaPoolAudioDescriptionCommand { Name = "Some file", Index = index + 1, IsUsed = true }); } stateBefore = helper.Helper.BuildLibState(); var bytes = MediaPoolUtil.RandomFrame(sampleCount); worker = new DownloadJobWorker(_output, index + 1, 0, bytes); var cb = new LockCallback(); helper.SendAndWaitForChange(stateBefore, () => { clip.Lock(cb); }); Assert.True(cb.Wait.WaitOne(2000)); var downloadCb = new TransferCallback(); clip.AddCallback(downloadCb); clip.DownloadAudio(); helper.HandleUntil(downloadCb.Wait, 5000); Assert.True(downloadCb.Wait.WaitOne(500)); Assert.Equal(_BMDSwitcherMediaPoolEventType.bmdSwitcherMediaPoolEventTypeTransferCompleted, downloadCb.Result); Assert.Null(downloadCb.Frame); Assert.NotNull(downloadCb.Audio); Assert.Equal((int)(sampleCount * 4), downloadCb.Audio.GetSize()); byte[] sdkBytes = MediaPoolUtil.GetSdkAudioBytes(downloadCb.Audio); // TODO - this needs a better rule that can be properly exposed via the lib byte[] flippedBytes = pidCmd.Model >= ModelId.PS4K ? MediaPoolUtil.FlipAudio(bytes) : bytes; Assert.Equal(BitConverter.ToString(flippedBytes), BitConverter.ToString(sdkBytes)); helper.SendAndWaitForChange(stateBefore, () => { clip.Unlock(cb); }); } }); }
public bool TryExecute(string key, int timeoutMs, LockCallback success) { return(TryExecuteAsync(key, timeoutMs, delegate() { success(); return Task.FromResult(false); }).Result); }
public void SyncLock(string message, LockCallback callback, object state) { if(callback == null) throw new ArgumentNullException("callback"); locked = true; if(FreeCL.UI.Application.MainForm != null) { FreeCL.Forms.LockedGuiForm.SyncStart( message, new FreeCL.Forms.LockCallback(SyncLockCallback), new LockCallbackData(callback, state)); } else { callback(state); } locked = false; }
/// <summary> /// Attempts to execute the 'success' callback inside a lock based on 'key'. If successful, returns true. /// If the lock cannot be acquired within 'timoutMs', returns false /// In a worst-case scenario, it could take up to twice as long as 'timeoutMs' to return false. /// </summary> /// <param name="key"></param> /// <param name="success"></param> /// <param name="failure"></param> /// <param name="timeoutMs"></param> public bool TryExecute(string key, int timeoutMs, LockCallback success) { //Record when we started. We don't want an infinite loop. DateTime startedAt = DateTime.UtcNow; // Tracks whether the lock acquired is still correct bool validLock = true; // The lock corresponding to 'key' object itemLock = null; try { //We have to loop until we get a valid lock and it stays valid until we lock it. do { // 1) Creation/aquire phase lock (createLock) { // We have to lock on dictionary writes, since otherwise // two locks for the same file could be created and assigned // at the same time. (i.e, between TryGetValue and the assignment) if (!locks.TryGetValue(key, out itemLock)) { locks[key] = itemLock = new Object(); //make a new lock! } } // Loophole (part 1): // Right here - this is where another thread (executing part 2) could remove 'itemLock' // from the dictionary, and potentially, yet another thread could // insert a new value for 'itemLock' into the dictionary... etc, etc.. // 2) Execute phase if (System.Threading.Monitor.TryEnter(itemLock, timeoutMs)) { try { // May take minutes to acquire this lock. // Trying to detect an occurence of loophole above // Check that itemLock still exists and matches the dictionary lock (createLock) { object newLock = null; validLock = locks.TryGetValue(key, out newLock); validLock = validLock && newLock == itemLock; } // Only run the callback if the lock is valid if (validLock) { success(); // Extremely long-running callback, perhaps throwing exceptions return(true); } } finally { System.Threading.Monitor.Exit(itemLock);//release lock } } else { validLock = false; //So the finally clause doesn't try to clean up the lock, someone else will do that. return(false); //Someone else had the lock, they can clean it up. } //Are we out of time, still having an invalid lock? if (!validLock && Math.Abs(DateTime.UtcNow.Subtract(startedAt).TotalMilliseconds) > timeoutMs) { //We failed to get a valid lock in time. return(false); } // If we had an invalid lock, we have to try everything over again. } while (!validLock); } finally { if (validLock) { // Loophole (part 2). When loophole part 1 and 2 cross paths, // An lock object may be removed before being used, and be orphaned // 3) Cleanup phase - Attempt cleanup of lock objects so we don't // have a *very* large and slow dictionary. lock (createLock) { // TryEnter() fails instead of waiting. // A normal lock would cause a deadlock with phase 2. // Specifying a timeout would add great and pointless overhead. // Whoever has the lock will clean it up also. if (System.Threading.Monitor.TryEnter(itemLock)) { try { // It succeeds, so no-one else is working on it // (but may be preparing to, see loophole) // Only remove the lock object if it // still exists in the dictionary as-is object existingLock = null; if (locks.TryGetValue(key, out existingLock) && existingLock == itemLock) { locks.Remove(key); } } finally { // Remove the lock System.Threading.Monitor.Exit(itemLock); } } } } } // Ideally the only objects in 'locks' will be open operations now. return(true); }
/// <summary> /// Attempts to execute the 'success' callback inside a lock based on 'key'. If successful, returns true. /// If the lock cannot be acquired within 'timoutMs', returns false /// In a worst-case scenario, it could take up to twice as long as 'timeoutMs' to return false. /// </summary> /// <param name="key"></param> /// <param name="success"></param> /// <param name="failure"></param> /// <param name="timeoutMs"></param> public bool TryExecute(string key, int timeoutMs, LockCallback success) { //Record when we started. We don't want an infinite loop. DateTime startedAt = DateTime.UtcNow; // Tracks whether the lock acquired is still correct bool validLock = true; // The lock corresponding to 'key' object itemLock = null; try { //We have to loop until we get a valid lock and it stays valid until we lock it. do { // 1) Creation/aquire phase lock (createLock) { // We have to lock on dictionary writes, since otherwise // two locks for the same file could be created and assigned // at the same time. (i.e, between TryGetValue and the assignment) if (!locks.TryGetValue(key, out itemLock)) locks[key] = itemLock = new Object(); //make a new lock! } // Loophole (part 1): // Right here - this is where another thread (executing part 2) could remove 'itemLock' // from the dictionary, and potentially, yet another thread could // insert a new value for 'itemLock' into the dictionary... etc, etc.. // 2) Execute phase if (System.Threading.Monitor.TryEnter(itemLock, timeoutMs)) { try { // May take minutes to acquire this lock. // Trying to detect an occurence of loophole above // Check that itemLock still exists and matches the dictionary lock (createLock) { object newLock = null; validLock = locks.TryGetValue(key, out newLock); validLock = validLock && newLock == itemLock; } // Only run the callback if the lock is valid if (validLock) { success(); // Extremely long-running callback, perhaps throwing exceptions return true; } } finally { System.Threading.Monitor.Exit(itemLock);//release lock } } else { validLock = false; //So the finally clause doesn't try to clean up the lock, someone else will do that. return false; //Someone else had the lock, they can clean it up. } //Are we out of time, still having an invalid lock? if (!validLock && Math.Abs(DateTime.UtcNow.Subtract(startedAt).TotalMilliseconds) > timeoutMs) { //We failed to get a valid lock in time. return false; } // If we had an invalid lock, we have to try everything over again. } while (!validLock); } finally { if (validLock) { // Loophole (part 2). When loophole part 1 and 2 cross paths, // An lock object may be removed before being used, and be orphaned // 3) Cleanup phase - Attempt cleanup of lock objects so we don't // have a *very* large and slow dictionary. lock (createLock) { // TryEnter() fails instead of waiting. // A normal lock would cause a deadlock with phase 2. // Specifying a timeout would add great and pointless overhead. // Whoever has the lock will clean it up also. if (System.Threading.Monitor.TryEnter(itemLock)) { try { // It succeeds, so no-one else is working on it // (but may be preparing to, see loophole) // Only remove the lock object if it // still exists in the dictionary as-is object existingLock = null; if (locks.TryGetValue(key, out existingLock) && existingLock == itemLock) locks.Remove(key); } finally { // Remove the lock System.Threading.Monitor.Exit(itemLock); } } } } } // Ideally the only objects in 'locks' will be open operations now. return true; }