多任务

This commit is contained in:
2026-02-28 16:30:25 +08:00
parent 02ff8295ef
commit 58df162054
12 changed files with 560 additions and 20 deletions

View File

@@ -1 +1 @@
2026-02-27 22:39:48 2026-02-28 16:28:03

View File

@@ -1 +1 @@
b67e0e7 02ff829

View File

@@ -28,9 +28,14 @@ namespace CMLeonOS
// 创建全局CosmosVFS实例 // 创建全局CosmosVFS实例
public static Sys.FileSystem.CosmosVFS fs = new Sys.FileSystem.CosmosVFS(); public static Sys.FileSystem.CosmosVFS fs = new Sys.FileSystem.CosmosVFS();
public static Shell shell;
public static UserSystem userSystem; public static UserSystem userSystem;
public static void ExecuteCommand(string command)
{
var tempShell = new Shell(userSystem);
tempShell.ExecuteCommand(command);
}
public static bool FixMode = false; public static bool FixMode = false;
public static DateTime SystemStartTime; public static DateTime SystemStartTime;
@@ -248,9 +253,6 @@ namespace CMLeonOS
_logger.Info("Kernel", $"User '{userSystem.CurrentUsername}' logged in successfully"); _logger.Info("Kernel", $"User '{userSystem.CurrentUsername}' logged in successfully");
// 登录成功后初始化Shell
shell = new Shell(userSystem);
// 检查并执行启动脚本 // 检查并执行启动脚本
ExecuteStartupScript(); ExecuteStartupScript();
@@ -282,10 +284,14 @@ namespace CMLeonOS
Console.WriteLine("A bug brings new wake, a line brings new shine."); Console.WriteLine("A bug brings new wake, a line brings new shine.");
} }
// 运行Shell用户可以输入exit退出 // 运行Shell进程用户可以输入exit退出
_logger.Info("Kernel", "Starting Shell"); _logger.Info("Kernel", "Starting Shell process");
shell.Run(); var shellProcess = new ShellProcess(userSystem);
_logger.Info("Kernel", "Shell exited"); ProcessManager.AddProcess(shellProcess);
shellProcess.TryStart();
shellProcess.TryRun();
shellProcess.TryStop();
_logger.Info("Kernel", "Shell process exited");
// 如果用户输入了exitShell.Run()会返回,继续循环 // 如果用户输入了exitShell.Run()会返回,继续循环
} }
@@ -442,6 +448,9 @@ namespace CMLeonOS
Console.WriteLine("Executing startup script..."); Console.WriteLine("Executing startup script...");
// Console.WriteLine("--------------------------------"); // Console.WriteLine("--------------------------------");
// 创建临时 Shell 实例来执行启动脚本
var tempShell = new Shell(userSystem);
// 逐行执行命令 // 逐行执行命令
foreach (string line in lines) foreach (string line in lines)
{ {
@@ -453,7 +462,7 @@ namespace CMLeonOS
// 执行命令 // 执行命令
// Console.WriteLine($"Executing: {line}"); // Console.WriteLine($"Executing: {line}");
shell.ExecuteCommand(line); tempShell.ExecuteCommand(line);
} }
// Console.WriteLine("--------------------------------"); // Console.WriteLine("--------------------------------");
@@ -536,10 +545,7 @@ namespace CMLeonOS
protected override void Run() protected override void Run()
{ {
if (shell != null) ProcessManager.Yield();
{
shell.Run();
}
} }
} }
} }

