1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Threading; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Time; 13 14 namespace Antmicro.Renode.Network.ExternalControl 15 { 16 public class RunFor : BaseCommand, IDisposable 17 { RunFor(ExternalControlServer parent)18 public RunFor(ExternalControlServer parent) 19 : base(parent) 20 { 21 } 22 Dispose()23 public void Dispose() 24 { 25 if(cancellationToken != null) 26 { 27 parent.Log(LogLevel.Warning, "RunFor disposed while running"); 28 } 29 cancellationToken?.Cancel(); 30 cancellationToken = null; 31 disposed = true; 32 } 33 Invoke(List<byte> data)34 public override Response Invoke(List<byte> data) 35 { 36 if(disposed) 37 { 38 return Response.CommandFailed(Identifier, "Command is unavailable"); 39 } 40 41 if(data.Count != 8) 42 { 43 return Response.CommandFailed(Identifier, "Expected 8 bytes of payload"); 44 } 45 46 if(cancellationToken != null) 47 { 48 return Response.CommandFailed(Identifier, "One RunFor command can be running at any given time"); 49 } 50 51 cancellationToken = new CancellationTokenSource(); 52 exception = null; 53 success = false; 54 55 var microseconds = BitConverter.ToUInt64(data.ToArray(), 0); 56 var interval = TimeInterval.FromMicroseconds(microseconds); 57 58 var thread = new Thread(() => 59 { 60 try 61 { 62 parent.Log(LogLevel.Info, "Executing RunFor({0}) command", interval); 63 EmulationManager.Instance.CurrentEmulation.RunFor(interval); 64 65 if(cancellationToken.IsCancellationRequested) 66 { 67 return; 68 } 69 70 success = true; 71 } 72 catch(Exception e) 73 { 74 exception = e; 75 } 76 cancellationToken?.Cancel(); 77 }) 78 { 79 IsBackground = true, 80 Name = GetType().Name 81 }; 82 83 thread.Start(); 84 cancellationToken.Token.WaitHandle.WaitOne(); 85 cancellationToken = null; 86 87 if(exception != null) 88 { 89 throw exception; 90 } 91 92 if(success) 93 { 94 return Response.Success(Identifier); 95 } 96 return Response.CommandFailed(Identifier, "RunFor was interrupted"); 97 } 98 99 public override Command Identifier => Command.RunFor; 100 public override byte Version => 0x0; 101 102 private bool success; 103 private Exception exception; 104 private CancellationTokenSource cancellationToken; 105 private bool disposed; 106 } 107 } 108