add old lci module

This commit is contained in:
qing committed 2026-08-02 20:15:07 +08:00
1 parent 38a6e815f0
commit 8499631091
171 files changed
+25562

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
.git/
.vscode/
.idea/
.cache/
#
init.csv
# cangjie
build/
target/
output/
module-resolve.json
module-lock.json
cjpm.lock
.cjpm-history
*.macrocall
*.gcda
*.gcno
# 其他
log
report
tmp
# ide
.arts
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+24
View File
@@ -0,0 +1,24 @@
## 为什么要做一个这样的项目
当时想做一个树莓派机器人,是准备用python来写控制程序,可是当时python的多线程能力较弱,
所以想到使用子系统,可是我没有VPN,无法安装ROS,所以就自己写了一个进程托管程序
## 使用方式
### 启动列表
```bash
# 创建启动列表,每一行是一个进程
touch init.csv
```
### 创建进程
```bash
curl -X POST http://localhost:5200/api/v2/create -d '["ls"]
```
### 进程列表
```bash
curl http://localhost:5200/api/v2/list
```
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")" || exit
#source ./.env/bin/activate
source /cangjie/envsetup.sh
exec cjpm run
+24
View File
@@ -0,0 +1,24 @@
[package]
cjc-version = "1.0.0"
name = "phs"
description = "nothing here"
version = "1.0.0"
target-dir = ""
src-dir = ""
output-type = "executable"
compile-option = ""
override-compile-option = ""
link-option = ""
package-configuration = {}
[dependencies]
[target.x86_64-unknown-linux-gnu]
[target.x86_64-unknown-linux-gnu.bin-dependencies]
path-option = ["/stdx/linux_x86_64_llvm/static/stdx"]
[target.aarch64-unknown-linux-gnu]
[target.aarch64-unknown-linux-gnu.bin-dependencies]
path-option = ["/stdx/linux_aarch64_llvm/static/stdx"]
[target.x86_64-w64-mingw32] # 系统架构和 OS 信息
[target.x86_64-w64-mingw32.bin-dependencies]
path-option = ["C:\\stdx\\windows_x86_64_llvm\\dynamic\\stdx"] # stdx 路径根据实际情况配置
+19
View File
@@ -0,0 +1,19 @@
[Unit]
Description=TxL.phs
After=network.target
Wants=network.target
[Service]
User=root
Group=root
WorkingDirectory=/root/___TxL/TestSuits/phs
ExecStart=bash /root/___TxL/TestSuits/phs/_run.sh
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=mozart-python-host
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
+312
View File
@@ -0,0 +1,312 @@
package phs
import std.sync.*;
/*
* Status 状态
*
* FIXME: 在枚举中定义操作函数
*/
enum Stat {
SHUT | STOP | START | RUNNING
}
/*
* Finite Status Machine 有限状态机
*
*
* FIXME(TritiumQin): 1. 柯里化
*
* FIXME(qing): 支持自定义状态
*/
open class Fsm {
/* 状态枚举 */
private var stat: Stat = STOP
/* 线程安全 */
private let mtx: Mutex = Mutex()
/*
* 条件变量
*
* FIXME: 我不知道这么写意义何在
*/
private let condition: Condition = synchronized(mtx) {
mtx.condition()
}
/* 辅助条件变量的布尔标志 */
private var flag: Bool = true
/* ---------------------------------------------- */
/*
* 阻塞等待状态改变,可以传入一个谓词,以确定什么时候终止
*
* 在该回调函数中返回true,则等待不会停止
*/
public func wait(keep!: (Stat) -> Bool = {_ => false}) {
synchronized(mtx) {
flag = true
while(flag || keep(stat)) {
condition.wait()
}
}
}
/* ---------------------------------------------- */
/*
* 对状态机进行某种操作,输入一个谓词。
*
* 会激活堵塞线程
*/
public func doc(p: (Stat) -> Stat): Stat {
synchronized(mtx) {
stat = p(stat)
flag= false // 试图唤醒阻塞的线程
condition.notifyAll()
return stat
}
}
/*
* 对状态机进行某种操作,输入一个谓词。
*
* 不会激活堵塞线程
*/
public func dop(p: (Stat) -> Stat): Stat {
synchronized(mtx) {
stat = p(stat)
return stat
}
}
}
/* Controllable Thread 可控制线程
*
* FIXME(花间岛):
* 1. 使用async语法糖
* 2. 封装iocp
*/
open class Th {
/* 持有线程类型 */
private var fut: Option<Future<Int64>> = None
/* 持有状态机类型 */
private let fsm: Fsm = Fsm()
/*----------------------------------------------*/
/* 持有静止事件回调 */
private var StopEvent: Option<() -> Unit> = None
/* 持有唤醒事件回调 */
private var WakeEvent: Option<() -> Unit> = None
/* 持有循环事件回调 */
private var LoopEvent: Option<() -> Unit> = None
/* 持有清理事件回调 */
private var ClearEvent: Option<() -> Unit> = None
/* 持有线程主函数回调 */
private var Main: Option<() -> Int64> = None // 线程主函数
/*----------------------------------------------*/
/* 使用谓词检查线程状态 */
public func chkp(): Stat {
return fsm.dop({ stat => return stat })
}
/*----------------------------------------------*/
/* 进入关闭状态 */
public func shut() {
fsm.doc({ _ => return SHUT })
}
/* 进入静止态 */
public func stop() {
fsm.doc({ _ => return STOP })
}
/* 进入启动状态 */
public func start() {
fsm.doc({ _ => return START })
}
/* 进入运行态 */
public func run() {
fsm.doc({ _ => return RUNNING })
}
/*----------------------------------------------*/
/* 状态机是否处于静止态 */
public func isStop() {
return match( chkp() ) {
case STOP => true
case _ => false
}}
/* 状态机是否处于关闭态 */
public func isShut() {
return match( chkp() ) {
case SHUT => true
case _ => false
}}
/* 状态机是否处于开始状态 */
public func isStart() {
return match( chkp() ) {
case START => true
case _ => false
}}
/* 状态机是否处于运行态 */
public func isRunning() {
return match( chkp() ) {
case RUNNING => true
case _ => false
}}
/*----------------------------------------------*/
/* 扮演函数,即设置线程事件 */
public func Act(
/* 静止事件 */
stop!: Option<() -> Unit> = None,
/* 唤醒事件 */
wake!: Option<() -> Unit> = None,
/* 循环事件 */
loop!: Option<() -> Unit> = None,
/* 清理事件 */
clear!:Option<() -> Unit> = None,
/* 线程主函数 */
mainloop!: Option<() -> Int64>= None
)
{
/* 只有静止态才能进行设置 */
if (!isStop()) { return; }
/* ------------------------------------------------- */
/* 设置静止事件,确保退出了静止态 */
StopEvent = stop ?? {=> fsm.wait(keep: {stat =>
match(stat) {
case STOP => true /* 保持等待 */
case _ => false
}
})}
/* 唤醒事件,默认直接进入运行态 */
WakeEvent = wake ?? {=> this.run()}
/* 循环事件,默认进行延时 */
LoopEvent = loop ?? {=> sleep(100 * Duration.millisecond)}
/* 清理事件,默认什么都不做 */
ClearEvent= clear?? {=> ;}
/* ------------------------------------------------- */
/* 线程主函数 */
Main = mainloop ?? {=>
/* 回字形循环 外层 */
while (!isShut()) {
this.inner()
}
return 0
}
/* ------------------------------------------------- */
}
/* ------------- 回字形循环 内层 -------------- */
private func inner() {
/* 静止状态 */
while(isStop()) { StopEvent.getOrThrow()() }
/* 唤醒事件 */
if (isStart()) { WakeEvent.getOrThrow()() }
/* 运行状态 */
while(isRunning()) { LoopEvent.getOrThrow()() }
/* 清理事件 */
ClearEvent.getOrThrow()()
}
/* --------------------------------------------- */
/*
* 创建资源,可控线程苏醒
*
* 如果在调用中等待线程启动,可能会造成死锁
* 想了想觉得也没有这个必要
*/
public func wake() {
/* 存在微小的冲突可能,所以我不让它进入静止态 */
this.start()
/* 创建卵 */
fut = Some<Future<Int64>>(spawn {
Main.getOrThrow()()
})
/* 等启动
*
* 20251020(qing): 如果线程启动太快,该等待可能会导致死锁
*/
//fsm.wait(keep: {stat => match(stat) {
// case START => true
// case _ => false
//}})
}
/* 等待线程结束 */
public func wait() {
let f = fut.getOrThrow()
return f.get()
}
/*
* 关闭线程,然后等待线程结束
*/
public func shut_and_wait() {
shut()
wait()
}
}
+211
View File
@@ -0,0 +1,211 @@
package phs
import std.io.*;
import std.fs.*;
import std.collection.*;
import std.sync.*;
import std.process.*;
import stdx.net.http.*;
import stdx.encoding.json.*;
const ADDR = "127.0.0.1" /* 监听IP地址 */
const PORT = 5200u16 /* 端口 UInt16类型 */
class Ps {
private let ps = LinkedList<SubProcess>()
private let mtx = Mutex()
/* 创建进程 */
public func create(arr: Array<String>) {
let path = arr[0]
let args = arr[1..]
let subp: SubProcess = launch(path, args,
//stdIn: ProcessRedirect.Discard, /* WINDOWS中不支持输入重定向 */
//stdOut: ProcessRedirect.Discard, /* 加了这行之后就在控制台看不到输出了 */
//stdErr: ProcessRedirect.Discard
)
this.clear() /* 清理进程 */
synchronized(mtx) {
ps.addLast(subp)
return;
}
}
/* 返回进程列表 */
public func list() {
var msg = ""
println('1')
this.clear() /* 清理进程,有锁 */
println('2')
synchronized(mtx) {
println('3')
for (p in ps) {
if (msg != "") { msg += "\n"; }
msg += '${p.pid.toString()}\t'
msg += '${p.command} '
//for (i in p.arguments) { /* 加上这个会失败 */
// msg += '${i} '
//}
/* 启动时间 */
msg += '\t${p.userTime.toString()}'
}
println('4')
}
return msg;
}
/* 杀死已经存在的进程 */
public func kill(pid: Int64) {
this.clear() /* 清理 */
synchronized(mtx) {
for (p in ps) {
if (p.pid == pid) {
p.terminate(force: true)
return
}
}
}
}
/*
* 进程自启动
*
* FIXME: 支持注释
*/
public func autoRun(csvpath: String) {
let file = File(csvpath, Read)
let bytes = readToEnd(file)
let ctt = String.fromUtf8(bytes)
let cmds = ctt.split("\n", removeEmpty: true)
for (cmd in cmds) {
try{
let arr = cmd.split(" ", removeEmpty: true)
this.create(arr)
} catch (exp: Exception) {
;
}
}
file.close()
}
/* 清理已经死去的进程,默认不加锁 */
private func clear() {
synchronized(mtx) {
let len = ps.size
for (i in (len-1)..=0 : -1) {
try {
let p = ps.nodeAt(i).getOrThrow()
println("start...")
p.value.wait(timeout: 1 * Duration.millisecond) /* 进程有没有退出 */
println("end...")
ps.remove(p)
}
catch (exp: TimeoutException) { /* 如果进程没有结束,会运行到这里 */
;
println("skip...")
}
}
}
}
}
/*
* 将JSON数组转为字符串的数组
*
* Json对象的每个元素只能是字符串,否则会报错
*/
func Jarr_to_arr(arr: JsonArray): Array<String> {
let len = arr.size() // Json数组的长度
let ret = Array<String>(len, repeat: "")
for (i in 0..len) {
let option: Option<JsonValue> = arr.get(i)
let jitem: JsonValue = option.getOrThrow()
let jstr: JsonString = jitem.asString()
let str: String = jstr.getValue()
ret[i] = str
}
return ret
}
/* cj命令行参数不包含可执行文件名 */
main(_: Array<String>): Int64 {
/* 进程组 */
let ps = Ps()
ps.autoRun("./init.csv")
/* 创建http服务器 */
let server: Server = ServerBuilder()
.addr(ADDR) /* 设置地址 */
.port(PORT) /* 设置端口 */
.build()
/* 创建进程的HTTP方法 */
server.distributor.register("/api/v2/create", { context =>
if (context.request.method == "POST") {
let content = StringReader(context.request.body).readToEnd() /* 阅读请求体 */
let array = JsonValue.fromStr(content).asArray() /* 解析json格式的请求体 */
let net_args: Array<String> = Jarr_to_arr(array) /* json数组转原生数组 */
ps.create(net_args)
/* ---- 准备响应 ---- */
let Headers = HttpHeaders()
Headers.add("Content-Type", "text/html; charset=utf-8;")
context.responseBuilder.setHeaders(Headers)
context.responseBuilder.body('OK')
}
})
/*
* 输出进程列表的HTTP方法
*/
server.distributor.register("/api/v2/list", { context =>
if (context.request.method == "GET") {
println('a')
/* 准备表单字符串 */
let ret = ps.list()
println('b')
/**** 准备响应 ****/
let Headers = HttpHeaders()
Headers.add("Content-Type", "text/html; charset=utf-8;")
context.responseBuilder.setHeaders(Headers)
context.responseBuilder.body(ret)
println('c')
}
})
/* 杀死一个已经存在的进程 */
server.distributor.register("/api/v2/kill", { context =>
if (context.request.method == "POST") {
let content = StringReader(context.request.body).readToEnd() /* 阅读请求体 */
let target_pid = JsonValue.fromStr(content)
.asObject()
.get("pid")
.getOrThrow()
.asInt()
.getValue()
ps.kill(target_pid)
/**** 准备响应 ****/
let Headers = HttpHeaders()
Headers.add("Content-Type", "text/html; charset=utf-8;")
context.responseBuilder.setHeaders(Headers)
context.responseBuilder.body("done")
}
})
/* 服务器开始运行 */
server.serve()
return 0
}
+66
View File
@@ -0,0 +1,66 @@
import requests
import json
def create_process(cmd_list, url="http://localhost:5200/api/v2/create"):
"""创建任意进程
Args:
cmd_list (list): 命令和参数列表,例如 ["timeout", "/t", "1000"]
url (str, optional): 请求URL,默认为 "http://localhost:5200/api/v2/create"
Returns:
requests.Response: 响应对象
"""
try:
# 发送POST请求
response = requests.post(url, data=json.dumps(cmd_list), timeout=30)
# 返回响应对象供进一步处理
return response
except requests.exceptions.RequestException as e:
print(f"创建进程失败: {e}")
return None
def create_process_with_output(cmd_list, url="http://localhost:5200/api/v2/create"):
"""创建任意进程并打印输出
Args:
cmd_list (list): 命令和参数列表,例如 ["timeout", "/t", "1000"]
url (str, optional): 请求URL,默认为 "http://localhost:5200/api/v2/create"
Returns:
dict or str: 响应内容,JSON解析后的字典或原始文本
"""
response = create_process(cmd_list, url)
if response is None:
return None
# 打印响应状态码
print(f"响应状态码: {response.status_code}")
# 尝试解析响应内容为JSON格式并打印
try:
response_json = response.json()
print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}")
return response_json
except json.JSONDecodeError:
print(f"响应内容(非JSON格式): {response.text}")
return response.text
if __name__ == "__main__":
# 示例用法
# 创建一个timeout进程,延迟1000毫秒
cmd = ["timeout", "/t", "1000"]
# 使用默认URL
print("使用默认URL:")
create_process_with_output(cmd)
# 示例:使用自定义URL(注释掉,可根据需要取消注释)
# print("\n使用自定义URL:")
# custom_url = "http://localhost:5200/api/v2/create"
# create_process_with_output(cmd, custom_url)
@@ -0,0 +1,30 @@
import requests
import json
def test_create_process():
"""测试访问phs web服务的create接口"""
# 设置请求URL
url = "http://localhost:5200/api/v2/create"
# 设置请求数据
data = ["timeout", "/t", "1000"]
# 发送POST请求
response = requests.post(url, data=json.dumps(data))
# 打印响应状态码
print(f"响应状态码: {response.status_code}")
# 尝试解析响应内容为JSON格式并打印
try:
response_json = response.json()
print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}")
except json.JSONDecodeError:
print(f"响应内容(非JSON格式): {response.text}")
# 返回响应对象供进一步处理
return response
if __name__ == "__main__":
# 执行测试函数
test_create_process()
@@ -0,0 +1,44 @@
import requests
import json
import argparse
def test_kill_process(pid):
"""测试访问phs web服务的kill接口"""
# 设置请求URL
url = "http://localhost:5200/api/v2/kill"
# 构造请求消息体
payload = {
"pid": pid
}
# 发送POST请求
response = requests.post(url, json=payload)
# 打印响应状态码
print(f"响应状态码: {response.status_code}")
# 尝试解析响应内容为JSON格式并打印
try:
response_json = response.json()
print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}")
except json.JSONDecodeError:
print(f"响应内容(非JSON格式): {response.text}")
# 返回响应对象供进一步处理
return response
if __name__ == "__main__":
# 创建命令行参数解析器
parser = argparse.ArgumentParser(description="测试访问phs web服务的kill接口")
# 添加pid参数
parser.add_argument("pid", type=int, help="要杀死的进程ID")
# 解析命令行参数
args = parser.parse_args()
# 执行测试函数,传入命令行参数中的pid
test_kill_process(args.pid)
@@ -0,0 +1,27 @@
import requests
import json
def test_create_process():
"""测试访问phs web服务的create接口"""
# 设置请求URL
url = "http://localhost:5200/api/v2/list"
# 发送POST请求
response = requests.get(url)
# 打印响应状态码
print(f"响应状态码: {response.status_code}")
# 尝试解析响应内容为JSON格式并打印
try:
response_json = response.json()
print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}")
except json.JSONDecodeError:
print(f"响应内容(非JSON格式): {response.text}")
# 返回响应对象供进一步处理
return response
if __name__ == "__main__":
# 执行测试函数
test_create_process()