184
System/Process.cs Normal file
View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using Sys = Cosmos.System;
namespace CMLeonOS
{
public enum ProcessType
{
Service,
Application,
Background
}
public abstract class Process
{
private protected Process(string name, ProcessType type)
{
Name = name;
Type = type;
}
private protected Process(string name, ProcessType type, Process parent)
{
Name = name;
Type = type;
Parent = parent;
}
internal ulong Id { get; set; }
internal List<string> Args { get; private set; }
internal string Name { get; set; }
internal ProcessType Type { get; private set; }
internal DateTime Created { get; private set; } = DateTime.Now;
internal bool IsRunning { get; private set; } = false;
internal bool Swept { get; set; } = false;
internal bool Critical { get; set; } = false;
internal Process Parent { get; set; }
public virtual void Start()
{
if (Type == ProcessType.Service)
{
CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service starting: {Name}");
}
IsRunning = true;
}
public abstract void Run();
public virtual void Stop()
{
if (Type == ProcessType.Service)
{
CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service stopping: {Name}");
}
IsRunning = false;
foreach (Process process in ProcessManager.Processes)
{
if (process.Parent == this && process.IsRunning)
{
process.TryStop();
}
}
}
public void TryRun()
{
try
{
Run();
}
catch (Exception e)
{
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed: {e.ToString()}");
TryStop();
}
}
}
public void TryStart()
{
try
{
Start();
}
catch (Exception e)
{
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while starting: {e.ToString()}");
TryStop();
}
}
}
public void TryStop()
{
try
{
Stop();
}
catch (Exception e)
{
IsRunning = false;
if (Critical)
{
Console.Clear();
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine();
Console.WriteLine("========================================");
Console.WriteLine(" CRITICAL PROCESS CRASHED");
Console.WriteLine("========================================");
Console.WriteLine();
Console.WriteLine($"Process: {Name}");
Console.WriteLine($"ID: {Id}");
Console.WriteLine();
Console.WriteLine("Error:");
Console.WriteLine(e.ToString());
Console.WriteLine();
Console.WriteLine("Press any key to reboot...");
Console.ReadKey();
Sys.Power.Reboot();
}
else
{
CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while stopping: {e.ToString()}");
}
}
}
}
}

92
System/ProcessManager.cs Normal file
View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
namespace CMLeonOS
{
public static class ProcessManager
{
public static List<Process> Processes = new List<Process>();
private static ulong nextProcessId = 0;
public static Process AddProcess(Process parent, Process process)
{
process.Parent = parent;
AddProcess(process);
return process;
}
public static Process AddProcess(Process process)
{
if (Processes.Contains(process))
return process;
process.Id = nextProcessId;
nextProcessId++;
Processes.Add(process);
return process;
}
public static void Sweep()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
if (!Processes[i].IsRunning)
{
Processes.Remove(Processes[i]);
}
}
}
public static void Yield()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
Process process = Processes[i];
if (process.IsRunning)
{
process.TryRun();
}
}
}
public static Process GetProcessById(ulong processId)
{
foreach (Process process in Processes)
{
if (process.Id == processId) return process;
}
return null;
}
public static Process GetProcessByName(string name)
{
foreach (Process process in Processes)
{
if (process.Name == name) return process;
}
return null;
}
public static T GetProcess<T>()
{
foreach (Process process in Processes)
{
if (process is T processT) return processT;
}
return default;
}
public static void StopAll()
{
for (int i = Processes.Count - 1; i >= 0; i--)
{
Process process = Processes[i];
process.TryStop();
}
}
}
}

63
System/ShellProcess.cs Normal file
View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using CMLeonOS.Commands;
using CMLeonOS.shell;
namespace CMLeonOS
{
public class ShellProcess : Process
{
private Shell shell;
public ShellProcess(UserSystem userSystem) : base("Shell", ProcessType.Application)
{
shell = new Shell(userSystem);
}
public override void Run()
{
CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process started");
try
{
shell.Run();
}
catch (Exception e)
{
CMLeonOS.Logger.Logger.Instance.Error("Shell", $"Shell crashed: {e.ToString()}");
}
CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process stopped");
}
}
public class CommandProcess : Process
{
private string command;
private string args;
private Shell shell;
public CommandProcess(string command, string args, Shell shell) : base($"Command_{command}", ProcessType.Application)
{
this.command = command;
this.args = args;
this.shell = shell;
}
public override void Run()
{
CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Executing command: {command} {args}");
try
{
CommandList.ProcessCommand(shell, command, args);
}
catch (Exception e)
{
CMLeonOS.Logger.Logger.Instance.Error($"Command_{command}", $"Command failed: {e.ToString()}");
}
CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Command completed: {command}");
}
}
}

