Add singleton/system manifest, process args, and async management support

This commit is contained in:
Stone_Red
2026-06-09 22:53:13 +02:00
parent a0c9f827e0
commit f7eea21de5
6 changed files with 318 additions and 30 deletions
+62 -13
View File
@@ -8,42 +8,60 @@ public static class ProcessManager
{
private static readonly ConcurrentDictionary<int, (Process Process, Thread Thread)> processes = new();
private static readonly ConcurrentDictionary<Type, ConcurrentHashSet<int>> processesByType = new();
private static int nextProcessId = 0;
public static int SpawnProcess<T>() where T : Process, new()
private static int nextSystemProcessId = -1;
public static int SpawnProcess<T>(string[]? args = null) where T : Process, new()
{
int id = GetNextProcessId();
if (ProcessManifest.HasFlag<T>(ProcessManifest.ProcessManifestFlags.Singleton) && IsProcessRunning<T>())
{
throw new InvalidOperationException($"An instance of process type {typeof(T).Name} is already running.");
}
int id = ProcessManifest.HasFlag<T>(ProcessManifest.ProcessManifestFlags.System) ? GetNextSystemProcessId() : GetNextProcessId();
T process = new()
{
Id = id
};
processesByType.AddOrUpdate(typeof(T), _ => [id], (_, set) =>
{
set.Add(id);
return set;
});
Thread thread = new(() =>
{
try
{
process.Run();
}
catch (Exception ex)
{
Console.WriteLine($"Process {process.Name} (ID: {process.Id}) terminated with an exception: {ex}");
process.Run(args ?? []);
}
finally
{
_ = processes.TryRemove(id, out _);
processes.TryRemove(id, out _);
if (processesByType.TryGetValue(typeof(T), out var set))
{
set.TryRemove(id);
if (set.Count == 0)
processesByType.TryRemove(typeof(T), out _);
}
WindowManager.CloseWindowsForProcess(id);
}
});
_ = processes.TryAdd(id, (process, thread));
processes.TryAdd(id, (process, thread));
thread.Start();
return id;
}
public static void StopProcess(int processId)
public static void StopProcess(int processId, bool waitForExit = false)
{
if (!processes.TryGetValue(processId, out (Process Process, Thread Thread) entry))
{
@@ -51,10 +69,17 @@ public static class ProcessManager
}
entry.Process.RequestStop();
}
WindowManager.CloseWindowsForProcess(processId);
public static async Task StopProcessAndWaitAsync(int processId)
{
if (!processes.TryGetValue(processId, out (Process Process, Thread Thread) entry))
{
return;
}
_ = processes.TryRemove(processId, out _);
entry.Process.RequestStop();
await Task.Run(() => entry.Thread.Join());
}
public static void StopAllProcesses()
@@ -77,6 +102,25 @@ public static class ProcessManager
return null;
}
public static bool IsProcessRunning<T>() where T : Process
{
return processesByType.TryGetValue(typeof(T), out var set) && set.Count > 0;
}
public static IEnumerable<T> GetProcessesOfType<T>() where T : Process
{
if (processesByType.TryGetValue(typeof(T), out var set))
{
foreach (int processId in set)
{
if (processes.TryGetValue(processId, out (Process Process, Thread Thread) entry) && entry.Process is T typedProcess)
{
yield return typedProcess;
}
}
}
}
public static IEnumerable<Process> GetAllProcesses()
{
foreach ((Process Process, Thread Thread) entry in processes.Values)
@@ -101,4 +145,9 @@ public static class ProcessManager
{
return nextProcessId++;
}
private static int GetNextSystemProcessId()
{
return nextSystemProcessId--;
}
}