diff --git a/src/ProcSim.Core/CPU.cs b/src/ProcSim.Core/Cpu.cs similarity index 93% rename from src/ProcSim.Core/CPU.cs rename to src/ProcSim.Core/Cpu.cs index c941a60..bb73629 100644 --- a/src/ProcSim.Core/CPU.cs +++ b/src/ProcSim.Core/Cpu.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Interruptions; +using ProcSim.Core.Interruptions; using ProcSim.Core.Process; using ProcSim.Core.Scheduler; using ProcSim.Core.Syscall; @@ -7,15 +7,15 @@ namespace ProcSim.Core; -public class CPU +public class Cpu { - private readonly ConcurrentDictionary> _programs; + private readonly ConcurrentDictionary> _programs; private readonly InterruptController _interruptController; private readonly InterruptService _isrv; private List _instructions; private ConcurrentQueue _ops; - public CPU(uint id, InterruptController intc, InterruptService isrv, IScheduler sched, SystemCallDispatcher syscallDisp, ConcurrentDictionary> processPrograms, Action subscribeToTick) + public Cpu(uint id, InterruptController intc, InterruptService isrv, IScheduler sched, SystemCallDispatcher syscallDisp, ConcurrentDictionary> processPrograms, Action subscribeToTick) { Id = id; _interruptController = intc; @@ -34,7 +34,7 @@ public CPU(uint id, InterruptController intc, InterruptService isrv, IScheduler } public uint Id { get; } - public PCB CurrentPCB + public Pcb CurrentPCB { get; set diff --git a/src/ProcSim.Core/Dispatcher.cs b/src/ProcSim.Core/Dispatcher.cs index 5023fea..34d31cb 100644 --- a/src/ProcSim.Core/Dispatcher.cs +++ b/src/ProcSim.Core/Dispatcher.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; using System.Diagnostics; using System.Text.Json; @@ -6,9 +6,9 @@ namespace ProcSim.Core; public static class Dispatcher { - public static void SwitchContext(CPU cpu, PCB next) + public static void SwitchContext(Cpu cpu, Pcb next) { - PCB prev = cpu.CurrentPCB; + Pcb prev = cpu.CurrentPCB; prev?.OnExitRunning(cpu.UserCycleCount, cpu.SyscallCycleCount); if (prev == next) { @@ -29,7 +29,7 @@ public static void SwitchContext(CPU cpu, PCB next) } } - public static void SaveContext(CPU cpu, PCB pcb) + public static void SaveContext(Cpu cpu, Pcb pcb) { Debug.WriteLine($"Process {pcb.ProcessId} - Saving context (PC: {cpu.PC}, SP: {cpu.SP})"); @@ -42,7 +42,7 @@ public static void SaveContext(CPU cpu, PCB pcb) Debug.WriteLine($"Process {pcb.ProcessId} - Saved PCB: {JsonSerializer.Serialize(pcb)}"); } - public static void LoadContext(CPU cpu, PCB pcb) + public static void LoadContext(Cpu cpu, Pcb pcb) { cpu.PC = pcb.ProgramCounter; cpu.SP = pcb.StackPointer; diff --git a/src/ProcSim.Core/IO/IODevice.cs b/src/ProcSim.Core/IO/IODevice.cs index d3021aa..13ac485 100644 --- a/src/ProcSim.Core/IO/IODevice.cs +++ b/src/ProcSim.Core/IO/IODevice.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Interruptions; +using ProcSim.Core.Interruptions; using ProcSim.Core.Monitoring.Models; using ProcSim.Core.Process; using System.Collections.Concurrent; @@ -10,7 +10,7 @@ public class IODevice : IDisposable { private readonly BlockingCollection _queue = []; private readonly InterruptController _interruptController; - private readonly ConcurrentQueue _waiters = []; + private readonly ConcurrentQueue _waiters = []; private readonly List _workers; private bool _disposed; private readonly CancellationTokenSource _cts; @@ -44,31 +44,43 @@ public IODevice(uint deviceId, uint vector, uint baseLatency, InterruptControlle public long TotalRequests => _totalRequests; public long TotalProcessed => _totalProcessed; - public void Submit(PCB pcb, uint operationUnits) + public void Submit(Pcb pcb, uint operationUnits) { Debug.WriteLine($"IODevice {Id} - Received request from process {pcb.ProcessId} (Operation Units: {operationUnits})"); pcb.State = ProcessState.Waiting; _queue.Add(new IORequest(pcb, operationUnits)); } - public IEnumerable PopWaiters() + public IEnumerable PopWaiters() { - if (!_waiters.TryDequeue(out PCB pcb)) + if (!_waiters.TryDequeue(out Pcb pcb)) yield break; yield return pcb; } public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) { if (_disposed) return; - _queue.CompleteAdding(); + if (disposing) + { + // Dispose managed resources + _queue.CompleteAdding(); + _cts.Cancel(); + Task.WaitAll([.. _workers]); + _queue.Dispose(); + _cts.Dispose(); + } + _disposed = true; - _cts.Cancel(); - Task.WaitAll([.. _workers]); - _queue.Dispose(); } private async Task WorkerAsync(uint channelId, CancellationToken ct) diff --git a/src/ProcSim.Core/IO/IoRequest.cs b/src/ProcSim.Core/IO/IoRequest.cs index 31dec13..68d7fc6 100644 --- a/src/ProcSim.Core/IO/IoRequest.cs +++ b/src/ProcSim.Core/IO/IoRequest.cs @@ -1,5 +1,5 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; namespace ProcSim.Core.IO; -public record IORequest(PCB Pcb, uint OperationUnits); +public record IORequest(Pcb Pcb, uint OperationUnits); diff --git a/src/ProcSim.Core/Interruptions/Handlers/IInterruptHandler.cs b/src/ProcSim.Core/Interruptions/Handlers/IInterruptHandler.cs index b005597..c1e2b25 100644 --- a/src/ProcSim.Core/Interruptions/Handlers/IInterruptHandler.cs +++ b/src/ProcSim.Core/Interruptions/Handlers/IInterruptHandler.cs @@ -1,9 +1,9 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; namespace ProcSim.Core.Interruptions.Handlers; public interface IInterruptHandler { bool CanHandle(uint vector); - Instruction BuildBody(uint vector, CPU cpu); + Instruction BuildBody(uint vector, Cpu cpu); } diff --git a/src/ProcSim.Core/Interruptions/Handlers/IoInterruptHandler.cs b/src/ProcSim.Core/Interruptions/Handlers/IoInterruptHandler.cs index 95873c8..9bd0b82 100644 --- a/src/ProcSim.Core/Interruptions/Handlers/IoInterruptHandler.cs +++ b/src/ProcSim.Core/Interruptions/Handlers/IoInterruptHandler.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.IO; +using ProcSim.Core.IO; using ProcSim.Core.Process; using ProcSim.Core.Process.Factories; @@ -11,7 +11,7 @@ public bool CanHandle(uint vector) return devices.ContainsKey(vector - 33); } - public Instruction BuildBody(uint vector, CPU cpu) + public Instruction BuildBody(uint vector, Cpu cpu) { IODevice device = devices[vector - 33]; return InstructionFactory.HandleIo(device); diff --git a/src/ProcSim.Core/Interruptions/Handlers/TimerInterruptHandler.cs b/src/ProcSim.Core/Interruptions/Handlers/TimerInterruptHandler.cs index 19d295d..5abdaa2 100644 --- a/src/ProcSim.Core/Interruptions/Handlers/TimerInterruptHandler.cs +++ b/src/ProcSim.Core/Interruptions/Handlers/TimerInterruptHandler.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; using ProcSim.Core.Process.Factories; namespace ProcSim.Core.Interruptions.Handlers; @@ -12,7 +12,7 @@ public bool CanHandle(uint vector) return vector == TimerVector; } - public Instruction BuildBody(uint vector, CPU cpu) + public Instruction BuildBody(uint vector, Cpu cpu) { return InstructionFactory.ContextSwitch(); } diff --git a/src/ProcSim.Core/Interruptions/InterruptService.cs b/src/ProcSim.Core/Interruptions/InterruptService.cs index 8983f11..abae4fe 100644 --- a/src/ProcSim.Core/Interruptions/InterruptService.cs +++ b/src/ProcSim.Core/Interruptions/InterruptService.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Interruptions.Handlers; +using ProcSim.Core.Interruptions.Handlers; using ProcSim.Core.Process; using System.Diagnostics; @@ -10,7 +10,7 @@ public class InterruptService(List handlers) public long InterruptCount => _interruptCount; - public Instruction BuildISR(uint vector, CPU cpu) + public Instruction BuildISR(uint vector, Cpu cpu) { Interlocked.Increment(ref _interruptCount); IInterruptHandler handler = handlers.First(h => h.CanHandle(vector)); diff --git a/src/ProcSim.Core/Kernel.cs b/src/ProcSim.Core/Kernel.cs index 511f277..226e85f 100644 --- a/src/ProcSim.Core/Kernel.cs +++ b/src/ProcSim.Core/Kernel.cs @@ -1,7 +1,6 @@ -using ProcSim.Core.Interruptions; +using ProcSim.Core.Interruptions; using ProcSim.Core.Interruptions.Handlers; using ProcSim.Core.IO; -using ProcSim.Core.Monitoring; using ProcSim.Core.Process; using ProcSim.Core.Process.Factories; using ProcSim.Core.Scheduler; @@ -13,16 +12,17 @@ namespace ProcSim.Core; public class Kernel : IDisposable { - private readonly Dictionary _idlePcbs = []; + private readonly Dictionary _idlePcbs = []; private readonly InterruptController _interruptController = new(); private IScheduler _scheduler; + private bool _disposed; public const uint KERNEL_TERMINATE_VECTOR = 31; public Dictionary Devices { get; } = []; - public Dictionary Cpus { get; } = []; - public ConcurrentDictionary> Programs { get; } = new(); + public Dictionary Cpus { get; } = []; + public ConcurrentDictionary> Programs { get; } = new(); public ulong GlobalCycle { get; private set; } public uint RegisterDevice(string name, uint baseLatency, uint channels) @@ -48,11 +48,11 @@ public void Initialize(uint cores, uint quantum, SchedulerType schedulerType, Ac for (uint coreId = 0; coreId < cores; coreId++) { List idleInstructions = [InstructionFactory.Idle()]; - PCB idleProcess = new((int)coreId, $"Idle({coreId})", null, ProcessStaticPriority.Normal) { State = ProcessState.Ready }; + Pcb idleProcess = new((int)coreId, $"Idle({coreId})", null, ProcessStaticPriority.Normal) { State = ProcessState.Ready }; _idlePcbs[coreId] = idleProcess; Programs[idleProcess] = idleInstructions; - CPU cpu = new(coreId, _interruptController, interruptService, _scheduler, syscallDispatcher, Programs, subscribeToTick); + Cpu cpu = new(coreId, _interruptController, interruptService, _scheduler, syscallDispatcher, Programs, subscribeToTick); Cpus.Add(coreId, cpu); _interruptController.RegisterCore(coreId); @@ -66,7 +66,7 @@ public void Initialize(uint cores, uint quantum, SchedulerType schedulerType, Ac public int CreateProcess(ProcessDto program) { int id = Programs.Count; - PCB pcb = new(id, program.Name, program.Registers, program.Priority); + Pcb pcb = new(id, program.Name, program.Registers, program.Priority); Programs[pcb] = [.. program.Instructions]; _scheduler.Admit(pcb); return id; @@ -80,7 +80,7 @@ public void TerminateProcess(int pid) return; } - PCB pcb = Programs.Keys.FirstOrDefault(p => p.ProcessId == pid); + Pcb pcb = Programs.Keys.FirstOrDefault(p => p.ProcessId == pid); if (pcb?.State is null or ProcessState.Terminated) return; @@ -92,13 +92,27 @@ public void TerminateProcess(int pid) public void SetProcessStaticPriority(int pid, ProcessStaticPriority newPriority) { - PCB pcb = Programs.Keys.First(p => p.ProcessId == pid); + Pcb pcb = Programs.Keys.First(p => p.ProcessId == pid); pcb.StaticPriority = newPriority; } public void Dispose() { - foreach (IODevice device in Devices.Values) - device.Dispose(); + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + foreach (IODevice device in Devices.Values) + device.Dispose(); + } + + _disposed = true; } } diff --git a/src/ProcSim.Core/Monitoring/MonitoringService.cs b/src/ProcSim.Core/Monitoring/MonitoringService.cs index 2acea4b..a3a46c8 100644 --- a/src/ProcSim.Core/Monitoring/MonitoringService.cs +++ b/src/ProcSim.Core/Monitoring/MonitoringService.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.IO; +using ProcSim.Core.IO; using ProcSim.Core.Monitoring.Models; using ProcSim.Core.Process; using System.Collections.Concurrent; @@ -15,7 +15,6 @@ public class MonitoringService : IDisposable private readonly CancellationTokenSource _cts = new(); private readonly Dictionary _prevCpu = []; - private ulong _prevGlobalCycle; private readonly Dictionary _prevProcCycles = []; private readonly Dictionary> _prevChan = []; private readonly Dictionary> _deviceChannelBusy = []; @@ -24,6 +23,7 @@ public class MonitoringService : IDisposable private readonly ConcurrentDictionary _ioStarts = []; private Kernel _kernel; + private bool _disposed; public MonitoringService() { @@ -73,12 +73,10 @@ public void SetKernel(Kernel kernel) DeviceMetrics.Clear(); // inicializa snapshots de CPU e processos - foreach (CPU cpu in _kernel.Cpus.Values) + foreach (Cpu cpu in _kernel.Cpus.Values) _prevCpu[cpu.Id] = new CpuSnapshot(cpu); - _prevGlobalCycle = kernel.GlobalCycle; - - foreach (PCB pcb in kernel.Programs.Keys) + foreach (Pcb pcb in kernel.Programs.Keys) _prevProcCycles[pcb.ProcessId] = 0; foreach (IODevice device in kernel.Devices.Values) @@ -114,7 +112,6 @@ private async Task CollectAsync(CancellationToken ct) DateTime ts = DateTime.UtcNow; ulong nowTick = _kernel.GlobalCycle; - _prevGlobalCycle = nowTick; // 1) CPU por núcleo e agregados ulong totalC = 0UL; // total de ticks em todas as CPUs @@ -123,7 +120,7 @@ private async Task CollectAsync(CancellationToken ct) ulong totalI = 0UL; // ticks de interrupção (sum of dI) ulong totalIdle = 0UL; // ticks de idle (sum of dIdle) - foreach (CPU cpu in _kernel.Cpus.Values) + foreach (Cpu cpu in _kernel.Cpus.Values) { CpuSnapshot prev = _prevCpu[cpu.Id]; @@ -159,7 +156,7 @@ private async Task CollectAsync(CancellationToken ct) processSnapshots.Add(new ProcessSnapshot(Pid: 0, Name: "Idle", State: idlePercent > 0 ? ProcessState.Running : ProcessState.Ready, CpuUsage: idlePercent, StaticPriority: ProcessStaticPriority.Normal, DynamicPriority: -1)); - foreach (PCB pcb in _kernel.Programs.Keys) + foreach (Pcb pcb in _kernel.Programs.Keys) { if (pcb.ProcessId < _kernel.Cpus.Count) continue; @@ -270,14 +267,29 @@ private void OnIoRequestCompleted(IoRequestNotification req) public void Dispose() { - _cts.Cancel(); - _timer.Dispose(); - Debug.WriteLineIf(DebugEnabled, "[MonitoringService] Disposed"); + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + _cts.Cancel(); + _cts.Dispose(); + _timer.Dispose(); + Debug.WriteLineIf(DebugEnabled, "[MonitoringService] Disposed"); + } + + _disposed = true; + } } private sealed record CpuSnapshot(ulong CycleCount, ulong UserCycleCount, ulong SyscallCycleCount, ulong InterruptCycleCount, ulong IdleCycleCount) { - public CpuSnapshot(CPU cpu) : this(cpu.CycleCount, cpu.UserCycleCount, cpu.SyscallCycleCount, cpu.InterruptCycleCount, cpu.IdleCycleCount) { } + public CpuSnapshot(Cpu cpu) : this(cpu.CycleCount, cpu.UserCycleCount, cpu.SyscallCycleCount, cpu.InterruptCycleCount, cpu.IdleCycleCount) { } } private sealed record ChannelSnapshot diff --git a/src/ProcSim.Core/Process/Factories/MicroOpFactory.cs b/src/ProcSim.Core/Process/Factories/MicroOpFactory.cs index 359a8f8..a19e708 100644 --- a/src/ProcSim.Core/Process/Factories/MicroOpFactory.cs +++ b/src/ProcSim.Core/Process/Factories/MicroOpFactory.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.IO; +using ProcSim.Core.IO; using ProcSim.Core.Syscall; namespace ProcSim.Core.Process.Factories; @@ -75,7 +75,7 @@ public static MicroOp SwitchContext() Description: "Troca de contexto para próximo processo", Execute: cpu => { - PCB next = cpu.Scheduler.Preempt(cpu); + Pcb next = cpu.Scheduler.Preempt(cpu); Dispatcher.SwitchContext(cpu, next); } ); @@ -106,7 +106,7 @@ public static MicroOp IoHandler(IODevice device) Description: "Finaliza I/O e admite processos aguardando no dispositivo", Execute: cpu => { - foreach (PCB pcb in device.PopWaiters()) + foreach (Pcb pcb in device.PopWaiters()) { pcb.OnIoCompleted(cpu.CycleCount); cpu.Scheduler.Admit(pcb); diff --git a/src/ProcSim.Core/Process/MicroOp.cs b/src/ProcSim.Core/Process/MicroOp.cs index 29f3208..a16fbbe 100644 --- a/src/ProcSim.Core/Process/MicroOp.cs +++ b/src/ProcSim.Core/Process/MicroOp.cs @@ -1,3 +1,3 @@ -namespace ProcSim.Core.Process; +namespace ProcSim.Core.Process; -public record MicroOp(string Name, string Description, Action Execute); +public record MicroOp(string Name, string Description, Action Execute); diff --git a/src/ProcSim.Core/Process/PCB.cs b/src/ProcSim.Core/Process/Pcb.cs similarity index 92% rename from src/ProcSim.Core/Process/PCB.cs rename to src/ProcSim.Core/Process/Pcb.cs index 1b24422..9fbf541 100644 --- a/src/ProcSim.Core/Process/PCB.cs +++ b/src/ProcSim.Core/Process/Pcb.cs @@ -1,10 +1,10 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; namespace ProcSim.Core.Process; -public class PCB +public class Pcb { - public PCB(int processId, string name, Dictionary registers, ProcessStaticPriority staticPriority) + public Pcb(int processId, string name, Dictionary registers, ProcessStaticPriority staticPriority) { for (uint i = 0; i < 8; i++) { diff --git a/src/ProcSim.Core/Scheduler/IScheduler.cs b/src/ProcSim.Core/Scheduler/IScheduler.cs index b104d21..a3878b0 100644 --- a/src/ProcSim.Core/Scheduler/IScheduler.cs +++ b/src/ProcSim.Core/Scheduler/IScheduler.cs @@ -1,10 +1,10 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; namespace ProcSim.Core.Scheduler; public interface IScheduler { - void Admit(PCB pcb); - PCB Preempt(CPU cpu); - void Decommission(PCB pcb); + void Admit(Pcb pcb); + Pcb Preempt(Cpu cpu); + void Decommission(Pcb pcb); } \ No newline at end of file diff --git a/src/ProcSim.Core/Scheduler/PriorityScheduler.cs b/src/ProcSim.Core/Scheduler/PriorityScheduler.cs index 5b6b32d..f4b7dfe 100644 --- a/src/ProcSim.Core/Scheduler/PriorityScheduler.cs +++ b/src/ProcSim.Core/Scheduler/PriorityScheduler.cs @@ -1,9 +1,9 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; using System.Diagnostics; namespace ProcSim.Core.Scheduler; -public sealed class PriorityScheduler(IReadOnlyDictionary idlePcbs, Kernel kernel) : IScheduler +public sealed class PriorityScheduler(IReadOnlyDictionary idlePcbs, Kernel kernel) : IScheduler { private const ulong AGING_QUANTUM = 50; private const double ALPHA = 5.0; // IO to CPU time ratio factor @@ -11,10 +11,10 @@ public sealed class PriorityScheduler(IReadOnlyDictionary idlePcbs, K private const double GAMMA = 0.1; // Queue length penalty factor private const int MAX_DYNAMIC_PRIORITY = (int)ProcessStaticPriority.RealTime + 4; - private readonly PriorityQueue _readyQueue = new(); + private readonly PriorityQueue _readyQueue = new(); private readonly Lock _queueLock = new(); - public void Admit(PCB pcb) + public void Admit(Pcb pcb) { if (pcb.State == ProcessState.Terminated) { @@ -32,10 +32,10 @@ public void Admit(PCB pcb) pcb.LastEnqueueCycle = kernel.GlobalCycle; } - public PCB Preempt(CPU cpu) + public Pcb Preempt(Cpu cpu) { - PCB prev = cpu.CurrentPCB; - PCB next = GetNext(cpu.Id); + Pcb prev = cpu.CurrentPCB; + Pcb next = GetNext(cpu.Id); if (next == idlePcbs[cpu.Id] && prev?.State == ProcessState.Running) { @@ -47,35 +47,35 @@ public PCB Preempt(CPU cpu) Admit(prev); if (prev == idlePcbs[cpu.Id]) - prev.State = ProcessState.Ready; + prev?.State = ProcessState.Ready; next.State = ProcessState.Running; return next; } - public void Decommission(PCB pcb) + public void Decommission(Pcb pcb) { lock (_queueLock) { - var remainingItems = _readyQueue.UnorderedItems + IEnumerable<(Pcb Element, int Priority)> remainingItems = _readyQueue.UnorderedItems .Where(item => item.Element.ProcessId != pcb.ProcessId) .Select(item => (item.Element, item.Priority)); _readyQueue.Clear(); - foreach (var (item, priority) in remainingItems) + foreach ((Pcb item, int priority) in remainingItems) { _readyQueue.Enqueue(item, priority); } - + Debug.WriteLine($"Decommissioned process {pcb.ProcessId} from PriorityScheduler."); } } - public PCB GetNext(uint cpuId) + public Pcb GetNext(uint cpuId) { lock (_queueLock) { - while (_readyQueue.TryDequeue(out PCB next, out _)) + while (_readyQueue.TryDequeue(out Pcb next, out _)) { if (next.State != ProcessState.Terminated) { @@ -91,7 +91,7 @@ public PCB GetNext(uint cpuId) return idlePcbs[cpuId]; } - private int RecalculatePriority(PCB pcb, ulong now) + private int RecalculatePriority(Pcb pcb, ulong now) { ulong wait = now - pcb.LastEnqueueCycle; double boost = BETA * (wait / (double)AGING_QUANTUM); diff --git a/src/ProcSim.Core/Scheduler/RoundRobinScheduler.cs b/src/ProcSim.Core/Scheduler/RoundRobinScheduler.cs index d365bcd..c5f4cfe 100644 --- a/src/ProcSim.Core/Scheduler/RoundRobinScheduler.cs +++ b/src/ProcSim.Core/Scheduler/RoundRobinScheduler.cs @@ -1,14 +1,14 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; using System.Diagnostics; namespace ProcSim.Core.Scheduler; -public sealed class RoundRobinScheduler(IReadOnlyDictionary idlePcbs) : IScheduler +public sealed class RoundRobinScheduler(IReadOnlyDictionary idlePcbs) : IScheduler { - private Queue readyQueue = new(); + private Queue readyQueue = new(); private readonly Lock _queueLock = new(); - public void Admit(PCB pcb) + public void Admit(Pcb pcb) { if (pcb.State == ProcessState.Terminated) { @@ -22,25 +22,25 @@ public void Admit(PCB pcb) readyQueue.Enqueue(pcb); } - public PCB Preempt(CPU cpu) + public Pcb Preempt(Cpu cpu) { - PCB prev = cpu.CurrentPCB; + Pcb prev = cpu.CurrentPCB; if (prev?.State == ProcessState.Running && prev != idlePcbs[cpu.Id]) Admit(prev); if (prev == idlePcbs[cpu.Id]) prev.State = ProcessState.Ready; - PCB next = GetNext(cpu.Id); + Pcb next = GetNext(cpu.Id); next.State = ProcessState.Running; return next; } - public PCB GetNext(uint cpuId) + public Pcb GetNext(uint cpuId) { lock (_queueLock) { - while (readyQueue.TryDequeue(out PCB next)) + while (readyQueue.TryDequeue(out Pcb next)) { if (next.State != ProcessState.Terminated) { @@ -54,11 +54,11 @@ public PCB GetNext(uint cpuId) return idlePcbs[cpuId]; } - public void Decommission(PCB pcb) + public void Decommission(Pcb pcb) { lock (_queueLock) { - readyQueue = new Queue(readyQueue.Where(p => p.ProcessId != pcb.ProcessId)); + readyQueue = new Queue(readyQueue.Where(p => p.ProcessId != pcb.ProcessId)); Debug.WriteLine($"Decommissioned process {pcb.ProcessId} from RoundRobinScheduler."); } } diff --git a/src/ProcSim.Core/Scheduler/SchedulerFactory.cs b/src/ProcSim.Core/Scheduler/SchedulerFactory.cs index 239d660..e5d8adf 100644 --- a/src/ProcSim.Core/Scheduler/SchedulerFactory.cs +++ b/src/ProcSim.Core/Scheduler/SchedulerFactory.cs @@ -1,10 +1,10 @@ -using ProcSim.Core.Process; +using ProcSim.Core.Process; namespace ProcSim.Core.Scheduler; internal static class SchedulerFactory { - public static IScheduler Create(SchedulerType schedulerType, Kernel kernel, IReadOnlyDictionary idlePcbs) + public static IScheduler Create(SchedulerType schedulerType, Kernel kernel, IReadOnlyDictionary idlePcbs) { return schedulerType switch { diff --git a/src/ProcSim.Core/Simulation/SimulationController.cs b/src/ProcSim.Core/Simulation/SimulationController.cs index 3ad01a5..c71ea48 100644 --- a/src/ProcSim.Core/Simulation/SimulationController.cs +++ b/src/ProcSim.Core/Simulation/SimulationController.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.Configuration; +using ProcSim.Core.Configuration; using ProcSim.Core.IO; using ProcSim.Core.Monitoring; using ProcSim.Core.Process; @@ -236,7 +236,7 @@ private IEnumerable BuildIoInstruction(IoOperationConfigModel ioOpe } } - private IEnumerable BuildCpuInstructions(CpuOperationConfigModel cpuOperation) + private static IEnumerable BuildCpuInstructions(CpuOperationConfigModel cpuOperation) { for (int i = 0; i < cpuOperation.RepeatCount; i++) { diff --git a/src/ProcSim.Core/Syscall/SystemCallDispatcher.cs b/src/ProcSim.Core/Syscall/SystemCallDispatcher.cs index 7ab412a..04f1033 100644 --- a/src/ProcSim.Core/Syscall/SystemCallDispatcher.cs +++ b/src/ProcSim.Core/Syscall/SystemCallDispatcher.cs @@ -1,4 +1,4 @@ -using ProcSim.Core.IO; +using ProcSim.Core.IO; using ProcSim.Core.Process; using System.Diagnostics; @@ -8,9 +8,9 @@ public class SystemCallDispatcher(IReadOnlyDictionary devices) { public IReadOnlyDictionary Devices { get; } = devices; - public void HandleSyscall(CPU cpu, SyscallType type, uint deviceId, uint operationUnits = 0) + public void HandleSyscall(Cpu cpu, SyscallType type, uint deviceId, uint operationUnits = 0) { - PCB current = cpu.CurrentPCB; + Pcb current = cpu.CurrentPCB; switch (type) { case SyscallType.IoRequest: diff --git a/src/ProcSim/Assets/Settings.cs b/src/ProcSim/Assets/Settings.cs index e5b48a8..83c1f0e 100644 --- a/src/ProcSim/Assets/Settings.cs +++ b/src/ProcSim/Assets/Settings.cs @@ -1,31 +1,8 @@ -namespace ProcSim.Assets; +namespace ProcSim.Assets; - -// This class allows you to handle specific events on the settings class: -// The SettingChanging event is raised before a setting's value is changed. -// The PropertyChanged event is raised after a setting's value is changed. -// The SettingsLoaded event is raised after the setting values are loaded. -// The SettingsSaving event is raised before the setting values are saved. internal sealed partial class Settings { - public Settings() { - // // To add event handlers for saving and changing settings, uncomment the lines below: - // - // this.SettingChanging += this.SettingChangingEventHandler; - // - // this.SettingsSaving += this.SettingsSavingEventHandler; - // - } - - private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) - { - // Add code to handle the SettingChangingEvent event here. - } - - private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) - { - // Add code to handle the SettingsSaving event here. } } diff --git a/src/ProcSim/Converters/BooleanToVisibilityConverter.cs b/src/ProcSim/Converters/BooleanToVisibilityConverter.cs index 12a7e53..63c1396 100644 --- a/src/ProcSim/Converters/BooleanToVisibilityConverter.cs +++ b/src/ProcSim/Converters/BooleanToVisibilityConverter.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Windows; using System.Windows.Data; @@ -13,31 +13,27 @@ public object Convert(object value, Type targetType, object parameter, CultureIn { flag = v; } - else if (value is bool?) - { - bool? nullable = (bool?)value; - flag = nullable.GetValueOrDefault(); - } - if (parameter != null) - { - if (bool.Parse((string)parameter)) - flag = !flag; - } - if (flag) - return Visibility.Visible; + if (GetBoolParameter(parameter)) + flag = !flag; - return Visibility.Collapsed; + return flag ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { bool back = value is Visibility visibility && visibility == Visibility.Visible; - if (parameter != null) - { - if ((bool)parameter) - back = !back; - } + if (GetBoolParameter(parameter)) + back = !back; + return back; } + + private static bool GetBoolParameter(object parameter) + { + if (parameter is bool b) + return b; + + return parameter is string s && bool.TryParse(s, out bool result) && result; + } } \ No newline at end of file diff --git a/src/ProcSim/Converters/EnumDescriptionConverter.cs b/src/ProcSim/Converters/EnumDescriptionConverter.cs index f409c74..9c2f473 100644 --- a/src/ProcSim/Converters/EnumDescriptionConverter.cs +++ b/src/ProcSim/Converters/EnumDescriptionConverter.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.ComponentModel; using System.Globalization; using System.Reflection; @@ -8,7 +8,7 @@ namespace ProcSim.Converters; public sealed class EnumDescriptionConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter = null, CultureInfo culture = null) + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value switch { diff --git a/src/ProcSim/Converters/InvertBooleanConverter.cs b/src/ProcSim/Converters/InvertBooleanConverter.cs index 70f3252..ce2b5ac 100644 --- a/src/ProcSim/Converters/InvertBooleanConverter.cs +++ b/src/ProcSim/Converters/InvertBooleanConverter.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Windows.Data; namespace ProcSim.Converters; @@ -8,11 +8,15 @@ public class InvertBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - bool original = (bool)value; - return !original; + return InvertBoolean(value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return InvertBoolean(value); + } + + private static bool InvertBoolean(object value) { bool original = (bool)value; return !original; diff --git a/src/ProcSim/Helpers/BindingProxy.cs b/src/ProcSim/Helpers/BindingProxy.cs index ed56259..69b43db 100644 --- a/src/ProcSim/Helpers/BindingProxy.cs +++ b/src/ProcSim/Helpers/BindingProxy.cs @@ -1,10 +1,13 @@ -using System.Windows; +using System.Windows; namespace ProcSim.Helpers; public class BindingProxy : Freezable { - protected override Freezable CreateInstanceCore() => new BindingProxy(); + protected override Freezable CreateInstanceCore() + { + return new BindingProxy(); + } public object Data { diff --git a/src/ProcSim/ViewModels/CpuOperationConfigViewModel.cs b/src/ProcSim/ViewModels/CpuOperationConfigViewModel.cs new file mode 100644 index 0000000..fcdac96 --- /dev/null +++ b/src/ProcSim/ViewModels/CpuOperationConfigViewModel.cs @@ -0,0 +1,76 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using ProcSim.Converters; +using ProcSim.Core.Configuration; + +namespace ProcSim.ViewModels; + +public sealed partial class CpuOperationConfigViewModel : ObservableObject +{ + public CpuOperationConfigViewModel() + { + Type = CpuOperationType.Random; + RepeatCount = 1; + } + + public static CpuOperationType[] CpuOperationTypeValues { get; } = [.. Enum.GetValues().Where(x => x != CpuOperationType.None)]; + + [ObservableProperty] + public partial CpuOperationType Type { get; set; } + [ObservableProperty] + public partial int Min { get; set; } + [ObservableProperty] + public partial int Max { get; set; } + [ObservableProperty] + public partial uint RepeatCount { get; set; } + + public CpuOperationConfigModel MapToModel() + { + return new(Type, Min, Max, RepeatCount); + } + + public void UpdateFromModel(CpuOperationConfigModel model) + { + Type = model.Type; + Min = model.Min; + Max = model.Max; + RepeatCount = model.RepeatCount; + } + + public bool Validate(out IEnumerable errors) + { + List list = []; + + if (Type == CpuOperationType.None) + list.Add("Tipo de operação CPU não foi selecionado."); + + if (Min == 0 || Max == 0) + list.Add("Valores mínimo e máximo não podem ser zero."); + + if (Min >= Max) + list.Add("Valor mínimo não pode ser maior ou igual ao máximo."); + + if (RepeatCount == 0) + list.Add("Repetições não podem ser zero."); + + errors = list; + return list.Count == 0; + } + + public string GetSummary() + { + return $"CPU: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(Type),-6} Min: {Min} Max: {Max}"; + } + + public bool ValueEquals(CpuOperationConfigViewModel other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + + if (Type != other.Type) return false; + if (Min != other.Min) return false; + if (Max != other.Max) return false; + if (RepeatCount != other.RepeatCount) return false; + + return true; + } +} diff --git a/src/ProcSim/ViewModels/IoOperationConfigViewModel.cs b/src/ProcSim/ViewModels/IoOperationConfigViewModel.cs new file mode 100644 index 0000000..7028940 --- /dev/null +++ b/src/ProcSim/ViewModels/IoOperationConfigViewModel.cs @@ -0,0 +1,96 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using ProcSim.Converters; +using ProcSim.Core.Configuration; +using ProcSim.Core.IO; + +namespace ProcSim.ViewModels; + +public sealed partial class IoOperationConfigViewModel : ObservableObject +{ + public IoOperationConfigViewModel() + { + DeviceType = IoDeviceType.Disk; + RepeatCount = 1; + } + + public static IoDeviceType[] IoDeviceTypeValues { get; } = [.. Enum.GetValues().Where(x => x != IoDeviceType.None)]; + + [ObservableProperty] + public partial IoDeviceType DeviceType { get; set; } + [ObservableProperty] + public partial uint Duration { get; set; } + [ObservableProperty] + public partial uint MinDuration { get; set; } + [ObservableProperty] + public partial uint MaxDuration { get; set; } + [ObservableProperty] + public partial bool IsRandom { get; set; } + [ObservableProperty] + public partial uint RepeatCount { get; set; } + + public bool Validate(out IEnumerable errors) + { + List list = []; + + if (DeviceType == IoDeviceType.None) + list.Add("Dispositivo não foi selecionado."); + + if (Duration == 0 && !IsRandom) + list.Add("Duração não pode ser zero."); + + if (IsRandom && (MinDuration == 0 || MaxDuration == 0 || MinDuration > MaxDuration)) + list.Add("Duração mínima e máxima inválida."); + + if (RepeatCount == 0) + list.Add("Repetições não podem ser zero."); + + errors = list; + return list.Count == 0; + } + + public string GetSummary() + { + if (IsRandom) + return $"I/O: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(DeviceType),-6} Min: {MinDuration}u Max: {MaxDuration}u"; + + return $"I/O: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(DeviceType),-6} {Duration}u"; + } + + public IoOperationConfigModel MapToModel() + { + return new() + { + DeviceType = DeviceType, + Duration = Duration, + MinDuration = MinDuration, + MaxDuration = MaxDuration, + IsRandom = IsRandom, + RepeatCount = RepeatCount + }; + } + + public void UpdateFromModel(IoOperationConfigModel model) + { + DeviceType = model.DeviceType; + Duration = model.Duration; + MinDuration = model.MinDuration; + MaxDuration = model.MaxDuration; + IsRandom = model.IsRandom; + RepeatCount = model.RepeatCount; + } + + public bool ValueEquals(IoOperationConfigViewModel other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + + if (DeviceType != other.DeviceType) return false; + if (Duration != other.Duration) return false; + if (MinDuration != other.MinDuration) return false; + if (MaxDuration != other.MaxDuration) return false; + if (IsRandom != other.IsRandom) return false; + if (RepeatCount != other.RepeatCount) return false; + + return true; + } +} \ No newline at end of file diff --git a/src/ProcSim/ViewModels/LoopType.cs b/src/ProcSim/ViewModels/LoopType.cs new file mode 100644 index 0000000..0140911 --- /dev/null +++ b/src/ProcSim/ViewModels/LoopType.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; + +namespace ProcSim.ViewModels; + +public enum LoopType +{ + [Description("")] + None, + [Description("Infinito")] + Infinite, + [Description("Finito")] + Finite, + [Description("Random")] + Random +} diff --git a/src/ProcSim/ViewModels/MainViewModel.cs b/src/ProcSim/ViewModels/MainViewModel.cs index ff73d15..bfbb662 100644 --- a/src/ProcSim/ViewModels/MainViewModel.cs +++ b/src/ProcSim/ViewModels/MainViewModel.cs @@ -1,7 +1,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using ProcSim.Core.Monitoring; using ProcSim.New.ViewModels; -using System.ComponentModel; using System.IO; namespace ProcSim.ViewModels; diff --git a/src/ProcSim/ViewModels/OperationConfigViewModel.cs b/src/ProcSim/ViewModels/OperationConfigViewModel.cs index 12fe7e6..c43cacb 100644 --- a/src/ProcSim/ViewModels/OperationConfigViewModel.cs +++ b/src/ProcSim/ViewModels/OperationConfigViewModel.cs @@ -1,22 +1,10 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using ProcSim.Converters; +using CommunityToolkit.Mvvm.ComponentModel; using ProcSim.Core.Configuration; -using ProcSim.Core.IO; using System.ComponentModel; namespace ProcSim.ViewModels; -public enum OperationType -{ - [Description("")] - None, - [Description("CPU")] - Cpu, - [Description("I/O")] - Io -} - -public partial class OperationConfigViewModel : ObservableObject +public sealed partial class OperationConfigViewModel : ObservableObject { public OperationConfigViewModel() { @@ -103,14 +91,14 @@ public bool Validate(out IEnumerable errors) return list.Count == 0; } - public bool Equals(OperationConfigViewModel other) + public bool ValueEquals(OperationConfigViewModel other) { if (other is null) return false; if (ReferenceEquals(this, other)) return true; if (Type != other.Type) return false; - if (!CpuOperationConfig.Equals(other.CpuOperationConfig)) return false; - if (!IoOperationConfig.Equals(other.IoOperationConfig)) return false; + if (!CpuOperationConfig.ValueEquals(other.CpuOperationConfig)) return false; + if (!IoOperationConfig.ValueEquals(other.IoOperationConfig)) return false; return true; } @@ -120,164 +108,3 @@ private void Child_PropertyChanged(object sender, PropertyChangedEventArgs e) OnPropertyChanged(nameof(Summary)); } } - -public partial class CpuOperationConfigViewModel : ObservableObject -{ - public CpuOperationConfigViewModel() - { - Type = CpuOperationType.Random; - RepeatCount = 1; - } - - public static CpuOperationType[] CpuOperationTypeValues { get; } = [.. Enum.GetValues().Where(x => x != CpuOperationType.None)]; - - [ObservableProperty] - public partial CpuOperationType Type { get; set; } - [ObservableProperty] - public partial int Min { get; set; } - [ObservableProperty] - public partial int Max { get; set; } - [ObservableProperty] - public partial uint RepeatCount { get; set; } - - public CpuOperationConfigModel MapToModel() - { - return new(Type, Min, Max, RepeatCount); - } - - public void UpdateFromModel(CpuOperationConfigModel model) - { - Type = model.Type; - Min = model.Min; - Max = model.Max; - RepeatCount = model.RepeatCount; - } - - public bool Validate(out IEnumerable errors) - { - List list = []; - - if (Type == CpuOperationType.None) - list.Add("Tipo de operação CPU não foi selecionado."); - - if (Min == 0 || Max == 0) - list.Add("Valores mínimo e máximo não podem ser zero."); - - if (Min >= Max) - list.Add("Valor mínimo não pode ser maior ou igual ao máximo."); - - if (RepeatCount == 0) - list.Add("Repetições não podem ser zero."); - - errors = list; - return list.Count == 0; - } - - public string GetSummary() - { - return $"CPU: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(Type),-6} Min: {Min} Max: {Max}"; - } - - public bool Equals(CpuOperationConfigViewModel other) - { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - - if (Type != other.Type) return false; - if (Min != other.Min) return false; - if (Max != other.Max) return false; - if (RepeatCount != other.RepeatCount) return false; - - return true; - } -} - -public partial class IoOperationConfigViewModel : ObservableObject -{ - public IoOperationConfigViewModel() - { - DeviceType = IoDeviceType.Disk; - RepeatCount = 1; - } - - public static IoDeviceType[] IoDeviceTypeValues { get; } = [.. Enum.GetValues().Where(x => x != IoDeviceType.None)]; - - [ObservableProperty] - public partial IoDeviceType DeviceType { get; set; } - [ObservableProperty] - public partial uint Duration { get; set; } - [ObservableProperty] - public partial uint MinDuration { get; set; } - [ObservableProperty] - public partial uint MaxDuration { get; set; } - [ObservableProperty] - public partial bool IsRandom { get; set; } - [ObservableProperty] - public partial uint RepeatCount { get; set; } - - public bool Validate(out IEnumerable errors) - { - List list = []; - - if (DeviceType == IoDeviceType.None) - list.Add("Dispositivo não foi selecionado."); - - if (Duration == 0 && !IsRandom) - list.Add("Duração não pode ser zero."); - - if (IsRandom && (MinDuration == 0 || MaxDuration == 0 || MinDuration > MaxDuration)) - list.Add("Duração mínima e máxima inválida."); - - if (RepeatCount == 0) - list.Add("Repetições não podem ser zero."); - - errors = list; - return list.Count == 0; - } - - public string GetSummary() - { - if (IsRandom) - return $"I/O: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(DeviceType),-6} Min: {MinDuration}u Max: {MaxDuration}u"; - - return $"I/O: {RepeatCount}x {EnumDescriptionConverter.GetEnumDescription(DeviceType),-6} {Duration}u"; - } - - public IoOperationConfigModel MapToModel() - { - return new() - { - DeviceType = DeviceType, - Duration = Duration, - MinDuration = MinDuration, - MaxDuration = MaxDuration, - IsRandom = IsRandom, - RepeatCount = RepeatCount - }; - } - - public void UpdateFromModel(IoOperationConfigModel model) - { - DeviceType = model.DeviceType; - Duration = model.Duration; - MinDuration = model.MinDuration; - MaxDuration = model.MaxDuration; - IsRandom = model.IsRandom; - RepeatCount = model.RepeatCount; - } - - public bool Equals(IoOperationConfigViewModel other) - { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - - if (DeviceType != other.DeviceType) return false; - if (Duration != other.Duration) return false; - if (MinDuration != other.MinDuration) return false; - if (MaxDuration != other.MaxDuration) return false; - if (IsRandom != other.IsRandom) return false; - if (RepeatCount != other.RepeatCount) return false; - - return true; - } -} \ No newline at end of file diff --git a/src/ProcSim/ViewModels/OperationType.cs b/src/ProcSim/ViewModels/OperationType.cs new file mode 100644 index 0000000..74d8125 --- /dev/null +++ b/src/ProcSim/ViewModels/OperationType.cs @@ -0,0 +1,13 @@ +using System.ComponentModel; + +namespace ProcSim.ViewModels; + +public enum OperationType +{ + [Description("")] + None, + [Description("CPU")] + Cpu, + [Description("I/O")] + Io +} diff --git a/src/ProcSim/ViewModels/ProcessConfigViewModel.cs b/src/ProcSim/ViewModels/ProcessConfigViewModel.cs index 8ab7a41..0604bc4 100644 --- a/src/ProcSim/ViewModels/ProcessConfigViewModel.cs +++ b/src/ProcSim/ViewModels/ProcessConfigViewModel.cs @@ -1,25 +1,12 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ProcSim.Core.Configuration; using ProcSim.Core.Process; using System.Collections.ObjectModel; -using System.ComponentModel; namespace ProcSim.ViewModels; -public enum LoopType -{ - [Description("")] - None, - [Description("Infinito")] - Infinite, - [Description("Finito")] - Finite, - [Description("Random")] - Random -} - -public partial class ProcessConfigViewModel : ObservableObject +public sealed partial class ProcessConfigViewModel : ObservableObject { public ProcessConfigViewModel() { @@ -171,7 +158,7 @@ public bool Validate(out IEnumerable errors) return list.Count == 0; } - public bool Equals(ProcessConfigViewModel other) + public bool ValueEquals(ProcessConfigViewModel other) { if (ReferenceEquals(other, this)) return true; if (other is null) return false; @@ -180,14 +167,13 @@ public bool Equals(ProcessConfigViewModel other) if (Priority != other.Priority) return false; if (LoopType != other.LoopType) return false; if (Operations.Count != other.Operations.Count) return false; - if (LoopType == other.LoopType) return false; if (Iterations != other.Iterations) return false; if (MinIterations != other.MinIterations) return false; if (MaxIterations != other.MaxIterations) return false; for (int i = 0; i < Operations.Count; i++) { - if (!Operations[i].Equals(other.Operations[i])) + if (!Operations[i].ValueEquals(other.Operations[i])) return false; } diff --git a/src/ProcSim/ViewModels/ProcessesConfigViewModel.cs b/src/ProcSim/ViewModels/ProcessesConfigViewModel.cs index f80e3e2..5b9ada5 100644 --- a/src/ProcSim/ViewModels/ProcessesConfigViewModel.cs +++ b/src/ProcSim/ViewModels/ProcessesConfigViewModel.cs @@ -1,4 +1,4 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Win32; using ProcSim.Assets; @@ -165,7 +165,7 @@ private void Reset() private bool CanSave() { - return SelectedProcess is not null && !SelectedProcess.Equals(SelectedProcessRef); + return SelectedProcess is not null; } private bool CanCancel() diff --git a/src/ProcSim/ViewModels/TaskManagerDetailsViewModel.cs b/src/ProcSim/ViewModels/TaskManagerDetailsViewModel.cs index 21ede9a..a7112f1 100644 --- a/src/ProcSim/ViewModels/TaskManagerDetailsViewModel.cs +++ b/src/ProcSim/ViewModels/TaskManagerDetailsViewModel.cs @@ -1,4 +1,4 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ProcSim.Core.Monitoring; using ProcSim.Core.Process; diff --git a/src/ProcSim/ViewModels/VmConfigViewModel.cs b/src/ProcSim/ViewModels/VmConfigViewModel.cs index 80b4f27..550294e 100644 --- a/src/ProcSim/ViewModels/VmConfigViewModel.cs +++ b/src/ProcSim/ViewModels/VmConfigViewModel.cs @@ -1,4 +1,4 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Win32; using ProcSim.Assets; @@ -106,7 +106,7 @@ public void UpdateFromModel(VmConfigModel model) else { device.Type = type; - device.Name = converter.Convert(type, typeof(string)) as string ?? type.ToString(); + device.Name = converter.Convert(type, typeof(string), null, null) as string ?? type.ToString(); device.Channels = 1; device.IsEnabled = false; } diff --git a/src/ProcSim/Views/ProcessesConfigControl.xaml b/src/ProcSim/Views/ProcessesConfigControl.xaml index 33411a0..466f6a7 100644 --- a/src/ProcSim/Views/ProcessesConfigControl.xaml +++ b/src/ProcSim/Views/ProcessesConfigControl.xaml @@ -1,4 +1,4 @@ - - + - (e.OriginalSource as DependencyObject) is null) + ProcessesDataGrid.SelectedItem = null; + } +#pragma warning restore S2325 // Methods and properties that don't access instance data should be static + + private static T FindAncestor(DependencyObject element) where T : DependencyObject + { + while (element is not null) + { + if (element is T target) return target; + element = VisualTreeHelper.GetParent(element); + } + return null; } } diff --git a/src/ProcSim/Views/SimulationControlView.xaml.cs b/src/ProcSim/Views/SimulationControlView.xaml.cs index 2ff5829..6eb3687 100644 --- a/src/ProcSim/Views/SimulationControlView.xaml.cs +++ b/src/ProcSim/Views/SimulationControlView.xaml.cs @@ -1,4 +1,4 @@ -using System.Windows.Controls; +using System.Windows.Controls; using System.Windows.Data; namespace ProcSim.Views; @@ -10,6 +10,7 @@ public SimulationControlView() InitializeComponent(); } +#pragma warning disable S2325 // Methods and properties that don't access instance data should be static private void Slider_DragCompleted(object sender, object e) { if (sender is Slider slider) @@ -18,4 +19,5 @@ private void Slider_DragCompleted(object sender, object e) binding?.UpdateSource(); } } +#pragma warning restore S2325 // Methods and properties that don't access instance data should be static }