View File

@@ -118,7 +118,7 @@ namespace UniLua
return 1; return 1;
} }
CMLeonOS.Kernel.shell?.ExecuteCommand(command); CMLeonOS.Kernel.ExecuteCommand(command);
lua.PushBoolean(true); lua.PushBoolean(true);
return 1; return 1;
} }
@@ -132,7 +132,7 @@ namespace UniLua
return 1; return 1;
} }
CMLeonOS.Kernel.shell?.ExecuteCommand($"com {filePath}"); CMLeonOS.Kernel.ExecuteCommand($"com {filePath}");
lua.PushBoolean(true); lua.PushBoolean(true);
return 1; return 1;
} }

View File

@@ -163,6 +163,12 @@ namespace CMLeonOS.shell
case "uptime": case "uptime":
shell.ShowUptime(); shell.ShowUptime();
break; break;
case "ps":
shell.ShowProcesses();
break;
case "kill":
shell.KillProcess(args);
break;
case "grep": case "grep":
shell.GrepFile(args); shell.GrepFile(args);
break; break;

View File

@@ -260,6 +260,18 @@ namespace CMLeonOS.Commands
Description = "Show system uptime" Description = "Show system uptime"
}, },
new CommandInfo new CommandInfo
{
Command = "ps",
Parameters = "",
Description = "List all running processes"
},
new CommandInfo
{
Command = "kill",
Parameters = "<process_id>",
Description = "Kill a process by ID"
},
new CommandInfo
{ {
Command = "matrix", Command = "matrix",
Parameters = "", Parameters = "",
@@ -403,7 +415,7 @@ namespace CMLeonOS.Commands
{ {
Command = "help", Command = "help",
Parameters = "<page>", Parameters = "<page>",
Description = "Show help page (1-4)", Description = "Show help page (1-5)",
SubCommands = new[] { new SubCommandInfo { Command = "help all", Description = "Show all help pages" } } SubCommands = new[] { new SubCommandInfo { Command = "help all", Description = "Show all help pages" } }
} }
}; };

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class KillCommand
{
public static void KillProcess(string args, Action<string> showError, Action<string> showWarning)
{
try
{
if (string.IsNullOrWhiteSpace(args))
{
showError("Usage: kill <process_id>");
showError("Example: kill 123");
return;
}
if (!ulong.TryParse(args, out ulong processId))
{
showError($"Invalid process ID: {args}");
showError("Process ID must be a number.");
return;
}
Process process = ProcessManager.GetProcessById(processId);
if (process == null)
{
showError($"Process not found: {processId}");
showError("Use 'ps' command to list all processes.");
return;
}
if (process.Name == "Shell")
{
showError("Cannot kill Shell process.");
showError("Use 'exit' command instead.");
return;
}
if (!process.IsRunning)
{
showWarning($"Process {process.Name} ({processId}) is already stopped.");
return;
}
CMLeonOS.Logger.Logger.Instance.Info("Kill", $"Killing process: {process.Name} ({processId})");
process.TryStop();
Console.WriteLine($"Process {process.Name} ({processId}) stopped successfully.");
}
catch (Exception ex)
{
showError($"Error killing process: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class PsCommand
{
public static void ShowProcesses(Action<string> showError, Action<string> showWarning)
{
try
{
Console.WriteLine("====================================");
Console.WriteLine(" Process List");
Console.WriteLine("====================================");
Console.WriteLine();
if (ProcessManager.Processes.Count == 0)
{
Console.WriteLine("No processes running.");
Console.WriteLine();
return;
}
Console.Write("ID ");
Console.Write("Name ");
Console.Write("Type ");
Console.Write("Parent ");
Console.WriteLine("Status ");
Console.WriteLine("----------------------------------------------------------------------");
foreach (var process in ProcessManager.Processes)
{
string parentId = process.Parent != null ? process.Parent.Id.ToString() : "N/A";
string status = process.IsRunning ? "Running" : "Stopped";
string type = process.Type.ToString();
Console.Write(process.Id.ToString().PadRight(8));
Console.Write(" ");
Console.Write(process.Name.PadRight(20));
Console.Write(" ");
Console.Write(type.PadRight(12));
Console.Write(" ");
Console.Write(parentId.PadRight(8));
Console.Write(" ");
Console.WriteLine(status);
}
Console.WriteLine();
Console.WriteLine("Total processes: " + ProcessManager.Processes.Count);
Console.WriteLine();
}
catch (Exception ex)
{
showError($"Error listing processes: {ex.Message}");
}
}
}
}

View File

@@ -128,7 +128,7 @@ namespace CMLeonOS
{ {
var command = parts[0].Trim().ToLower(); var command = parts[0].Trim().ToLower();
var args = parts.Length > 1 ? string.Join(" ", parts, 1, parts.Length - 1).Trim() : ""; var args = parts.Length > 1 ? string.Join(" ", parts, 1, parts.Length - 1).Trim() : "";
ProcessCommand(command, args); ProcessCommandAsProcess(command, args);
} }
} }
@@ -409,7 +409,7 @@ namespace CMLeonOS
"cpass", "hostname", "ipconfig", "setdns", "setgateway", "nslookup", "cpass", "hostname", "ipconfig", "setdns", "setgateway", "nslookup",
"ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "lua2cla", "cla", "ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "lua2cla", "cla",
"branswe", "beep", "env", "whoami", "uptime", "alias", "branswe", "beep", "env", "whoami", "uptime", "alias",
"unalias", "base64", "testgui" "unalias", "base64", "testgui", "ps", "kill"
}; };
} }
@@ -462,6 +462,59 @@ namespace CMLeonOS
shell.CommandList.ProcessCommand(this, expandedCommand, expandedArgs); shell.CommandList.ProcessCommand(this, expandedCommand, expandedArgs);
} }
public void ProcessCommandAsProcess(string command, string args)
{
string expandedCommand = command;
string expandedArgs = args;
if (command.StartsWith(":"))
{
string appName = command.Substring(1);
string appPath = "0:\\apps\\" + appName + ".lua";
if (System.IO.File.Exists(appPath))
{
Commands.Script.LuaCommand.ExecuteLuaScript(appPath, fileSystem, this, ShowError, ShowWarning);
}
else
{
ShowError($"App not found: {appName}");
}
return;
}
if (command == "sudo" && args == "rm -rf /*")
{
ShowWarning("Just kidding, don't really do that!");
ShowWarning("System is protected, root directory won't be deleted!");
return;
}
string aliasValue = Commands.AliasCommand.GetAlias(command);
if (aliasValue != null)
{
var aliasParts = aliasValue.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (aliasParts.Length > 0)
{
expandedCommand = aliasParts[0];
if (aliasParts.Length > 1)
{
expandedArgs = aliasParts[1] + (string.IsNullOrEmpty(args) ? "" : " " + args);
}
else
{
expandedArgs = args;
}
}
}
var commandProcess = new CommandProcess(expandedCommand, expandedArgs, this);
ProcessManager.AddProcess(commandProcess);
commandProcess.TryStart();
commandProcess.TryRun();
commandProcess.TryStop();
}
public void ProcessEcho(string args) public void ProcessEcho(string args)
{ {
Commands.System.EchoCommand.ProcessEcho(args); Commands.System.EchoCommand.ProcessEcho(args);
@@ -1003,6 +1056,16 @@ namespace CMLeonOS
Commands.System.UptimeCommand.ShowUptime(ShowError, ShowWarning); Commands.System.UptimeCommand.ShowUptime(ShowError, ShowWarning);
} }
public void ShowProcesses()
{
Commands.System.PsCommand.ShowProcesses(ShowError, ShowWarning);
}
public void KillProcess(string args)
{
Commands.System.KillCommand.KillProcess(args, ShowError, ShowWarning);
}
public void CreateFTP() public void CreateFTP()
{ {
Console.WriteLine("===================================="); Console.WriteLine("====================================");